views.py 554 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import base64
  4. import datetime
  5. import logging
  6. import random
  7. import re
  8. import time
  9. import urlparse
  10. import uuid
  11. from collections import Counter, defaultdict
  12. from decimal import Decimal
  13. from itertools import groupby
  14. from operator import itemgetter
  15. import arrow
  16. import cytoolz
  17. import simplejson as json
  18. from bson import Regex
  19. from bson.objectid import ObjectId
  20. from dateutil.relativedelta import relativedelta
  21. from django.conf import settings
  22. from django.contrib import auth
  23. from django.contrib.auth.hashers import make_password
  24. from django.core.cache import caches
  25. from django.core.handlers.wsgi import WSGIRequest
  26. from django.http import HttpResponse
  27. from django.views.decorators.http import require_POST, require_GET
  28. from mongoengine import Q
  29. from mongoengine.errors import DoesNotExist, NotUniqueError
  30. from typing import TYPE_CHECKING, Optional, cast, Union, Dict, Mapping
  31. from voluptuous import MultipleInvalid
  32. from apilib import utils_datetime
  33. from apilib.monetary import RMB, VirtualCoin, sum_rmb
  34. from apilib.quantity import Quantity
  35. from apilib.utils import natural_sort, is_number, round_2_digits
  36. from apilib.utils_datetime import to_datetime, defaultTodayDate, dt_to_timestamp, get_zero_time, \
  37. get_tomorrow_zero_time
  38. from apilib.utils_datetime import today_datetime_range
  39. from apilib.utils_json import JsonResponse, json_dumps
  40. from apilib.utils_mongo import format_dot_key
  41. from apilib.utils_string import cn
  42. from apilib.utils_url import add_query
  43. from apps import serviceCache, reportCache
  44. from apps.common.utils import get_start_and_end_by_month, get_start_and_end_by_year, get_date_range
  45. from apps.thirdparties.aliyun import AliyunSlider
  46. from apps.web.agent.models import Agent
  47. from apps.web.api.models import APIStartDeviceRecord
  48. from apps.web.common.models import District, DEFAULT_DEALER_FEATURES, WithdrawRecord, OperatorLog, \
  49. MonthlyPackageTemp, WithdrawBankCard
  50. from apps.web.common.proxy import ClientRechargeModelProxy, ClientConsumeModelProxy, DealerDailyStatsModelProxy, \
  51. GroupDailyStatsModelProxy, DeviceDailyStatsModelProxy, ClientDealerIncomeModelProxy, DealerReportModelProxy
  52. from apps.web.common.transaction import WithdrawStatus, WITHDRAW_PAY_TYPE, translate_withdraw_state
  53. from apps.web.common.transaction.pay import OrderCacheMgr, PayManager, RefundManager
  54. from apps.web.common.validation import NAME_RE, PHONE_NUMBER_RE
  55. from apps.web.constant import (
  56. Const,
  57. DEALER_CONSUMPTION_AGG_KIND_TRANSLATION,
  58. DEALER_CONSUMPTION_AGG_KIND, DEALER_CONSUMPTION_AGG_KIND_UNIT,
  59. MONTH_DATE_KEY,
  60. FAULT_RECORD_STATUS, APP_TYPE, AppPlatformType, PollRecordDefine, TYPE_ADJUST_USER_VIRTUAL_CARD, DeviceCmdCode,
  61. ErrorCode, RECHARGE_CARD_TYPE, RECHARGE_RECORD_VIA_TRANSLATION, skip_package_unit_verify_list,
  62. skip_package_range_verify_list, skip_package_params_verify_list, USER_RECHARGE_TYPE, CONSUMETYPE,
  63. support_policy_weifule, support_policy_device)
  64. from apps.web.constant import RechargeRecordVia
  65. from apps.web.core import PayAppType, ROLE
  66. from apps.web.core.accounting import Accounting, devCoinTmpl
  67. from apps.web.core.auth.wechat import WechatAuthBridge
  68. from apps.web.core.bridge import WechatClientProxy
  69. from apps.web.core.db import paginate, prepare_query, search_query
  70. from apps.web.core.device_define.huopo import HuopoCacheMgr
  71. from apps.web.core.exceptions import ServiceException, InvalidParameter, ParameterError, InvalidFileSize, \
  72. InvalidFileName, RentDeviceError
  73. from apps.web.core.file import AliOssFileUploader, SwapGroupPicFileUploader
  74. from apps.web.core.helpers import ActionDeviceBuilder
  75. from apps.web.core.messages.sms import (
  76. dealerAutoWithdrawSMSProvider,
  77. dealerRegisterSMSProvider,
  78. dealerWithdrawSMSProvider,
  79. dealerBindWechatSMSProvider,
  80. dealerBindWalletWechatSMSProvider,
  81. dealerEditMonitorSMSProvider,
  82. dealerMonitorWithdrawSMSProvider)
  83. from apps.web.core.models import OfflineTask, WechatPayApp, WechatAuthApp
  84. from apps.web.core.networking import MessageSender
  85. from apps.web.core.payment import WithdrawGateway, PaymentGateway
  86. from apps.web.core.payment.wechat import WechatPaymentGateway
  87. from apps.web.core.sysparas import SysParas
  88. from apps.web.core.utils import DefaultJsonErrorResponse, JsonErrorResponse, JsonOkResponse, parse_json_payload
  89. from apps.web.dealer import OfflineTaskType
  90. from apps.web.dealer.define import DEALER_INCOME_SOURCE, DEALER_INCOME_SOURCE_TRANSLATION, DEALER_INCOME_TYPE, \
  91. PAY_NOTIFY_URL, DEALER_BIND_WECHAT_URL, DEALER_BIND_WALLET_WECHAT_URL
  92. from apps.web.dealer.models import (
  93. Dealer, UpscoreRecord, Merchant, DealerRechargeRecord,
  94. OnSale, OnSaleRecord, VirtualCard,
  95. ElecPriceTemplate, ItemType,
  96. SubAccount, DealerMessage, Complaint, AdjustUserVirtualCardRecord, ExchangeOrder, DealerAddr, UpCardScoreRecord,
  97. PermissionRole, PermissionRule, TodoMessage, ApiAppInfo, RefundDealerRechargeRecord)
  98. from apps.web.dealer.proxy import DealerIncomeProxy
  99. from apps.web.dealer.transaction import post_pay, refund_post_pay
  100. from apps.web.dealer.utils import gen_login_response, gen_home_response, gen_subaccount_login_response, \
  101. VirtualCardBuilder, create_dealer_sim_charge_order, DealerSessionBuilder, MyToken, \
  102. create_dealer_charge_order_for_api, create_dealer_charge_order_for_disable_ad
  103. from apps.web.dealer.validation import dealerSchema
  104. from apps.web.dealer.validator import UserListValidator
  105. from apps.web.dealer.withdraw import DealerWithdrawService
  106. from apps.web.device.define import DeviceChannelType
  107. from apps.web.device.models import Device, Group, FeedBack, DeviceType, StockRecord, Cell, FaultRecord, Part, Battery, \
  108. GroupDict, DeviceRentOrder, GroupCacheMgr
  109. from apps.web.device.models import DeviceDict, RequestBodyDict, SwapGroup, DiscountPriceCharging, PriceCharging, \
  110. ChargeTag, Picture
  111. from apps.web.device.timescale import SignalManager
  112. from apps.web.device.utils import device_control_cache_key
  113. from apps.web.exceptions import UserServerException
  114. from apps.web.helpers import get_wx_config, current_platform, get_app, \
  115. get_wechat_auth_bridge, \
  116. get_wechat_user_manager_mp_proxy, \
  117. remove_some_desc_for_consume, get_inhourse_wechat_env_pay_gateway
  118. from apps.web.management.models import Manager
  119. from apps.web.merchant.models import MerchantSourceInfo
  120. from apps.web.report.models import (
  121. DevReport, GroupReport, DealerReport,
  122. GroupDailyStat, DealerMonthlyStat, DealerDailyStat, DeviceDailyStat
  123. )
  124. from apps.web.report.utils import (
  125. consumption_unit_precision,
  126. to_quantity,
  127. translate_income,
  128. translate_consumption)
  129. from apps.web.south_intf.zhejiang_fire import Company
  130. from apps.web.south_intf.zhejiang_fire import handler_event_to_zhejiang
  131. from apps.web.user.models import RechargeRecord, ConsumeRecord, MyUser, CardConsumeRecord, Card, \
  132. CardRechargeRecord, CardRechargeOrder, UserVirtualCard, ServiceProgress, VCardConsumeRecord, \
  133. VirtualCardRechargeRecord, BlackListUsers, SwapCardRecord, UniqueUser
  134. from apps.web.user.transaction_deprecated import refund_cash
  135. from apps.web.user.utils import check_black_user, BatteryInfo
  136. from apps.web.user.utils2 import get_paginate
  137. from apps.web.utils import (permission_required, LimitAttemptsManager,
  138. dealer_login, subAccount_login, error_tolerate,
  139. ensure_all_fields_are_not_empty,
  140. is_login, check_role, is_dealer, concat_server_end_url,
  141. ErrorResponseRedirect,
  142. FrontEndResponseRedirect, ExternalResponseRedirect, DealerBindIdResponseRedirect,
  143. ViewValidator, record_operation_behavior)
  144. from apps.web.wrapper import request_limit_by_user
  145. from library.jd.pay import PiType
  146. from library.saobei import SaobeiException
  147. from taskmanager.mediator import task_caller
  148. from apps.web.south_intf.swap_carcharger import SwapContract
  149. from library.wechatbase.exceptions import WeChatException
  150. logger = logging.getLogger(__name__)
  151. merge_with = cytoolz.merge_with
  152. get_in = cytoolz.get_in
  153. if TYPE_CHECKING:
  154. from apps.web.core.db import CustomQuerySet
  155. from collections import Iterable
  156. from apps.web.core.db import Query
  157. from apps.web.common.models import UserSearchable
  158. from apps.web.core.payment.jdaggre import JDAggrePaymentGateway
  159. from apps.web.core.payment.saobei import SaobeiPaymentGateway
  160. from apps.web.core.payment import DlbPaymentGateway
  161. from apps.web.core.adapter.bolai_gateway import ChargingGatewayBox
  162. from apps.web.core.adapter.bolai_node import ChargingBox
  163. from apps.web.core.adapter.huiteng import washerHTBox
  164. from apps.web.core.adapter.xiyiji import WasherBox
  165. @error_tolerate(nil=DefaultJsonErrorResponse)
  166. @permission_required(ROLE.dealer, ROLE.subaccount)
  167. def getCheckCodeForNewTel(request):
  168. # type: (WSGIRequest)->JsonResponse
  169. payload = json.loads(request.body)
  170. toNumber = payload.get('phone', None)
  171. agentId = request.user.agentId
  172. agent = Agent.get_agent(agentId)
  173. productName = agent['productName']
  174. status, msg = dealerRegisterSMSProvider.get(phoneNumber = toNumber,
  175. productName = productName,
  176. vendor = SysParas.get_sms_vendor(request.user.smsVendor))
  177. if not status:
  178. return JsonResponse({'result': 0, 'description': msg})
  179. else:
  180. return JsonResponse({'result': 1, 'description': ''})
  181. @error_tolerate(nil=DefaultJsonErrorResponse)
  182. def getCheckCode(request):
  183. # type: (WSGIRequest)->JsonResponse
  184. """
  185. 经销商获取注册短信验证码
  186. :param request:
  187. :return:
  188. """
  189. payload = json.loads(request.body)
  190. toNumber = payload.get('phone', None)
  191. agentId = request.COOKIES.get('agentId', settings.MY_PRIMARY_AGENT_ID)
  192. agent = Agent.objects(id = agentId).first() # type: Agent
  193. sessionId = payload.get('csessionid', None)
  194. sig = payload.get('sig', None)
  195. token = payload.get('nc_token', None)
  196. result = eval(AliyunSlider().check_validation_results(sessionId, sig, token))
  197. if type(result) is dict:
  198. resultCode = result.get('Code', 900)
  199. else:
  200. resultCode = 900
  201. if resultCode == 100:
  202. status, msg = dealerRegisterSMSProvider.get(phoneNumber = toNumber,
  203. productName = agent.productName,
  204. vendor = SysParas.get_sms_vendor(agent.smsVendor))
  205. if not status:
  206. return JsonResponse({'result': 0, 'description': msg})
  207. else:
  208. return JsonResponse({'result': 1, 'description': ''})
  209. else:
  210. return JsonResponse({'result': 0, 'description': u'非正常请求,验证码发送失败'})
  211. @error_tolerate(nil=DefaultJsonErrorResponse)
  212. def verifyForgetCode(request):
  213. # type: (WSGIRequest)->JsonResponse
  214. """
  215. 经销商验证短信验证码
  216. :param request:
  217. :return:
  218. """
  219. phone = request.POST.get('phone', None)
  220. code = request.POST.get('code', None)
  221. password = request.POST.get('password', "")
  222. agentId = request.POST.get('agentId')
  223. if not agentId:
  224. return JsonErrorResponse(u'未选择您对应的代理商,请刷新后再试')
  225. dealer = Dealer.objects(username=phone, agentId=agentId).first()
  226. while True:
  227. if dealer is None:
  228. response = JsonErrorResponse(u'该手机号尚未注册,请注册后再进行操作')
  229. break
  230. if password == "":
  231. response = JsonErrorResponse(u"请输入密码")
  232. break
  233. status, desc = dealerRegisterSMSProvider.verify(phone, code)
  234. if not status:
  235. response = JsonErrorResponse(desc)
  236. else:
  237. dealer.set_password(password)
  238. dealer.unlock_login()
  239. response = JsonResponse({"result": 1, "description": None, "payload": {}})
  240. break
  241. if agentId != request.COOKIES.get('agentId'):
  242. Agent.record_cookie(agentId, response)
  243. return response
  244. @error_tolerate(nil=DefaultJsonErrorResponse)
  245. def getSubAccountCheckCode(request):
  246. # type: (WSGIRequest)->JsonResponse
  247. """
  248. 经销商获取注册短信验证码
  249. :param request:
  250. :return:
  251. """
  252. payload = json.loads(request.body)
  253. toNumber = payload.get('phone', None)
  254. agentId = request.COOKIES.get('agentId', settings.MY_PRIMARY_AGENT_ID)
  255. agent = Agent.objects(id = agentId).first() # type: Agent
  256. sessionId = payload.get('csessionid', None)
  257. sig = payload.get('sig', None)
  258. token = payload.get('nc_token', None)
  259. result = eval(AliyunSlider().check_validation_results(sessionId, sig, token))
  260. if type(result) is dict:
  261. resultCode = result.get('Code', 900)
  262. else:
  263. resultCode = 900
  264. if resultCode == 100:
  265. status, msg = dealerRegisterSMSProvider.get(phoneNumber = toNumber,
  266. productName = agent.productName,
  267. vendor = SysParas.get_sms_vendor(agent.smsVendor))
  268. if not status:
  269. return JsonResponse({'result': 0, 'description': msg})
  270. else:
  271. return JsonResponse({'result': 1, 'description': ''})
  272. else:
  273. return JsonResponse({'result': 0, 'description': u'非正常请求,验证码发送失败'})
  274. @error_tolerate(nil=DefaultJsonErrorResponse)
  275. def verifySubAccountForgetCode(request):
  276. # type: (WSGIRequest)->JsonResponse
  277. """
  278. 经销商验证短信验证码
  279. :param request:
  280. :return:
  281. """
  282. phone = request.POST.get('phone', None)
  283. code = request.POST.get('code', None)
  284. password = request.POST.get('password', "")
  285. agentId = request.POST.get('agentId')
  286. if not agentId:
  287. return JsonErrorResponse(u'未选择您对应的代理商,请刷新后再试')
  288. subaccount = SubAccount.objects(username=phone, agentId=agentId).first()
  289. while True:
  290. if subaccount is None:
  291. response = JsonErrorResponse(u'该手机号不是子账号,请主账号添加此子账号后再进行操作')
  292. break
  293. if password == "":
  294. response = JsonErrorResponse(u"请输入密码")
  295. break
  296. status, desc = dealerRegisterSMSProvider.verify(phone, code)
  297. if not status:
  298. response = JsonErrorResponse(desc)
  299. else:
  300. subaccount.set_password(password)
  301. subaccount.unlock_login()
  302. response = JsonResponse({"result": 1, "description": None, "payload": {}})
  303. break
  304. if agentId != request.COOKIES.get('agentId'):
  305. Agent.record_cookie(agentId, response)
  306. return response
  307. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  308. def getDealerRegisterSMSCode(request):
  309. # type: (WSGIRequest)->JsonResponse
  310. payload = json.loads(request.body)
  311. phoneNumber = payload.get('phoneNumber', None)
  312. agentId = request.COOKIES.get('agentId', settings.MY_PRIMARY_AGENT_ID)
  313. agent = Agent.objects(id = agentId).first() # type: Agent
  314. sessionId = payload.get('csessionid', None)
  315. sig = payload.get('sig', None)
  316. token = payload.get('nc_token', None)
  317. result = eval(AliyunSlider().check_validation_results(sessionId, sig, token))
  318. if type(result) is dict:
  319. resultCode = result.get('Code', 900)
  320. else:
  321. resultCode = 900
  322. if not phoneNumber:
  323. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  324. if len(Dealer.objects.filter(username = phoneNumber, agentId = agentId)):
  325. return JsonResponse({'result': 0, 'description': u'该手机号已注册'})
  326. if resultCode == 100:
  327. status, msg = dealerRegisterSMSProvider.get(phoneNumber = phoneNumber,
  328. productName = agent.productName,
  329. vendor = SysParas.get_sms_vendor(agent.smsVendor))
  330. if not status:
  331. return JsonResponse({'result': 0, 'description': msg})
  332. else:
  333. return JsonResponse({'result': 1, 'description': ''})
  334. else:
  335. return JsonResponse({'result': 0, 'description': u'非正常请求,验证码发送失败'})
  336. def dealerRegister(request):
  337. # type: (WSGIRequest)->JsonResponse
  338. try:
  339. rawPayload = json.loads(request.body) # type: dict
  340. mid = rawPayload.pop('managerId', None)
  341. if mid:
  342. agentId = Manager.objects.get(id=ObjectId(mid)).primeAgentId
  343. rawPayload['agentId'] = str(agentId)
  344. else:
  345. agentId = rawPayload.pop('agentId', None)
  346. if agentId:
  347. rawPayload['agentId'] = str(agentId)
  348. try:
  349. payload = dealerSchema(rawPayload)
  350. except MultipleInvalid:
  351. return JsonErrorResponse(description=u'信息填入有误,请检查手机号码等信息是否合法')
  352. agentId = rawPayload.get('agentId')
  353. agent = Agent.objects(id=agentId).first() # type: Optional[Agent]
  354. if not agent:
  355. return JsonErrorResponse(description=u'请联系您的代理商获取正确的经销商注册地址')
  356. username = payload.pop('username').strip()
  357. password = payload.pop('password').strip()
  358. if PHONE_NUMBER_RE.match(username) is None:
  359. return JsonErrorResponse(description=u'请输入正确格式的手机号码')
  360. status, msg = dealerRegisterSMSProvider.verify(phoneNumber=username, smsCode=rawPayload["code"])
  361. if not status:
  362. return JsonErrorResponse(description=msg)
  363. payload['features'] = DEFAULT_DEALER_FEATURES
  364. if 'merchant' in agent.features:
  365. payload['features'].append('merchant')
  366. try:
  367. Dealer.create_user(
  368. username = username,
  369. password = password,
  370. adShow = True,
  371. noAdPolicy = 'banner',
  372. annualTrafficCost = agent.annualTrafficCost if \
  373. agent.annualTrafficCost > agent.trafficCardCost else agent.trafficCardCost,
  374. trafficCardCost = agent.trafficCardCost,
  375. withdrawFeeRatio = agent.withdrawFeeRatio if \
  376. agent.withdrawFeeRatio > agent.withdrawFeeRatioCost else agent.withdrawFeeRatioCost,
  377. **payload
  378. )
  379. except NotUniqueError:
  380. return JsonErrorResponse(description=u'该经销商已注册')
  381. except MultipleInvalid as e:
  382. logger.exception('failed to validate register dealer payload due to %s' % e)
  383. return JsonErrorResponse(description=u'部分输入不合法,请重试')
  384. except Exception as e:
  385. logger.exception('cannot register dealer due to %s' % e)
  386. return JsonErrorResponse(description=u'注册失败请重试')
  387. return JsonOkResponse()
  388. def dealerAccess(request):
  389. # type: (WSGIRequest)->JsonResponse
  390. agentId = request.GET.get('agentId', '')
  391. if not is_login(request, ROLE.dealer):
  392. response = gen_login_response(agentId)
  393. else:
  394. agent = Agent.objects(id=str(request.user.agentId)).get()
  395. if (not agentId) or (agentId == request.user.agentId) or (agentId == str(agent.primary_agent.id)):
  396. agentId = request.user.agentId
  397. response = gen_home_response(agentId)
  398. else:
  399. response = gen_login_response(agentId)
  400. return response
  401. def subAccountAccess(request):
  402. agentId = request.GET.get('agentId', '')
  403. if not is_login(request, ROLE.subaccount):
  404. response = gen_subaccount_login_response(agentId)
  405. else:
  406. agent = Agent.objects(id=str(request.user.agentId)).get()
  407. if (not agentId) or (agentId == request.user.agentId) or (agentId == str(agent.primary_agent.id)):
  408. agentId = request.user.agentId
  409. response = gen_home_response(agentId)
  410. else:
  411. response = gen_subaccount_login_response(agentId)
  412. return response
  413. def login(request):
  414. # type: (WSGIRequest)->JsonResponse
  415. username = request.POST.get('name', None)
  416. password = request.POST.get('password', None)
  417. agentId = request.POST.get('agentId')
  418. if not agentId:
  419. return JsonResponse({'result': 100, 'description': u'未选择对应的代理商,请刷新后在试', 'payload': {}})
  420. if not all([username, password]):
  421. response = JsonResponse({'result': 0, 'description': u'缺少用户名或密码', 'payload': {}})
  422. else:
  423. response = dealer_login(request, logger, username, password, agentId=agentId)
  424. if agentId != request.COOKIES.get('agentId', None):
  425. Agent.record_cookie(agentId, response)
  426. return response
  427. def subAccountLogin(request):
  428. username = request.POST.get('name', None)
  429. password = request.POST.get('password', None)
  430. agentId = request.POST.get('agentId')
  431. if not all([username, password]):
  432. response = JsonResponse({'result': 0, 'description': u'缺少用户名或密码', 'payload': {}})
  433. else:
  434. response = subAccount_login(request, logger, username, password, agentId=agentId)
  435. if agentId != request.COOKIES.get('agentId', None):
  436. Agent.record_cookie(agentId, response)
  437. response.set_cookie(key='sub_account_login_agentid', value=str(agentId), max_age=24 * 3600 * 30, domain = settings.COOKIE_DOMAIN)
  438. return response
  439. @permission_required(ROLE.dealer, ROLE.subaccount)
  440. def homepageData(request):
  441. # type: (WSGIRequest)->JsonResponse
  442. currentDealer = request.user # type: Optional[Dealer, SubAccount]
  443. dealer = request.user.myBoss # type: Dealer
  444. # 显示经销商的总余额(资金池+消费分润) 分两级显示
  445. deviceBalance = dealer.sub_balance(DEALER_INCOME_TYPE.DEVICE_INCOME)
  446. ledgerBalance = dealer.sub_balance(DEALER_INCOME_TYPE.LEDGER_CONSUME)
  447. payload = {
  448. 'totalBalance': deviceBalance + ledgerBalance,
  449. 'deviceBalance': deviceBalance,
  450. 'ledgerBalance': ledgerBalance
  451. }
  452. groupIds = Group.get_group_ids_of_dealer(str(dealer.id))
  453. partnerGroupIds = Group.get_group_ids_of_partner(str(dealer.id))
  454. groupIds.extend(partnerGroupIds)
  455. devList = Device.get_devices_by_group(groupIds).values()
  456. offlineCount, expireCount, allCount = 0, 0, 0
  457. for dev in devList: # type: DeviceDict
  458. allCount += 1
  459. if not dev.online:
  460. offlineCount += 1
  461. if dev.is_authorized_to_dealer(str(dealer.id)) and (dev.sim_expire_notify or dev.is_expired):
  462. expireCount += 1
  463. onlineCount = allCount - offlineCount
  464. payload.update({'onlineCount': onlineCount, 'offlineCount': offlineCount})
  465. payload['adShow'] = currentDealer.adShow
  466. payload['feedback'] = FeedBack.get_unhandled_count(ownerId=str(dealer.id))
  467. if expireCount > 0:
  468. payload['simCardTip'] = {
  469. 'expireCount': expireCount,
  470. 'todoMsg': TodoMessage.sim_expire_message(str(currentDealer.id), expireCount)
  471. }
  472. payload['pushBrokerUrl'] = currentDealer.pushBrokerUrl
  473. payload['isPurePartner'] = currentDealer.isPurePartner
  474. payload['inhouseApp'] = currentDealer.is_inhouse_wallet
  475. # 获取agent的相关信息
  476. resultResponse = JsonResponse({'result': 1, 'description': None, 'payload': payload})
  477. resultResponse = Agent.record_cookie(currentDealer.agentId, resultResponse)
  478. return resultResponse
  479. @error_tolerate(nil=JsonErrorResponse(u'上分失败,请重试'))
  480. @permission_required(ROLE.dealer, ROLE.subaccount)
  481. def onPoints(request):
  482. # type: (WSGIRequest)->JsonResponse
  483. """
  484. 远程上分, 支持经销商和代理商进行操作,代理商通过上分测试机器系统流程正确。
  485. :param request:
  486. :return:
  487. """
  488. TYPE_POINTS = ''
  489. TYPE_CHARGE_CARD = 'chargeCard'
  490. def __points__(dev, ruleId):
  491. smartBox = ActionDeviceBuilder.create_action_device(dev)
  492. if dev.support_reliable:
  493. orderNo = dev.ownerId[-10:]+ConsumeRecord.make_no()
  494. order = ConsumeRecord(orderNo=orderNo, openId=dev.ownerId)
  495. order.package = dev.get('washConfig',{}).get(ruleId)
  496. order.attachParas = attachParas
  497. smartBox.start_device_realiable(order)
  498. lineInfo = {'port':attachParas.get('chargeIndex'), 'status':Const.DEV_WORK_STATUS_WORKING}
  499. Device.update_port_control_cache(dev.devNo, lineInfo)
  500. else:
  501. smartBox.start(ruleId, openId = None, attachParas = attachParas)
  502. address = Group.get_group(dev['groupId'])['address']
  503. groupName = Group.get_group(dev['groupId'])['groupName']
  504. score = dev.get('washConfig', {}).get(ruleId, {}).get('coins', 0)
  505. UpscoreRecord(
  506. logicalCode=dev['logicalCode'],
  507. devNo=devNo,
  508. ownerId=ownerId,
  509. time=datetime.datetime.now(),
  510. score=score,
  511. address=address,
  512. groupName=groupName,
  513. devType=dev['devType']['name'],
  514. type=TYPE_POINTS
  515. ).save()
  516. def __charge_card(dev, price):
  517. smartBox = ActionDeviceBuilder.create_action_device(dev)
  518. smartBox.remote_charge_card(price)
  519. address = Group.get_group(dev['groupId'])['address']
  520. groupName = Group.get_group(dev['groupId'])['groupName']
  521. UpscoreRecord(
  522. logicalCode=dev['logicalCode'],
  523. devNo=devNo,
  524. ownerId=ownerId,
  525. time=datetime.datetime.now(),
  526. score=price,
  527. address=address,
  528. groupName=groupName,
  529. devType=dev['devType']['name'],
  530. type=TYPE_CHARGE_CARD
  531. ).save()
  532. def __huopo_points(dev):
  533. ruleId = "1"
  534. smartBox = ActionDeviceBuilder.create_action_device(dev)
  535. smartBox.start(ruleId, openId = None, attachParas = attachParas)
  536. address = Group.get_group(dev['groupId'])['address']
  537. groupName = Group.get_group(dev['groupId'])['groupName']
  538. score = 0
  539. UpscoreRecord(
  540. logicalCode=dev['logicalCode'],
  541. devNo=devNo,
  542. ownerId=ownerId,
  543. time=datetime.datetime.now(),
  544. score=score,
  545. address=address,
  546. groupName=groupName,
  547. devType=dev['devType']['name'],
  548. type=TYPE_POINTS
  549. ).save()
  550. def __policy_points__(dev, ruleId):
  551. smartBox = ActionDeviceBuilder.create_action_device(dev)
  552. if dev.support_reliable:
  553. orderNo = dev.ownerId[-10:]+ConsumeRecord.make_no()
  554. order = ConsumeRecord(orderNo=orderNo, openId=dev.ownerId)
  555. order.package = smartBox.prepare_package(ruleId, attachParas)
  556. order.attachParas = attachParas
  557. smartBox.start_device_realiable(order)
  558. lineInfo = {
  559. 'port': attachParas.get('chargeIndex'),
  560. 'status': Const.DEV_WORK_STATUS_WORKING,
  561. 'nickName': '经销商远程上分',
  562. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  563. }
  564. data = smartBox._check_package(order.package)
  565. if 'needTime' in data:
  566. lineInfo.update({'needTime': data['needTime']})
  567. if 'needElec' in data:
  568. lineInfo.update({'needElec': data['needElec']})
  569. Device.update_port_control_cache(dev.devNo, lineInfo)
  570. address = Group.get_group(dev['groupId'])['address']
  571. groupName = Group.get_group(dev['groupId'])['groupName']
  572. UpscoreRecord(
  573. logicalCode=dev['logicalCode'],
  574. devNo=devNo,
  575. ownerId=ownerId,
  576. time=datetime.datetime.now(),
  577. package=order.package,
  578. address=address,
  579. groupName=groupName,
  580. devType=dev['devType']['name'],
  581. type=TYPE_POINTS
  582. ).save()
  583. try:
  584. ownerId = str(request.user.bossId)
  585. logicalCode = request.POST.get('logicalCode', None)
  586. attachParas = json.loads(request.POST.get('attachParas', '{}'))
  587. attachParas['onPoints'] = True
  588. type = request.POST.get('type', '')
  589. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  590. dev = Device.get_dev(devNo)
  591. if not dev:
  592. return JsonResponse({'result': 2, 'description': u'设备不存在'})
  593. if dev['ownerId'] != ownerId:
  594. return JsonResponse({'result': 2, 'description': u'不是你家设备,不能操作喔'})
  595. dealer = dev.owner
  596. agent = Agent.objects.filter(id=str(dealer.agentId)).first() # type: Agent
  597. if 'disable_dealer_onPoints_and_sendCoins' in agent.features:
  598. return JsonResponse(
  599. {'result': 0, 'description': '设备无法使用该功能奥, 如有问题, 请联系代理商', 'payload': {}})
  600. # 霍珀的道闸适配
  601. if dev["devType"]["code"] == Const.DEVICE_TYPE_CODE_HP_GATE:
  602. __huopo_points(dev)
  603. return JsonResponse({'result': 1, 'description': u'success'})
  604. if dev["devType"]["code"] in support_policy_device:
  605. ruleId = request.POST.get('ruleId', None)
  606. __policy_points__(dev, ruleId)
  607. return JsonResponse({'result': 1, 'description': u'success'})
  608. if type == TYPE_POINTS:
  609. ruleId = request.POST.get('ruleId', None)
  610. # 如果是串口设备,上分的话,直接使用套餐。这里把串口和非串口的上分统一起来,行为应该有创建者创建具备行为的实例
  611. if not ruleId:
  612. return JsonResponse(
  613. {'result': 0, 'description': u'没有找到对应的套餐信息,请您重新选择其他分值.或者检查设备是否没有注册到系统', 'payload': {}})
  614. __points__(dev, ruleId)
  615. elif type == TYPE_CHARGE_CARD:
  616. price = int(request.POST.get('coins', 0))
  617. if price <= 0:
  618. return JsonResponse({'result': 0, 'description': u'充值金额错,请重新输入', 'payload': {}})
  619. __charge_card(dev, price)
  620. return JsonResponse({'result': 1, 'description': u'success'})
  621. except ServiceException, e:
  622. logger.exception(e)
  623. return JsonResponse(e.result)
  624. @permission_required(ROLE.dealer, ROLE.subaccount)
  625. def onPointsRecords(request):
  626. # type: (WSGIRequest)->JsonResponse
  627. """
  628. 上分记录查询
  629. :param request:
  630. :return:
  631. """
  632. ownerId = str(request.user.bossId)
  633. pageIndex = int(request.GET.get('pageIndex', 1))
  634. pageSize = int(request.GET.get('pageSize', 10))
  635. objs = UpscoreRecord.objects.filter(ownerId=ownerId).order_by('-time')
  636. rcdList = []
  637. total = 0
  638. sumCoins = 0
  639. sumCoinsTotal = 0
  640. sumCharge = 0
  641. sumChargeTotal = 0
  642. for obj in objs:
  643. if obj.type == 'chargeCard':
  644. sumCharge += obj.score
  645. sumChargeTotal += 1
  646. else:
  647. sumCoins += obj.score
  648. sumCoinsTotal += 1
  649. total += 1
  650. rcdList.append({
  651. 'logicalCode': obj.logicalCode,
  652. 'devNo': obj.devNo,
  653. 'createdStr': obj.time.strftime('%Y-%m-%d %H:%M:%S'),
  654. 'coins': obj.score,
  655. 'et_type_name': obj.devType,
  656. 'address': obj.address,
  657. 'groupName': obj.groupName,
  658. 'type': obj.type})
  659. return JsonResponse({
  660. "result": 1,
  661. "description": None,
  662. "payload": {
  663. "sumCoins": sumCoins,
  664. 'sumCoinsTotal': sumCoinsTotal,
  665. 'sumCharge': sumCharge,
  666. 'sumChargeTotal': sumChargeTotal,
  667. "rcds": {
  668. "total": total,
  669. "items": rcdList[(pageIndex - 1) * pageSize:pageIndex * pageSize],
  670. }
  671. }
  672. })
  673. @permission_required(ROLE.dealer, ROLE.subaccount)
  674. def handlerKeepingOrder(request):
  675. """
  676. 关闭订单取消订单
  677. 霍珀道闸 由于出现后付费的情况,可能存在两种情况需要将订单取消 用户扫码进门,创建了订单但是门没开 用户扫码出门,钱已经扣了但门没开
  678. 此接口 供经销商对于此类订单的处理
  679. """
  680. TYPE_CANCEL = "cancel"
  681. TYPE_CLOSE = "close"
  682. _id = request.GET.get("id")
  683. _type = request.GET.get("type")
  684. # 取消订单
  685. sp = ServiceProgress.objects.get(id=_id)
  686. sp.isFinished = True
  687. sp.finished_time = int(time.time())
  688. order = ConsumeRecord.objects.get(id=sp.consumes[0])
  689. if _type == TYPE_CLOSE:
  690. order.isNormal = True
  691. order.finishedTime = datetime.datetime.now()
  692. order.remarks = u"经销商 %s 关闭订单" % request.user.nickname
  693. serviceInfo = {
  694. "finishedTime": str(order.finishedTime)[:19],
  695. }
  696. order.serviceInfo = serviceInfo
  697. elif _type == TYPE_CANCEL:
  698. order.finishedTime = datetime.datetime.now()
  699. order.remarks = u"经销商 %s 取消订单" % request.user.nickname
  700. order.isNormal = False
  701. try:
  702. sp.save()
  703. order.save()
  704. except Exception as e:
  705. logger.exception(e)
  706. return JsonResponse({'result': 0, 'description': u'数据查询出错', 'payload': {}})
  707. else:
  708. # 清除该停车数量 无论是终止订单还是取消订单,其进车数量始终 需要 -1
  709. key = "maxParking"
  710. if order.attachParas.get("vCardId"):
  711. key = "VIPMaxParking"
  712. serviceInfo = HuopoCacheMgr.get_parking_cache(order.groupId)
  713. if serviceInfo is not None:
  714. parkingInfo = serviceInfo.get("parkingInfo", {})
  715. parkingNum = parkingInfo.get(key, 0)
  716. else:
  717. parkingInfo = {}
  718. parkingNum = 0
  719. if parkingNum > 0:
  720. parkingNum -= 1
  721. parkingInfo.update({key: parkingNum})
  722. HuopoCacheMgr.set_parking_cache(order.groupId, {"parkingInfo": parkingInfo})
  723. return JsonResponse({'result': 1, 'description': u'success'})
  724. @permission_required(ROLE.dealer, ROLE.subaccount)
  725. def getKeepingOrder(request):
  726. """
  727. 获取正在进行的订单
  728. """
  729. pageIndex = int(request.GET.get("pageIndex", 1))
  730. pageSize = int(request.GET.get("pageSize", 10))
  731. ownerId = str(request.user.bossId)
  732. logicalCode = request.GET.get('logicalCode', None)
  733. attachParas = json.loads(request.POST.get('attachParas', '{}'))
  734. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  735. dev = Device.get_dev(devNo)
  736. if not dev:
  737. return JsonResponse({'result': 0, 'description': u'设备不存在'})
  738. if dev['ownerId'] != ownerId:
  739. return JsonResponse({'result': 0, 'description': u'不是你家设备,不能操作喔'})
  740. sps = ServiceProgress.objects.filter(device_imei=devNo, devTypeCode=dev["devType"]["code"], isFinished=False).all()
  741. dataList = list()
  742. for sp in sps:
  743. user = MyUser.objects.filter(openId=sp.open_id).first()
  744. order = ConsumeRecord.objects.get(id=sp.consumes[0])
  745. tempData = {
  746. "id": sp.id,
  747. "nickname": user.nickname,
  748. "avatar": user.avatar,
  749. "startTime": order.time
  750. }
  751. dataList.append(tempData)
  752. return JsonResponse(
  753. {'result': 1,
  754. 'description': u'',
  755. 'payload':
  756. {
  757. "total": len(dataList),
  758. "dataList": dataList[(pageIndex-1)*pageSize: pageIndex*pageSize]
  759. }
  760. })
  761. # 获取默认地址
  762. @permission_required(ROLE.dealer, ROLE.subaccount)
  763. def groupInfo(request):
  764. # 获取默认地址
  765. def groupInfoDefault(request):
  766. # type: (WSGIRequest)->JsonResponse
  767. groupId = request.GET.get('groupId', None)
  768. ownerId = str(request.user.bossId)
  769. group = Group.get_group(groupId)
  770. if group is None:
  771. return JsonResponse({"result": 0, "description": u"没有找到地址信息", "payload": {}})
  772. if group['ownerId'] == ownerId:
  773. group['isManager'] = True
  774. else:
  775. group['isManager'] = False
  776. groupOwner = Dealer.get_dealer(group['ownerId'])
  777. group['managerName'] = groupOwner['nickname'] + " " + groupOwner['username']
  778. group['partner'] = group['partnerDict'].values()
  779. for partner in group['partner']:
  780. if partner['id'] == ownerId:
  781. partner['self'] = True
  782. else:
  783. reload_parter = Dealer.get_dealer(partner['id'])
  784. partner['tel'] = reload_parter['username']
  785. partner['name'] = reload_parter['nickname']
  786. partner['self'] = False
  787. # 添加 合伙人商户的状态给前台显示 如果合伙人商户的状态是 初始状态 需要为合伙人绑定银行卡
  788. partner = Dealer.objects.get(id=partner["id"])
  789. partner["merchantStatus"] = int(MerchantSourceInfo.get_source_record(partner).status)
  790. district = District.get_district(group['districtId'])
  791. group['district'] = district
  792. if not group['isManager']:
  793. for i in range(len(group['partner'])-1,-1,-1):
  794. if not group['partner'][i]['self']:
  795. del group['partner'][i]
  796. return JsonResponse({"result": 1, "description": None, "payload": group})
  797. current_user = request.user # type: UserSearchable
  798. return groupInfoDefault(request)
  799. @permission_required(ROLE.dealer, ROLE.subaccount)
  800. def groupIncomeData(request):
  801. # type: (WSGIRequest)->JsonResponse
  802. """
  803. 查询地址组的收益
  804. 地址组收益的记录方式已经发生了改变 对于收益的部分 记录在 daily.incomeMap下面的数据,每个经销商一条,为总的收益,没有明细划分
  805. :param request:
  806. :return:
  807. """
  808. def get_group_info(g, _id):
  809. isM = _id == g.get("ownerId")
  810. if not isM:
  811. p = round_2_digits(float(g.get("partnerDict", dict()).get(_id, dict()).get("percent", 0)))
  812. else:
  813. fullPercent = 100
  814. for _partner in g.get("partnerDict", dict()).values():
  815. fullPercent -= float(_partner.get("percent", 0))
  816. p = round_2_digits(float(fullPercent))
  817. return isM, p
  818. current_user = request.user # type: Dealer
  819. dealerId = str(current_user.bossId)
  820. pageIndex = int(request.GET.get("pageIndex", 1))
  821. pageSize = int(request.GET.get("pageSize", 10))
  822. startDate = request.GET.get("startTime")
  823. endDate = request.GET.get("endTime")
  824. startDate, endDate = current_user.limit_filter_date(startDate, endDate)
  825. if endDate < startDate:
  826. return JsonResponse({
  827. 'result': 1, 'description': '', 'payload': {
  828. "total": 0,
  829. "dataList": [],
  830. "adShow": current_user.adShow
  831. }})
  832. else:
  833. searchKey = request.GET.get("searchKey", None)
  834. # 通过searchKey 获取组地址 作为查询的筛选条件
  835. # TODO 这个地方有一个问题在于 如果 地址组的合伙人一旦修改 之前的合伙人无法看到历史的数据 而新的合伙人能看到之前的数据
  836. groupIds = Group.search_group_ids_of_dealer(
  837. dealerId, searchKey
  838. ) + Group.search_group_ids_of_partner(
  839. dealerId, searchKey
  840. )
  841. groupIdSlice = groupIds[(pageIndex - 1) * pageSize: pageSize * pageIndex]
  842. if not groupIdSlice:
  843. return JsonResponse({
  844. 'result': 1, 'description': '', 'payload': {
  845. "total": len(groupIds),
  846. "dataList": [],
  847. "adShow": current_user.adShow
  848. }})
  849. groupStatisticMap = GroupDailyStatsModelProxy.get_groups_income_statistic(groupIds=groupIdSlice, startDate=startDate, endDate=endDate, dealerId=dealerId)
  850. groupDevCountMap = Device.get_device_count_by_group(groupIdSlice)
  851. rptDict = GroupReport.get_rpt(groupIdSlice, startDate, endDate) # 投币的信息
  852. # 经销商的特性判断 的相关信息的获取
  853. dealer = Dealer.objects.get(id=dealerId)
  854. showOfflineCoin = True if 'show_offline_coins' in dealer.features else False
  855. # 整合数据
  856. dataList = list()
  857. for _groupId in groupIdSlice:
  858. # 统计信息的过滤
  859. groupStatistic = groupStatisticMap.get(_groupId, {})
  860. # 要提前将这个不存在的统计值pop出来
  861. dealerActualIncome = RMB(groupStatistic.pop("dealerActualIncome", 0))
  862. incomeList = translate_income(groupStatistic)
  863. totalIncome = sum_rmb(_['value'] for _ in incomeList)
  864. # 组信息 以及分成比例的计算
  865. group = Group.get_group(_groupId) or dict()
  866. isManager, percent = get_group_info(group, dealerId)
  867. value = {
  868. "groupName": group.get("groupName", ""),
  869. "groupId": _groupId,
  870. "address": group.get("address", ""),
  871. "equipmentCount": groupDevCountMap.get(_groupId, 0),
  872. "isManager": isManager,
  873. "percent": percent,
  874. "agentProfitShare": request.user.agentProfitShare,
  875. "offlineCoins": rptDict.get(_groupId, dict()).get('lineCoins', 0),
  876. "incomeList": incomeList,
  877. "totalIncome": totalIncome,
  878. "dealerActualIncome": dealerActualIncome
  879. }
  880. if not showOfflineCoin:
  881. value.pop('offlineCoins', None)
  882. dataList.append(value)
  883. # 对 totalIncome 排序 优先返回金额最多的地址组
  884. dataList = sorted(dataList, key=lambda x: float(x["totalIncome"]), reverse=True)
  885. total = len(groupIds)
  886. return JsonResponse({"result": 1, "description": None, "payload": {
  887. "total": total,
  888. "dataList": dataList,
  889. "adShow": current_user.adShow
  890. }})
  891. @permission_required(ROLE.dealer, ROLE.subaccount)
  892. def getDevOffLineCoinStatByGroupId(request):
  893. # type: (WSGIRequest)->JsonResponse
  894. groupId = request.GET.get('groupId')
  895. group = Group.get_group(groupId)
  896. if not group:
  897. return JsonErrorResponse(u'找不到组ID')
  898. pageIndex = int(request.GET.get('pageIndex', 1))
  899. pageSize = int(request.GET.get('pageSize', 10))
  900. startDate = defaultTodayDate(request.GET.get('startTime'))
  901. endDate = defaultTodayDate(request.GET.get('endTime'))
  902. total = Device.get_collection().find({'groupId': groupId}).count()
  903. devNoList = Device.get_devNos_by_group([groupId])
  904. devInfo = Device.get_dev_by_nos(devNoList)
  905. dataList = [
  906. {
  907. 'logicalCode': devInfo[devNo]['logicalCode'],
  908. 'groupNumber': devInfo[devNo]['groupNumber'],
  909. 'devTypeName': devInfo[devNo].get('devType', {}).get('name', ''),
  910. 'offlineCoins': rpt['lineCoins'],
  911. }
  912. for devNo, rpt in DevReport.get_rpt(devNoList, startDate, endDate).iteritems()
  913. ]
  914. return JsonResponse(
  915. {
  916. 'result': 1,
  917. 'description': '',
  918. 'payload':
  919. {
  920. 'total': total,
  921. 'groupName': group['groupName'],
  922. 'dataList': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  923. }
  924. }
  925. )
  926. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  927. @permission_required(ROLE.dealer, ROLE.subaccount)
  928. def groupIncomeByGroupId(request):
  929. # type: (WSGIRequest)->JsonResponse
  930. """
  931. 获取 单一地址组的 收益 聚合信息
  932. :param request:
  933. :return:
  934. """
  935. dealerId = str(request.user.bossId)
  936. groupId = request.GET.get("groupId")
  937. startDate = request.GET.get("startTime")
  938. endDate = request.GET.get("endTime")
  939. if not groupId:
  940. return JsonErrorResponse(description=u'未提供地址ID')
  941. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  942. return JsonErrorResponse(description=u'无权限查看')
  943. group = Group.get_group(groupId)
  944. if not group:
  945. return JsonErrorResponse(description=u'组不存在')
  946. groupStatistic = GroupDailyStatsModelProxy.get_one_group_income_statistic(groupId, startDate, endDate)
  947. incomeTotalList = [{"name": u"总收益", "value": RMB(groupStatistic.get("totalIncome", 0))}]
  948. for _item in translate_income(groupStatistic):
  949. if _item.get("value", RMB(0)) > RMB(0):
  950. incomeTotalList.append(_item)
  951. return JsonResponse(
  952. {
  953. 'result': 1,
  954. 'description': 'ok',
  955. 'payload': {
  956. 'groupName': group['groupName'],
  957. "incomeTotalList": incomeTotalList
  958. }
  959. }
  960. )
  961. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  962. @permission_required(ROLE.dealer, ROLE.subaccount)
  963. def groupConsumptionByGroupId(request):
  964. # type: (WSGIRequest)->JsonResponse
  965. """
  966. 获取 单一地址组的 收益 聚合信息
  967. :param request:
  968. :return:
  969. """
  970. dealerId = str(request.user.bossId)
  971. groupId = request.GET.get("groupId")
  972. startDate = request.GET.get("startTime")
  973. endDate = request.GET.get("endTime")
  974. if not groupId:
  975. return JsonErrorResponse(description=u'未提供地址ID')
  976. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  977. return JsonErrorResponse(description=u'无权限查看')
  978. group = Group.get_group(groupId)
  979. if not group:
  980. return JsonErrorResponse(description=u'组不存在')
  981. groupStatistic = GroupDailyStatsModelProxy.get_one_group_consumption_statistic(groupId, startDate, endDate)
  982. agent = Agent.objects.get(id=request.user.agentId) # type: Agent
  983. consumptionTotalList = list()
  984. for _item in translate_consumption(groupStatistic, agent.hide_consume_kinds_dealer):
  985. if _item.get("value", Quantity(0)) > Quantity(0):
  986. consumptionTotalList.append(_item)
  987. return JsonResponse(
  988. {
  989. 'result': 1,
  990. 'description': 'ok',
  991. 'payload': {
  992. 'groupName': group['groupName'],
  993. "incomeTotalList": consumptionTotalList
  994. }
  995. }
  996. )
  997. EXTRA_INCOME_DEVICE_TYPE_CODES = [Const.DEVICE_TYPE_CODE_WASHCAR_LSHB]
  998. def realtime_income_available(typeCode):
  999. # type:(str)->bool
  1000. return typeCode in EXTRA_INCOME_DEVICE_TYPE_CODES
  1001. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  1002. @permission_required(ROLE.dealer, ROLE.subaccount)
  1003. def getRealtimeIncomeByDev(request):
  1004. # type: (WSGIRequest)->JsonResponse
  1005. # TODO 建立一个缓存的permission map 来将经销商ID与设备等相关权限对应起来
  1006. logicalCode = request.GET.get('logicalCode')
  1007. device = Device.get_dev_by_logicalCode(logicalCode)
  1008. if not device:
  1009. return JsonErrorResponse(description=u'设备不存在')
  1010. typeCode = device['devType']['code']
  1011. if realtime_income_available(typeCode):
  1012. return JsonErrorResponse(description=u'不支持当前设备查询实时收入')
  1013. translation = {
  1014. 'cardFee': u'刷卡总额',
  1015. 'coinFee': u'投币总额',
  1016. 'mobileFee': u'支付总额'
  1017. }
  1018. if typeCode == Const.DEVICE_TYPE_CODE_CHARGING_SIJIANG:
  1019. try:
  1020. smartBox = ActionDeviceBuilder.create_action_device(device)
  1021. conf = smartBox.get_dev_consume_count()
  1022. return JsonResponse(
  1023. {
  1024. 'result': 1,
  1025. 'description': '',
  1026. 'payload':
  1027. {
  1028. 'realTimeIncome': [
  1029. {'name': translation[k], 'value': v} for k, v in conf.iteritems() if k in translation
  1030. ]
  1031. }
  1032. })
  1033. except ServiceException as e:
  1034. logger.debug('cannot get_extra_income_by_specific_devices device=%s' % (device,))
  1035. logger.exception(e)
  1036. return JsonErrorResponse(description=u'网络不畅通,请稍后再试')
  1037. elif typeCode == Const.DEVICE_TYPE_CODE_WASHCAR_LSHB:
  1038. try:
  1039. # 获取设备上的卡的总收入、投币的总收入
  1040. smartBox = ActionDeviceBuilder.create_action_device(device)
  1041. mapping = {
  1042. 'cardFee': smartBox.get_card_count(),
  1043. 'coinFee': smartBox.get_coins_count()
  1044. }
  1045. return JsonResponse(
  1046. {
  1047. 'result': 1,
  1048. 'description': '',
  1049. 'payload': {
  1050. 'realTimeIncome': [{'name': translation[k], 'value': v} for k, v in mapping.iteritems() if
  1051. k in translation]
  1052. }
  1053. })
  1054. except ServiceException as e:
  1055. logger.debug('cannot get_extra_income_by_specific_devices device=%s' % (device,))
  1056. logger.exception(e)
  1057. return JsonErrorResponse(description=u'网络不畅通,请稍后再试')
  1058. else:
  1059. return JsonErrorResponse(description=u'不支持当前设备查询实时收入')
  1060. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  1061. @permission_required(ROLE.dealer, ROLE.subaccount)
  1062. def groupEquipmentIncomeByGroupId(request):
  1063. # type: (WSGIRequest)->JsonResponse
  1064. """
  1065. 获取组下设备按日期收益聚合数据
  1066. :param request:
  1067. :return:
  1068. """
  1069. # TODO Nicolas 此接口以及 groupEquipmentConsumptionByGroupId 存在问题
  1070. # TODO Nicolas 当该地址下设备信息发生变更的时候 ,通过 GroupDaily 获取的信息 和通过 DeviceDaily 聚合获取的信息会不一致
  1071. dealerId = str(request.user.bossId)
  1072. groupId = request.GET.get("groupId", None)
  1073. pageIndex = int(request.GET.get('pageIndex', 1))
  1074. pageSize = int(request.GET.get('pageSize', 10))
  1075. startDate = request.GET.get('startTime')
  1076. endDate = request.GET.get('endTime')
  1077. if groupId is None:
  1078. return JsonErrorResponse(description=u'未找到地址组,请重试')
  1079. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  1080. return JsonErrorResponse(description=u'无权限查看')
  1081. group = Group.get_group(groupId)
  1082. if not group:
  1083. return JsonErrorResponse(description=u'组不存在')
  1084. # 获取设备的日统计信息
  1085. logicalCodes = Device.get_logicalCode_by_groupId(groupId)
  1086. logicalCodeSlice = sorted(logicalCodes[(pageIndex - 1) * pageSize: pageIndex * pageSize])
  1087. statisticMap = DeviceDailyStatsModelProxy.get_devices_income_statistic(logicalCodeSlice, startDate, endDate)
  1088. dataList = list()
  1089. for logicalCode in logicalCodeSlice:
  1090. devStatistic = translate_income(statisticMap.get(logicalCode, dict()))
  1091. devStatistic = [_statistic for _statistic in devStatistic if _statistic["value"] > RMB(0)]
  1092. dev = Device.get_dev_by_l(logicalCode)
  1093. dataList.append({
  1094. "incomeList": devStatistic,
  1095. "logicalCode": logicalCode,
  1096. "groupId": groupId,
  1097. "type": dev.get("devType", dict()).get("name"),
  1098. 'groupNumber': dev.get('groupNumber'),
  1099. 'realtimeIncomeAvailable': realtime_income_available(dev.get('devType', dict()).get('code'))
  1100. })
  1101. return JsonResponse(
  1102. {
  1103. 'result': 1,
  1104. 'description': None,
  1105. 'payload': {
  1106. 'total': len(logicalCodes),
  1107. 'dataList': dataList
  1108. }
  1109. }
  1110. )
  1111. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  1112. @permission_required(ROLE.dealer, ROLE.subaccount)
  1113. def groupEquipmentConsumptionByGroupId(request):
  1114. # type: (WSGIRequest)->JsonResponse
  1115. """
  1116. 获取组下设备按日期消费聚合数据
  1117. :param request:
  1118. :return:
  1119. """
  1120. dealerId = str(request.user.bossId)
  1121. groupId = request.GET.get("groupId", None)
  1122. pageIndex = int(request.GET.get('pageIndex', 1))
  1123. pageSize = int(request.GET.get('pageSize', 10))
  1124. startDate = request.GET.get('startTime')
  1125. endDate = request.GET.get('endTime')
  1126. if groupId is None:
  1127. return JsonErrorResponse(description=u'未找到地址组,请重试')
  1128. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  1129. return JsonErrorResponse(description=u'无权限查看')
  1130. group = Group.get_group(groupId)
  1131. if not group:
  1132. return JsonErrorResponse(description=u'组不存在')
  1133. # 获取设备的日统计信息
  1134. logicalCodes = Device.get_logicalCode_by_groupId(groupId)
  1135. logicalCodeSlice = sorted(logicalCodes[(pageIndex-1)*pageSize: pageIndex*pageSize])
  1136. statisticMap = DeviceDailyStatsModelProxy.get_devices_consumption_statistic(logicalCodeSlice, startDate, endDate)
  1137. agent = Agent.objects.get(id = request.user.agentId) # type: Agent
  1138. dataList = list()
  1139. for logicalCode in logicalCodeSlice:
  1140. devStatistic = translate_consumption(statisticMap.get(logicalCode, dict()), hides = agent.hide_consume_kinds_dealer)
  1141. devStatistic = [_statistic for _statistic in devStatistic if _statistic["value"] > Quantity(0)]
  1142. dev = Device.get_dev_by_l(logicalCode)
  1143. dataList.append({
  1144. "consumptionList": devStatistic,
  1145. "logicalCode": logicalCode,
  1146. "groupId": groupId,
  1147. "type": dev.get("devType", dict()).get("name"),
  1148. 'groupNumber': dev.get('groupNumber'),
  1149. })
  1150. return JsonResponse(
  1151. {
  1152. 'result': 1,
  1153. 'description': "",
  1154. 'payload': {
  1155. 'total': len(logicalCodes),
  1156. 'dataList': dataList
  1157. }
  1158. }
  1159. )
  1160. def get_income_by_cat(stat, date_range, field):
  1161. return RMB(stat.get(date_range, {}).get('income', {}).get(field, 0))
  1162. def get_daily_income_by_cat(stat, field):
  1163. return get_income_by_cat(stat, 'daily', field)
  1164. def get_monthly_income_by_cat(stat, field):
  1165. return get_income_by_cat(stat, 'monthly', field)
  1166. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1167. def lastMonthIncome(request):
  1168. """
  1169. 按月统计 经销商的月收益
  1170. 获取的数据是当月的收益数据累加的 以及 每天的收益累计总和
  1171. :param request:
  1172. :return:
  1173. """
  1174. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1175. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y-%m"))
  1176. startDate, endDate = get_start_and_end_by_month(monthStr = timeStr)
  1177. rpts = {r['date']: r for r in DealerReport.get_rpts(dealerId, startDate, endDate)}
  1178. # 获取每一天的数据 首先要对时间参数进行鉴别 如果是本月的话,那么最后一天就是今天
  1179. dataList = list()
  1180. totalIncome, payIncome, offlineCoins = RMB(0), RMB(0), VirtualCoin(0)
  1181. rv = DealerDailyStatsModelProxy.get_days_income_stat(dealerId, timeStr)
  1182. for day, stat in rv.iteritems():
  1183. day_offline_count = VirtualCoin(rpts.get(day, {}).get('lineCoins', 0))
  1184. offlineCoins += day_offline_count
  1185. day_pay_income = RMB(get_in(["income", format(DEALER_INCOME_SOURCE.RECHARGE)], stat, default = 0)) + \
  1186. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.REDPACK)], stat, default = 0)) + \
  1187. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.RECHARGE_CARD)], stat, default = 0)) + \
  1188. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.RECHARGE_VIRTUAL_CARD)], stat, default = 0)) + \
  1189. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.REFUND_CASH)], stat, default = 0))
  1190. payIncome += day_pay_income
  1191. day_total_income = RMB(get_in(["totalIncome"], stat, default = 0))
  1192. totalIncome += day_total_income
  1193. dataList.append({
  1194. 'dateStr': day,
  1195. 'dateText': u'%s年%s月%s日' % tuple(day.split('-')),
  1196. 'payIncome': day_pay_income,
  1197. 'offlineCoins': day_offline_count,
  1198. 'totalIncome': day_total_income
  1199. })
  1200. if dealerId == '5d132407003048494763a51b':
  1201. if int(timeStr[0:4]) < 2021:
  1202. dataList = []
  1203. offlineCoins = 0
  1204. payIncome = 0
  1205. totalIncome = 0
  1206. else:
  1207. pass
  1208. return JsonOkResponse(payload=
  1209. {
  1210. "adShow": request.user.adShow,
  1211. "totalIncome": totalIncome,
  1212. "payIncome": payIncome,
  1213. "offlineCoins": offlineCoins,
  1214. "dataList": dataList
  1215. })
  1216. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1217. def lastYearIncome(request):
  1218. # type: (WSGIRequest)->JsonResponse
  1219. """
  1220. 按年统计经销商的收益
  1221. :param request:
  1222. :return:
  1223. """
  1224. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1225. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y"))
  1226. timeStr = Dealer.limit_filter_year(dealerId, timeStr[0:4])
  1227. if not timeStr:
  1228. return JsonOkResponse(payload = {'adShow': request.user.adShow, 'dataList': []})
  1229. else:
  1230. startDay, endDay = get_start_and_end_by_year(timeStr)
  1231. monthRange = [datetime.datetime.strftime(item, "%Y-%m") for item in get_date_range(startDay, endDay, "MS")]
  1232. offline_report = DealerReportModelProxy.get_year_by_month(dealerId = dealerId, yearStr = timeStr)
  1233. # 获取一年里面 按月聚合分组的数据
  1234. statisticMap = DealerDailyStatsModelProxy.get_one_year_income_as_month(dealerId = dealerId, yearStr = timeStr)
  1235. dataList = list()
  1236. for month in monthRange:
  1237. monthIncomeMap = statisticMap.get(month, dict())
  1238. tempMonthStatistics = {
  1239. "totalIncome": RMB(monthIncomeMap.get("totalIncome", 0)),
  1240. "offlineCoins": VirtualCoin(
  1241. offline_report.get('%d-%02d' % tuple(map(int, month.split('-'))), {}).get('lineCoins', 0)),
  1242. "dateStr": month,
  1243. "dateText": u"{}年{}月".format(*month.split("-")),
  1244. "payIncome": sum([_v for _k, _v in monthIncomeMap.items() if
  1245. _k in [DEALER_INCOME_SOURCE.RECHARGE_VIRTUAL_CARD,
  1246. DEALER_INCOME_SOURCE.RECHARGE_CARD,
  1247. DEALER_INCOME_SOURCE.RECHARGE,
  1248. DEALER_INCOME_SOURCE.REFUND_CASH,
  1249. DEALER_INCOME_SOURCE.REDPACK]], RMB(0))
  1250. }
  1251. dataList.append(tempMonthStatistics)
  1252. return JsonOkResponse(payload = {'adShow': request.user.adShow, 'dataList': dataList})
  1253. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1254. def lastMonthConsumption(request):
  1255. # type: (WSGIRequest)->JsonResponse
  1256. """
  1257. 按月统计 经销商的消耗信息
  1258. :param request:
  1259. :return:
  1260. """
  1261. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1262. dealer = Dealer.objects.get(id=dealerId)
  1263. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y-%m"))
  1264. _year = Dealer.limit_filter_year(dealerId, timeStr[0:4])
  1265. if not _year:
  1266. return JsonOkResponse(payload = {'dataList': []})
  1267. else:
  1268. agent = Agent.objects.get(id = request.user.agentId)
  1269. dataList = list()
  1270. rv = DealerDailyStatsModelProxy.get_days_consume_stat(dealerId, timeStr)
  1271. for _day, stat in rv.iteritems():
  1272. consumptionList = translate_consumption(get_in(["consumption"], stat, dict()),
  1273. hides = agent.hide_consume_kinds_dealer)
  1274. if "not_show_about_elec" in dealer.features:
  1275. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"消耗电量"]
  1276. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"电费成本"]
  1277. dataList.append({
  1278. "dateStr": _day,
  1279. "dateText": u"{}年{}月{}日".format(*_day.split("-")),
  1280. "consumptionList": consumptionList
  1281. })
  1282. return JsonOkResponse(payload = {'dataList': dataList})
  1283. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1284. def lastYearConsumption(request):
  1285. # type: (WSGIRequest)->JsonResponse
  1286. """
  1287. 一年的消费概览
  1288. :param request:
  1289. :return:
  1290. """
  1291. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1292. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y"))
  1293. timeStr = Dealer.limit_filter_year(dealerId, timeStr)
  1294. if not timeStr:
  1295. return JsonOkResponse(payload = {'dataList': []})
  1296. else:
  1297. # 获取统计的时间范围 获取月份的区间
  1298. startDay, endDay = get_start_and_end_by_year(timeStr)
  1299. monthRange = [datetime.datetime.strftime(item, "%Y-%m") for item in get_date_range(startDay, endDay, "MS")]
  1300. # 获取一年里面 按月聚合分组的消费数据
  1301. statisticMap = DealerDailyStatsModelProxy.get_one_year_consume_as_month(dealerId = dealerId, yearStr = timeStr)
  1302. # 消费信息 某些字段和特性相关联 先取出代理商的特性 留作判断
  1303. agent = Agent.objects.get(id = request.user.agentId)
  1304. dataList = list()
  1305. for _month in monthRange:
  1306. _item = statisticMap.get(_month, dict())
  1307. consumptionList = translate_consumption(_item, hides=agent.hide_consume_kinds_dealer)
  1308. dataList.append({
  1309. "dateStr": _month,
  1310. "dateText": u"{}年{}月".format(*_month.split("-")),
  1311. "consumptionList": consumptionList
  1312. })
  1313. return JsonOkResponse(payload={'dataList': dataList})
  1314. @permission_required(ROLE.dealer, ROLE.subaccount)
  1315. def updateInfo(request):
  1316. # type: (WSGIRequest)->JsonResponse
  1317. """
  1318. 支持经销商更改用户信息
  1319. :param request:
  1320. :return:
  1321. """
  1322. name = request.POST.get('name', '')
  1323. if NAME_RE.match(name) is None:
  1324. logger.info('update dealer name doesn\'t fit format, name=%s' % (name.encode('utf-8'),))
  1325. return JsonResponse({"result": 0, "description": "请输入正确格式的名称(2-20位)"})
  1326. if check_role(request.user, ROLE.dealer):
  1327. dealer = Dealer.objects(id=request.user.bossId).first() # type: Union[Dealer,None]
  1328. if dealer is None:
  1329. return JsonResponse({"result": 0, "description": "该经销商不存在"})
  1330. updated = dealer.update_dealer(ownerId=str(dealer.id), nickname=name)
  1331. if not updated:
  1332. logger.info('Dealer [updateInfo] failed, name=%s' % (name.encode('utf-8'),))
  1333. return JsonResponse({"result": 0, "description": u'更新失败,请重试'})
  1334. else:
  1335. return JsonResponse({"result": 1, "description": None})
  1336. else:
  1337. subaccount = SubAccount.objects(id=request.user.id).first() # type: Union[Dealer,None]
  1338. if subaccount is None:
  1339. return JsonResponse({"result": 0, "description": "该经销商不存在"})
  1340. updated = subaccount.update(nickname=name)
  1341. if not updated:
  1342. logger.info('subaccount [updateInfo] failed, name=%s' % (name.encode('utf-8'),))
  1343. return JsonResponse({"result": 0, "description": u'更新失败,请重试'})
  1344. else:
  1345. return JsonResponse({"result": 1, "description": None})
  1346. @permission_required(ROLE.dealer, ROLE.subaccount)
  1347. def verifyNewPhoneNumber(request):
  1348. # type: (WSGIRequest)->JsonResponse
  1349. """
  1350. 修改经销商手机号
  1351. :param request:
  1352. :return:
  1353. """
  1354. code = request.POST.get('code')
  1355. if not code:
  1356. return JsonResponse({"result": 0, "description": u'请输入验证码'})
  1357. phoneNumber = request.POST.get('phone')
  1358. if PHONE_NUMBER_RE.match(phoneNumber) is None:
  1359. logger.info('phone number format error, phone=%s' % phoneNumber)
  1360. return JsonResponse({"result": 0, "description": u"请输入正确的手机号码"})
  1361. if check_role(request.user, ROLE.dealer):
  1362. dealer = Dealer.objects(id=request.user.bossId).first() # type: Optional[Dealer]
  1363. if dealer is None:
  1364. return JsonResponse({"result": 0, "description": u"该经销商不存在"})
  1365. # : 检测是否系统内已有该号码,为了防止混淆
  1366. if Dealer.objects(username=phoneNumber).first():
  1367. return JsonResponse({"result": 0, "description": u"已存在与该手机号码绑定的账户"})
  1368. status, msg = dealerRegisterSMSProvider.verify(phoneNumber, code)
  1369. if status:
  1370. updated = dealer.update_dealer(ownerId=str(dealer.id), username=phoneNumber)
  1371. if updated:
  1372. Dealer.invalid_cache(dealer.id)
  1373. return JsonResponse({"result": 1, "description": None})
  1374. else:
  1375. return JsonResponse({"result": 0, "description": u'更换失败'})
  1376. else:
  1377. return JsonResponse({"result": 0, "description": msg})
  1378. else:
  1379. subAccount = SubAccount.objects(id=request.user.id,
  1380. agentId=request.user.agentId).first() # type: Optional[Dealer]
  1381. if subAccount is None:
  1382. return JsonResponse({"result": 0, "description": u"该子账号不存在"})
  1383. # : 检测是否系统内已有该号码,为了防止混淆
  1384. if SubAccount.objects(username=phoneNumber, agentId=request.user.agentId).first():
  1385. return JsonResponse({"result": 0, "description": u"已存在与该手机号码绑定的子账户"})
  1386. status, msg = dealerRegisterSMSProvider.verify(phoneNumber, code)
  1387. if status:
  1388. updated = subAccount.update(username=phoneNumber)
  1389. if updated:
  1390. return JsonResponse({"result": 1, "description": None})
  1391. else:
  1392. return JsonResponse({"result": 0, "description": u'更换失败'})
  1393. else:
  1394. return JsonResponse({"result": 0, "description": msg})
  1395. @permission_required(ROLE.dealer, ROLE.subaccount)
  1396. def setAddressFree(request):
  1397. # type: (WSGIRequest)->JsonResponse
  1398. """
  1399. 设置部分地址为免费地址, 其同一地址下所有设备都会供免费使用
  1400. :param request:
  1401. :return:
  1402. """
  1403. payload = parse_json_payload(request.body)
  1404. groupId = payload.get('groupId', None)
  1405. isFree = payload.get('isFree', False)
  1406. currentDealer = request.user.myBoss # type: Optional[Dealer]
  1407. if currentDealer.get_feature('disable_set_group_free').get('disable_set_group_free', False):
  1408. return JsonResponse(
  1409. {'result': 0, 'description': '设备无法使用该功能奥, 如有问题, 请联系代理商', 'payload': {}})
  1410. if groupId is None:
  1411. return JsonResponse({"result": 0, "description": u'地址不可为空'})
  1412. try:
  1413. Group.update_group(group_id=groupId, isFree=isFree)
  1414. return JsonResponse({"result": 1, "description": None})
  1415. except Exception as e:
  1416. logger.exception(e)
  1417. return JsonResponse({"result": 0, "description": u'修改失败'})
  1418. #### `经销商报表版块` ###############################################################
  1419. @permission_required(ROLE.dealer, ROLE.subaccount)
  1420. def dateCoins(request):
  1421. """
  1422. TODO 线下投币相关数据与收益计算展现彻底分离,接口需要重新审视
  1423. :param request:
  1424. :return:
  1425. """
  1426. ownerId = str(request.user.bossId)
  1427. now = datetime.datetime.now()
  1428. rpt = Accounting.getOwnerIncome(ownerId, now)
  1429. return JsonResponse({"result": 1, "description": None, 'payload': {"coins": rpt["lineCoins"]}})
  1430. @permission_required(ROLE.dealer, ROLE.subaccount)
  1431. def dateCoinsDetail(request):
  1432. """
  1433. TODO 线下投币相关数据与收益计算展现彻底分离,接口需要重新审视
  1434. :param request:
  1435. :return:
  1436. """
  1437. ownerId = str(request.user.bossId)
  1438. pageIndex = int(request.GET.get('pageIndex', 1))
  1439. pageSize = int(request.GET.get('pageSize', 10))
  1440. nowDate = datetime.datetime.now().strftime('%Y-%m-%d')
  1441. groupIds = Group.get_group_ids_of_dealer(ownerId)
  1442. devNos = Device.get_devNos_by_group(groupIds)
  1443. keys = [devCoinTmpl(devNo, nowDate) for devNo in devNos]
  1444. devCoinDict = reportCache.get_many(keys)
  1445. devNoList = []
  1446. for key, coins in devCoinDict.items():
  1447. coins = int(coins)
  1448. if coins == 0:
  1449. continue
  1450. tempList = key.split('_')
  1451. devNo = tempList[1]
  1452. devNoList.append({'devNo': devNo, 'coins_count': coins})
  1453. sorted(devNoList, key=lambda dev: dev['coins_count'], reverse=True)
  1454. total = len(devNoList)
  1455. resultDevDictList = devNoList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  1456. devNoList = [dev['devNo'] for dev in resultDevDictList]
  1457. devDict = Device.get_dev_by_nos(devNoList)
  1458. groupIds = [dev['groupId'] for dev in devDict.values()]
  1459. groupDict = Group.get_groups_by_group_ids(groupIds)
  1460. dataList = []
  1461. for dev in resultDevDictList:
  1462. if dev['devNo'] not in devDict:
  1463. logger.warning('dev<IMEI={}> not belong to dealer<id={}>'.format(dev['devNo'], ownerId))
  1464. continue
  1465. devDetail = devDict[dev['devNo']]
  1466. groupDetail = groupDict[devDetail['groupId']]
  1467. dataList.append({
  1468. 'value': devDetail['logicalCode'],
  1469. 'coins_count': dev['coins_count'],
  1470. "online": devDetail["online"],
  1471. "remark": devDetail["remarks"],
  1472. "type": devDetail['devType']['name'],
  1473. "groupNumber": devDetail["groupNumber"],
  1474. "groupName": groupDetail['groupName'],
  1475. "status": devDetail['status'],
  1476. "statusInfo": devDetail['statusInfo']
  1477. })
  1478. return JsonResponse({"result": 1, "description": None, 'payload': {"total": total, "dataList": dataList}})
  1479. ########################
  1480. #### 经销商收益消费数据中心
  1481. ########################
  1482. @require_GET
  1483. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益统计失败'))
  1484. @permission_required(ROLE.dealer, ROLE.subaccount)
  1485. def getIncomeStatistics(request):
  1486. # type: (WSGIRequest)->JsonResponse
  1487. """
  1488. 经销商经营统计 首页获取入口
  1489. :param request:
  1490. :return:
  1491. """
  1492. currentDealer = request.user # type: cast(Dealer)
  1493. groupIds = Group.get_group_ids_of_dealer_and_partner(str(currentDealer.bossId))
  1494. stats = [
  1495. {
  1496. "name": u"完成订单",
  1497. "value": GroupDailyStat.get_today_recharge_count(groupIds=groupIds),
  1498. "effect": "good",
  1499. "unit": "",
  1500. "necessary": True
  1501. }
  1502. ]
  1503. agent = Agent.objects(id=currentDealer.agentId).get() # type: Agent
  1504. start, end = today_datetime_range()
  1505. if not agent.supports('hide_dealer_newly_user_added_count'):
  1506. stats.append({
  1507. "name": u"新增用户",
  1508. "value": MyUser.get_new_user_count(groupIds=groupIds, start=start, end=end),
  1509. "effect": "good",
  1510. "unit": "",
  1511. "necessary": True
  1512. })
  1513. dailyStat = DealerDailyStat.get_today(currentDealer.bossId)
  1514. consumption = dailyStat.get("consumption", dict())
  1515. for kind in agent.hide_consume_kinds_dealer:
  1516. consumption.pop(kind, None)
  1517. for kind, value in consumption.iteritems():
  1518. stats.append(
  1519. {
  1520. "source": kind,
  1521. "name": DEALER_CONSUMPTION_AGG_KIND_TRANSLATION.get(kind, ''),
  1522. "value": to_quantity(kind, value),
  1523. "effect": "good",
  1524. "unit": DEALER_CONSUMPTION_AGG_KIND_UNIT.get(kind, ''),
  1525. "necessary": False
  1526. }
  1527. )
  1528. # 将非必须的并且值为 0的过滤掉
  1529. todayStatList = filter(lambda _: float(str((_.get("value", 0)))) > 0 or _.get("necessary"), stats)
  1530. now = datetime.datetime.now()
  1531. monthStr = MONTH_DATE_KEY.format(year=now.year, month=now.month)
  1532. return JsonOkResponse(
  1533. payload={
  1534. "monthIncome": DealerDailyStatsModelProxy.get_one_month_income(
  1535. dealerId = currentDealer.bossId, monthStr = monthStr),
  1536. "todayIncome": DealerDailyStat.get_today_income(dealerId = currentDealer.bossId),
  1537. 'todayRefundCash': abs(DealerDailyStat.get_today_refund_cash(dealerId = currentDealer.bossId)),
  1538. "todayStatList": todayStatList
  1539. }
  1540. )
  1541. @require_GET
  1542. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益消费来源失败'))
  1543. @permission_required(ROLE.dealer, ROLE.subaccount)
  1544. def getIncomeConsumptionCategories(request):
  1545. # type: (WSGIRequest)->JsonResponse
  1546. """
  1547. :param request:
  1548. :return:
  1549. """
  1550. currentDealer = request.user # type: cast(Dealer)
  1551. expand = lambda _: [{'text': v, 'value': k} for k, v in _.items()]
  1552. return JsonResponse(
  1553. {
  1554. 'result': 1,
  1555. 'description': '',
  1556. 'payload': {
  1557. 'income': expand(currentDealer.income_aggregate_source),
  1558. 'consumption': expand(currentDealer.consumption_aggregate_source)
  1559. }
  1560. })
  1561. @require_GET
  1562. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益列表失败'))
  1563. @permission_required(ROLE.dealer, ROLE.subaccount)
  1564. def getIncomeList(request):
  1565. # type: (WSGIRequest)->JsonResponse
  1566. """
  1567. 经销商经营统计的列表 从incomeProxy维度读取
  1568. :param request:
  1569. :return:
  1570. """
  1571. current_dealer = request.user # type: Union[Dealer, SubAccount]
  1572. current_dealer_id = str(current_dealer.bossId)
  1573. pageIndex = int(request.GET.get('pageIndex', 1))
  1574. pageSize = int(request.GET.get('pageSize', 10))
  1575. startTime = request.GET.get("startTime")
  1576. endTime = request.GET.get("endTime")
  1577. logicalCode = request.GET.get("logicalCode")
  1578. source = request.GET.get("secondary")
  1579. groupId = request.GET.get('groupId')
  1580. if groupId and groupId == 'undefined':
  1581. return JsonErrorResponse(description = u'地址过滤参数错误,请刷新后重试')
  1582. if not groupId:
  1583. groupIds = [ObjectId(groupId) for groupId in Group.get_group_ids_of_dealer_and_partner(current_dealer_id)]
  1584. else:
  1585. groupIds = [ObjectId(groupId)]
  1586. searchKey = request.GET.get("searchKey")
  1587. filters = {
  1588. "groupId__in": groupIds,
  1589. "hint": [('groupId', 1), ('dateTimeAdded', -1)],
  1590. }
  1591. if logicalCode:
  1592. filters.update({"logicalCode": logicalCode})
  1593. # 将source为 保险的排除 经销商的主营收益仅仅为以下几种
  1594. if source:
  1595. sources = [source]
  1596. else:
  1597. sources = [
  1598. DEALER_INCOME_SOURCE.REFUND_CASH,
  1599. DEALER_INCOME_SOURCE.RECHARGE,
  1600. DEALER_INCOME_SOURCE.REDPACK,
  1601. DEALER_INCOME_SOURCE.OFFLINE_COIN,
  1602. DEALER_INCOME_SOURCE.RECHARGE_CARD,
  1603. DEALER_INCOME_SOURCE.RECHARGE_VIRTUAL_CARD
  1604. ]
  1605. filters.update({"source__in": sources})
  1606. if searchKey:
  1607. filters.update({"searchKey": searchKey})
  1608. startTime, endTime = current_dealer.limit_filter_date(startTime, endTime)
  1609. if startTime > endTime:
  1610. return JsonResponse({
  1611. 'result': 1,
  1612. 'description': None,
  1613. 'payload': {
  1614. 'total': 0,
  1615. 'adShow': current_dealer.adShow,
  1616. 'totalAmount': RMB(0),
  1617. 'dataList': [],
  1618. }
  1619. })
  1620. # 获取收益集合
  1621. st = datetime.datetime.strptime(startTime, "%Y-%m-%d")
  1622. et = datetime.datetime.strptime(endTime, "%Y-%m-%d")
  1623. incomeQuery = DealerIncomeProxy.objects.filter(dateTimeAdded__gte=st, dateTimeAdded__lt=et+datetime.timedelta(days=1), **filters) # type: CustomQuerySet
  1624. total, totalAmount = incomeQuery.sum_and_count("actualAmountMap.{}".format(current_dealer_id))
  1625. # 第一次循环提取出收益模型以及其对应的充值单号
  1626. incomes = list()
  1627. ref_ids = list()
  1628. for _income in incomeQuery.paginate(pageIndex, pageSize): # type: DealerIncomeProxy
  1629. incomes.append(_income)
  1630. ref_ids.append(_income.ref_id)
  1631. # 取出所有的充值记录
  1632. recharges = dict()
  1633. if ref_ids:
  1634. for item in RechargeRecord.objects.filter(id__in=ref_ids): # type: RechargeRecord
  1635. recharges[str(item.id)] = item
  1636. # 最后看是否需要执行内存合单
  1637. dataList = list()
  1638. for _record in incomes:
  1639. if str(_record.ref_id) not in recharges:
  1640. logger.warning('order<id={}> not exist.'.format(str(_record.ref_id)))
  1641. continue
  1642. rechargeOrder = recharges[str(_record.ref_id)] # type: RechargeRecord
  1643. # 找到同级的子单 然后一起合并
  1644. if rechargeOrder.isSubOrder:
  1645. _subOrders = RechargeRecord.objects.filter(
  1646. id__ne=rechargeOrder.id,
  1647. ownerId=rechargeOrder.ownerId,
  1648. devNo=rechargeOrder.devNo,
  1649. openId=rechargeOrder.openId,
  1650. wxOrderNo=rechargeOrder.wxOrderNo
  1651. )
  1652. # 找到该笔支付单的所有分账单proxy
  1653. _incomes = DealerIncomeProxy.objects.filter(ref_id__in=[_.id for _ in _subOrders])
  1654. _data = _record.to_dict(dealerId=current_dealer_id)
  1655. _data["subs"] = [_record.to_dict(current_dealer_id)]
  1656. for _income in _incomes:
  1657. _incomeDict = _income.to_dict(current_dealer_id)
  1658. _data["totalAmount"] += _incomeDict["totalAmount"]
  1659. _data["amount"] += _incomeDict["amount"]
  1660. _data["subs"].append(_incomeDict)
  1661. else:
  1662. _data = _record.to_dict(dealerId=current_dealer_id)
  1663. dataList.append(_data)
  1664. return JsonResponse(
  1665. {
  1666. 'result': 1,
  1667. 'description': "",
  1668. 'payload': {
  1669. 'total': total,
  1670. 'adShow': current_dealer.adShow,
  1671. 'totalAmount': RMB(totalAmount),
  1672. 'dataList': dataList,
  1673. }
  1674. }
  1675. )
  1676. @require_GET
  1677. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益详情失败'))
  1678. @permission_required(ROLE.dealer, ROLE.subaccount)
  1679. def getIncomeDetail(request):
  1680. # type: (WSGIRequest)->JsonResponse
  1681. """
  1682. 根据 存在收入代理里的`ref_id`来获取真实的收入对应的对象,以拼装出真实的详情
  1683. :param request:
  1684. :return:
  1685. """
  1686. currentDealerId = str(request.user.bossId)
  1687. _id = request.GET.get("id")
  1688. _ref_id = request.GET.get("ref_id")
  1689. if not any([_id, _ref_id]) or 'groupId' not in request.GET:
  1690. return JsonErrorResponse(description=u'参数错误,请刷新后再试')
  1691. filters = {"id": _id} if _id else {"ref_id": ObjectId(_ref_id)}
  1692. filters.update({'shard_filter': {'groupId': request.GET.get('groupId')}})
  1693. record = ClientDealerIncomeModelProxy.get_one(**filters) # type: DealerIncomeProxy
  1694. if not record:
  1695. return JsonErrorResponse(description=u"未查询到该笔订单")
  1696. data = record.ref_detail(currentDealerId)
  1697. startKey = data.get("startKey", None)
  1698. if startKey:
  1699. consumeRecord = ConsumeRecord.objects(startKey=data.get('startKey', '')).first()
  1700. if consumeRecord is not None:
  1701. data.update({'orderNo': consumeRecord.orderNo})
  1702. data.update({'consumeId': str(consumeRecord.id)})
  1703. rechargeRecord = RechargeRecord.objects.filter(id=record.ref_id).first()
  1704. if rechargeRecord is not None and rechargeRecord.via == 'redpack':
  1705. data.update({'gateway': 'redpack'})
  1706. # 新加入一个判断,如果是group owner则显示全部正常信息,如果不是只显示全部金额和自己分到的金额信息
  1707. # 判断是否是group owner,如果是group显示全部完整信息
  1708. for partnerInfo in data['incomePartitionList']:
  1709. if partnerInfo['owner']:
  1710. if partnerInfo['role'] == 'me':
  1711. return JsonResponse({'result': 1, 'description': '', 'payload': data})
  1712. # 判断是role是否是me,如果不是本人信息则不显示
  1713. for i in range(len(data['incomePartitionList']) - 1, -1, -1):
  1714. if data['incomePartitionList'][i]['role'] != 'me':
  1715. del data['incomePartitionList'][i]
  1716. return JsonResponse({'result': 1, 'description': '', 'payload': data})
  1717. @require_GET
  1718. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取消费列表失败'))
  1719. @permission_required(ROLE.dealer, ROLE.subaccount)
  1720. def getConsumptionList(request):
  1721. # type: (WSGIRequest)->JsonResponse
  1722. """
  1723. :param request:
  1724. :return:
  1725. """
  1726. def coin_quantity(amount):
  1727. # type:(float)->Quantity
  1728. return Quantity(amount, places=consumption_unit_precision(DEALER_CONSUMPTION_AGG_KIND.COIN))
  1729. current_dealer = request.user # type: cast(Dealer)
  1730. current_dealer_id = str(current_dealer.bossId)
  1731. pageIndex = int(request.GET.get('pageIndex', 1))
  1732. pageSize = int(request.GET.get('pageSize', 10))
  1733. startTime = request.GET.get('startTime')
  1734. endTime = request.GET.get('endTime')
  1735. startTime, endTime = current_dealer.limit_filter_date(startTime, endTime)
  1736. if endTime < startTime:
  1737. return JsonResponse({
  1738. 'result': 1,
  1739. 'description': None,
  1740. 'payload': {
  1741. 'total': 0,
  1742. 'adShow': current_dealer.adShow,
  1743. 'totalAmount': RMB(0),
  1744. 'dataList': []
  1745. }
  1746. })
  1747. else:
  1748. logicalCode = request.GET.get("logicalCode")
  1749. source = request.GET.get("secondary")
  1750. groupId = request.GET.get('groupId')
  1751. filters = {
  1752. 'isNormal': True
  1753. }
  1754. if not groupId:
  1755. filters.update({
  1756. 'ownerId__in': Dealer.get_cooperative_dealer_ids(current_dealer_id),
  1757. 'groupId__in': Dealer.get_cooperative_group_ids(current_dealer_id)
  1758. })
  1759. else:
  1760. group = Group.get_group(groupId) # type: GroupDict
  1761. filters.update({
  1762. 'shard_filter': {'ownerId': group.ownerId},
  1763. 'groupId': groupId
  1764. })
  1765. searchKey = request.GET.get("searchKey")
  1766. if logicalCode:
  1767. filters.update({
  1768. "logicalCode": logicalCode
  1769. })
  1770. if source:
  1771. filters.update({"aggInfo__{}__exists".format(source): True})
  1772. if searchKey:
  1773. filters.update({"searchKey": searchKey})
  1774. # 获取的是总的数据条目
  1775. records = ClientConsumeModelProxy.get_data_list(startTime=startTime, endTime=endTime,
  1776. **filters) # type: CustomQuerySet
  1777. total, totalAmount = records.sum_and_count("coin")
  1778. totalAmount = coin_quantity(totalAmount)
  1779. agent = Agent.objects.get(id=current_dealer.agentId) # type: Agent
  1780. return JsonResponse(
  1781. {
  1782. 'result': 1,
  1783. 'description': None,
  1784. 'payload':
  1785. {
  1786. 'total': total,
  1787. 'adShow': current_dealer.adShow,
  1788. 'totalAmount': totalAmount,
  1789. 'dataList': [
  1790. _record.to_dict(source=source, hides=agent.hide_consume_kinds_dealer) for _record in
  1791. records.paginate(pageIndex, pageSize)
  1792. ],
  1793. }
  1794. })
  1795. @require_GET
  1796. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取消费详情失败'))
  1797. @permission_required(ROLE.dealer, ROLE.subaccount)
  1798. def getConsumptionDetail(request):
  1799. # type: (WSGIRequest)->JsonResponse
  1800. """
  1801. 消费详情应该附上成本信息(如果有)
  1802. 通过RECHARGE查询CONSUME有两种情况. 一个是CONSUME一定在RECHARGE之后; 还有一个是
  1803. 后支付, RECHARGE后建立起来. 这种情况下会在RECHARGE保存consumeid
  1804. :param request:
  1805. :return:
  1806. """
  1807. id_ = request.GET.get('id')
  1808. start_key = request.GET.get('startKey')
  1809. filters = {'shard_filter': {"ownerId": request.GET.get('ownerId')}}
  1810. if id_:
  1811. filters.update({"id": str(id_)})
  1812. record = ClientConsumeModelProxy.get_one(**filters) # type: ConsumeRecord
  1813. elif start_key:
  1814. filters.update({"startKey": start_key, "hint": [("startKey", 1)]})
  1815. record = ClientConsumeModelProxy.get_one(foreign_id=request.GET.get('ref_id'),
  1816. **filters) # type: ConsumeRecord
  1817. else:
  1818. logger.error("[getConsumptionDetail] not id and not startKey !")
  1819. return JsonErrorResponse(description=u'参数错误,请刷新后再试')
  1820. payload = record.to_detail()
  1821. if payload.has_key('aggInfo'):
  1822. newAggInfo = [remove_some_desc_for_consume(value, u'使用时长') for value in payload['aggInfo']]
  1823. payload['aggInfo'] = newAggInfo
  1824. if record.isNormal:
  1825. device = Device.get_dev(record.devNo) # type: DeviceDict
  1826. if device:
  1827. payload.update({
  1828. 'showPG': device.support_power_graph
  1829. })
  1830. else:
  1831. payload.update({'showPG': False})
  1832. return JsonOkResponse(payload=payload)
  1833. @require_POST
  1834. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"关闭订单失败"))
  1835. @permission_required(ROLE.dealer)
  1836. def closeOrder(request):
  1837. payload = json.loads(request.body)
  1838. orderId = payload.get("orderId", "")
  1839. order = ClientConsumeModelProxy.get_one(id=orderId)
  1840. order.status = "finished"
  1841. order.save()
  1842. return JsonOkResponse()
  1843. @permission_required(ROLE.dealer, ROLE.subaccount)
  1844. def groupConsumptionData(request):
  1845. # type: (WSGIRequest)->JsonResponse
  1846. """
  1847. 经销商旗下所有组的消费数据
  1848. :param request:
  1849. :return:
  1850. """
  1851. def get_group_info(g, _id):
  1852. isM = _id == g.get("ownerId")
  1853. if not isM:
  1854. p = round_2_digits(float(g.get("partnerDict", dict()).get(_id, dict()).get("percent", 0)))
  1855. else:
  1856. fullPercent = 100
  1857. for _partner in g.get("partnerDict", dict()).values():
  1858. fullPercent -= float(_partner.get("percent", 0))
  1859. p = round_2_digits(float(fullPercent))
  1860. return isM, p
  1861. current_user = request.user # type: Dealer
  1862. dealerId = str(current_user.bossId)
  1863. dealer = Dealer.objects.get(id=dealerId)
  1864. pageIndex = int(request.GET.get("pageIndex", 1))
  1865. pageSize = int(request.GET.get("pageSize", 10))
  1866. startDate = request.GET.get("startTime")
  1867. endDate = request.GET.get("endTime")
  1868. startDate, endDate = current_user.limit_filter_date(startDate, endDate)
  1869. if endDate < startDate:
  1870. return JsonResponse({
  1871. 'result': 1,
  1872. 'description': '',
  1873. 'payload': {
  1874. 'dataList': [],
  1875. 'total': 0,
  1876. 'adShow': current_user.adShow
  1877. }
  1878. })
  1879. else:
  1880. searchKey = request.GET.get("searchKey", None)
  1881. # 通过searchKey 获取组地址 作为查询的筛选条件
  1882. groupIds = Group.search_group_ids_of_dealer(dealerId, searchKey) + \
  1883. Group.search_group_ids_of_partner(dealerId, searchKey)
  1884. # 每个地址组一个单位 ,根据地址组ID来完成对数据分页
  1885. groupIdSlice = groupIds[(pageIndex - 1) * pageSize: pageSize * pageIndex]
  1886. groupStatisticMap = GroupDailyStatsModelProxy.get_groups_consumption_statistic(groupIds=groupIdSlice,
  1887. startDate=startDate,
  1888. endDate=endDate)
  1889. groupDevCountMap = Device.get_device_count_by_group(groupIdSlice)
  1890. agent = Agent.objects.get(id=current_user.agentId)
  1891. isHiddenUsedTime = True if 'hiddenUsedTime' in agent.features else False
  1892. dataList = list()
  1893. for _groupId in groupIdSlice:
  1894. groupStatistic = groupStatisticMap.get(_groupId, dict())
  1895. consumptionList = translate_consumption(groupStatistic, hides=agent.hide_consume_kinds_dealer)
  1896. # 志高电子隐藏经销商后台消耗电量和电费成本统计
  1897. if "not_show_about_elec" in dealer.features:
  1898. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"消耗电量"]
  1899. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"电费成本"]
  1900. if isHiddenUsedTime:
  1901. consumptionList = [_c for _c in consumptionList if _c.get("name") != u"使用时长"]
  1902. group = Group.get_group(_groupId)
  1903. isManager, percent = get_group_info(group, dealerId)
  1904. dataList.append({
  1905. 'groupName': group['groupName'],
  1906. 'groupId': group['groupId'],
  1907. 'address': group['address'],
  1908. 'equipmentCount': groupDevCountMap.get(_groupId, 0),
  1909. 'agentProfitShare': request.user.agentProfitShare,
  1910. 'isManager': group.get("ownerId") == dealerId,
  1911. 'consumptionList': consumptionList
  1912. })
  1913. dataList = sorted(dataList, key=lambda x: float(x['equipmentCount']), reverse=True)
  1914. total = len(groupIds)
  1915. return JsonResponse({
  1916. 'result': 1,
  1917. 'description': '',
  1918. 'payload': {
  1919. 'dataList': dataList,
  1920. 'total': total,
  1921. 'adShow': request.user.adShow
  1922. }
  1923. })
  1924. ##################################################################################
  1925. #### `经销商信息设置` ###############################################################
  1926. ##################################################################################
  1927. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新失败'))
  1928. @permission_required(ROLE.dealer, ROLE.subaccount)
  1929. def resetPassword(request):
  1930. # type: (WSGIRequest)->JsonResponse
  1931. dealer = request.user
  1932. oldPassword = request.POST.get('oldPassword', "")
  1933. if not oldPassword:
  1934. return JsonErrorResponse(description=u"请输入旧密码")
  1935. limitManager = LimitAttemptsManager('resetPassword', oldPassword)
  1936. if limitManager.is_exceeded_limit():
  1937. return JsonErrorResponse(description=u'超出输入错误次数限制,请明日再试')
  1938. if dealer.check_password(oldPassword):
  1939. password = request.POST.get('password', "")
  1940. if password == "":
  1941. return JsonErrorResponse(description=u"请输入密码")
  1942. else:
  1943. dealer.set_password(password)
  1944. request.session['password'] = password
  1945. limitManager.clear()
  1946. return JsonOkResponse()
  1947. else:
  1948. limitManager.incr()
  1949. return JsonErrorResponse(description=u'旧密码输入错误,您还可输入%s次' % limitManager.times_left())
  1950. # : 开关
  1951. # : 可考虑以后整合成一个接口
  1952. # : @url('service/toggleSwitches')
  1953. # : def f(request):
  1954. # : dealer.update(**json.loads(request.body))
  1955. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  1956. @permission_required(ROLE.dealer, ROLE.subaccount)
  1957. def setWithdrawMsgSwitch(request):
  1958. # type: (WSGIRequest)->JsonResponse
  1959. ownerId = str(request.user.bossId)
  1960. payload = json.loads(request.body) if request.body else {}
  1961. if not payload:
  1962. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  1963. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  1964. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  1965. updated = Dealer.objects(id=ownerId).update(withdrawlNotify=payload.get('on', False))
  1966. if updated:
  1967. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  1968. else:
  1969. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  1970. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  1971. @permission_required(ROLE.dealer, ROLE.subaccount)
  1972. def setOfflineNotifySwitch(request):
  1973. # type: (WSGIRequest)->JsonResponse
  1974. """
  1975. :param request:
  1976. :return:
  1977. """
  1978. ownerId = str(request.user.bossId)
  1979. payload = json.loads(request.body) if request.body else {}
  1980. if not payload:
  1981. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  1982. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  1983. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  1984. updated = Dealer.objects(id=ownerId).update(offlineNotifySwitch=payload.get('on', False))
  1985. if updated:
  1986. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  1987. else:
  1988. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  1989. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  1990. @permission_required(ROLE.dealer, ROLE.subaccount)
  1991. def saveOfflineNotifyTime(request):
  1992. # type: (WSGIRequest)->JsonResponse
  1993. """
  1994. :param request:
  1995. :return:
  1996. """
  1997. ownerId = str(request.user.bossId)
  1998. payload = json.loads(request.body) if request.body else {}
  1999. if not payload:
  2000. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  2001. if payload['offlineNotifyTime'] and (not request.user.isManagerialOpenIdBound):
  2002. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  2003. updated = Dealer.objects(id=ownerId).update(offlineNotifyTime=str(payload.get('offlineNotifyTime', '')))
  2004. if updated:
  2005. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2006. else:
  2007. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  2008. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  2009. @permission_required(ROLE.dealer, ROLE.subaccount)
  2010. def toggleNewUserPaymentOrderPushSwitch(request):
  2011. # type: (WSGIRequest)->JsonResponse
  2012. """
  2013. 用户支付订单后,即时推送给经销商
  2014. :param request:
  2015. :return:
  2016. """
  2017. ownerId = str(request.user.bossId)
  2018. payload = json.loads(request.body) if request.body else {}
  2019. if not payload:
  2020. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  2021. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  2022. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  2023. updated = Dealer.objects(id=ownerId).update(newUserPaymentOrderPushSwitch=payload.get('on', False))
  2024. if updated:
  2025. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2026. else:
  2027. return JsonResponse({"result": 0, "description": u'更新写入失败', 'payload': {}})
  2028. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  2029. @permission_required(ROLE.dealer, ROLE.subaccount)
  2030. def toggleDailyIncomeReportPushSwitch(request):
  2031. # type: (WSGIRequest)->JsonResponse
  2032. """
  2033. 每日9点推送昨日报表
  2034. :param request:
  2035. :return:
  2036. """
  2037. ownerId = str(request.user.bossId)
  2038. payload = json.loads(request.body) if request.body else {}
  2039. if not payload:
  2040. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  2041. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  2042. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  2043. updated = Dealer.objects(id=ownerId).update(dailyIncomeReportPushSwitch=payload.get('on', False))
  2044. if updated:
  2045. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2046. else:
  2047. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  2048. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'查询错误'))
  2049. @permission_required(ROLE.dealer, ROLE.subaccount)
  2050. def paymentOrderRecords(request):
  2051. # type: (WSGIRequest)->JsonResponse
  2052. """
  2053. 经销商后台查询充值订单(仅仅查询充值订单的 退币一些列的不要展示了)
  2054. :param request:
  2055. :return:
  2056. """
  2057. ownerId = str(request.user.bossId)
  2058. payload = json.loads(request.body)
  2059. pageIndex = payload.get("pageIndex")
  2060. pageSize = payload.get("pageSize")
  2061. startTime = payload.get("startTime")
  2062. endTime = payload.get("endTime")
  2063. if not endTime:
  2064. endTime = datetime.datetime.now()
  2065. else:
  2066. endTime = get_tomorrow_zero_time(datetime.datetime.strptime(endTime, "%Y-%m-%d"))
  2067. if not startTime:
  2068. startTime = get_zero_time(endTime)
  2069. else:
  2070. startTime = get_zero_time(datetime.datetime.strptime(startTime, "%Y-%m-%d"))
  2071. if startTime > endTime:
  2072. startTime = endTime
  2073. orderStatus = payload.get("orderStatus")
  2074. groupInfo = payload.get("group", dict())
  2075. deviceInfo = payload.get("device", dict())
  2076. queryFilters = {
  2077. 'dateTimeAdded': {
  2078. '$gte': startTime,
  2079. '$lt': endTime
  2080. },
  2081. "via": {
  2082. "$in": map(format, [
  2083. USER_RECHARGE_TYPE.RECHARGE_MIX,
  2084. USER_RECHARGE_TYPE.RECHARGE,
  2085. USER_RECHARGE_TYPE.RECHARGE_CARD,
  2086. USER_RECHARGE_TYPE.RECHARGE_VIRTUAL_CARD,
  2087. USER_RECHARGE_TYPE.RECHARGE_CASH,
  2088. USER_RECHARGE_TYPE.RECHARGE_MONTHLY_PACKAGE,
  2089. USER_RECHARGE_TYPE.RECHARGE_REDPACK,
  2090. USER_RECHARGE_TYPE.RECHARGE_INSURANCE
  2091. ])
  2092. }
  2093. }
  2094. search_key = payload.get('searchKey', None)
  2095. if search_key:
  2096. if len(search_key) < 15:
  2097. dev = Device.get_dev_by_logicalCode(search_key)
  2098. if dev:
  2099. queryFilters.update({'devNo': dev.devNo})
  2100. if 'devNo' not in queryFilters:
  2101. queryFilters.update({
  2102. '$or': [
  2103. {'orderNo': search_key},
  2104. {'wxOrderNo': search_key},
  2105. {'transactionId': search_key}
  2106. ]
  2107. })
  2108. else:
  2109. # 订单的状态
  2110. if orderStatus:
  2111. queryFilters.update({"result": orderStatus})
  2112. # 查找的逻辑 自下从上查找 依次是 设备 --> 组 --> 当前查询人 --> 空查询
  2113. # TODO 这个地方的信息安全性 完全依赖上次调度的接口, 目前没有做检查 记得加上
  2114. if deviceInfo:
  2115. queryFilters.update({"devNo": deviceInfo.get("devNo"), "ownerId": deviceInfo.get("ownerId")})
  2116. elif groupInfo:
  2117. queryFilters.update({"groupId": groupInfo.get("groupId"), "ownerId": groupInfo.get("ownerId")})
  2118. else:
  2119. # TODO 这个地方有个BUG 经销商的ID 防止部分新加入的组合伙人 能看到之前组的经营统计信息
  2120. groupIds = list(set(Group.get_group_ids_of_dealer_and_partner(ownerId)))
  2121. groups = Group.get_groups_by_group_ids(groupIds)
  2122. dealer_id_list = list(set([group['ownerId'] for group in groups.values()]))
  2123. queryFilters.update({
  2124. 'ownerId': {'$in': dealer_id_list},
  2125. 'groupId': {'$in': groupIds}
  2126. })
  2127. logger.debug('query recharges between {} and {}. filters = {}'.format(startTime, endTime, queryFilters))
  2128. # 添加筛选条件 选出不是交易子单的订单
  2129. query_set = RechargeRecord.objects.filter(__raw__=queryFilters).filter(attachParas__tradeOrderId=None).order_by('-dateTimeAdded') # type: CustomQuerySet
  2130. totalSum = query_set.sum(RechargeRecord.money.name)
  2131. total_count = query_set.count()
  2132. records = query_set.paginate(pageIndex, pageSize)
  2133. dataList = list()
  2134. for _item in records: # type: RechargeRecord
  2135. # 订单的基本信息
  2136. data = {
  2137. 'id': str(_item.id),
  2138. 'ownerId': _item.ownerId,
  2139. 'gateway': _item.gateway if _item.gateway else 'wechat',
  2140. 'result': _item.result if _item.result else '',
  2141. 'totalFee': _item.money if _item.money else 0,
  2142. 'address': _item.address if _item.address else '',
  2143. 'name': _item.groupName if _item.groupName else '',
  2144. 'nickname': _item.nickname if _item.nickname else '',
  2145. 'devTypeName': _item.dev_type_name,
  2146. 'groupNumber': _item.groupNumber if _item.groupNumber else '',
  2147. 'value': Device.get_logicalCode_by_devNo(_item.devNo) if _item.devNo else '',
  2148. 'wechatTrxid': _item.wxOrderNo if _item.wxOrderNo else '',
  2149. 'outTradeNo': _item.orderNo if _item.orderNo else '',
  2150. 'createdTime': _item.to_datetime_str(_item.dateTimeAdded),
  2151. 'description': _item.my_description if _item.my_description else '',
  2152. 'userId': _item.openId if _item.openId else '',
  2153. 'groupId': _item.groupId if _item.groupId else '',
  2154. 'via': _item.via if _item.via else '',
  2155. 'isQuickPay': _item.isQuickPay if _item.isQuickPay else False,
  2156. 'startKey': _item.attachParas.get('startKey', '') if _item.result == 'success' else '',
  2157. 'consumeId': _item.attachParas.get('consumeRecordId', ''),
  2158. 'isLedgered': _item.is_ledgered,
  2159. 'notLedgerDesc': _item.notLedgerDesc
  2160. }
  2161. # TODO 需要修改 加上子订单的信息
  2162. tradeOrders = RechargeRecord.objects.filter(
  2163. openId=_item.openId,
  2164. attachParas__tradeOrderId=str(_item.id)
  2165. )
  2166. _subs = list()
  2167. for _trade in tradeOrders: # type: RechargeRecord
  2168. _subData = {
  2169. 'id': str(_trade.id),
  2170. 'ownerId': _trade.ownerId,
  2171. 'gateway': _trade.gateway if _trade.gateway else 'wechat',
  2172. 'result': _trade.result if _trade.result else '',
  2173. 'totalFee': _trade.money if _trade.money else 0,
  2174. 'address': _trade.address if _trade.address else '',
  2175. 'name': _trade.groupName if _trade.groupName else '',
  2176. 'nickname': _trade.nickname if _trade.nickname else '',
  2177. 'devTypeName': _trade.dev_type_name,
  2178. 'groupNumber': _trade.groupNumber if _trade.groupNumber else '',
  2179. 'value': Device.get_logicalCode_by_devNo(_trade.devNo) if _trade.devNo else '',
  2180. 'wechatTrxid': _trade.wxOrderNo if _trade.wxOrderNo else '',
  2181. 'outTradeNo': _trade.orderNo if _trade.orderNo else '',
  2182. 'createdTime': _trade.to_datetime_str(_trade.dateTimeAdded),
  2183. 'description': _trade.my_description if _trade.my_description else '',
  2184. 'userId': _trade.openId if _trade.openId else '',
  2185. 'groupId': _trade.groupId if _trade.groupId else '',
  2186. 'via': _trade.via if _trade.via else '',
  2187. 'isQuickPay': _trade.isQuickPay if _trade.isQuickPay else False,
  2188. 'startKey': _trade.attachParas.get('startKey', '') if _trade.result == 'success' else '',
  2189. 'consumeId': _trade.attachParas.get('consumeRecordId', ''),
  2190. 'isLedgered': _trade.is_ledgered,
  2191. 'notLedgerDesc': _trade.notLedgerDesc
  2192. }
  2193. _subs.append(_subData)
  2194. data["subs"] = _subs
  2195. dataList.append(data)
  2196. return JsonResponse({
  2197. "result": 1,
  2198. "description": "",
  2199. 'payload': {
  2200. "page": pageIndex,
  2201. "pageSize": pageSize,
  2202. "total": total_count,
  2203. "totalSum":totalSum,
  2204. "items": dataList
  2205. }
  2206. })
  2207. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'查询错误'))
  2208. @permission_required(ROLE.dealer, ROLE.subaccount)
  2209. def consumeOrderRecords(request):
  2210. # type: (WSGIRequest)->JsonResponse
  2211. """
  2212. 经销商后台查询消费订单
  2213. :param request:
  2214. :return:
  2215. """
  2216. ownerId = str(request.user.bossId)
  2217. payload = json.loads(request.body)
  2218. pageIndex = payload.get("pageIndex")
  2219. pageSize = payload.get("pageSize")
  2220. startTime = payload.get("startTime")
  2221. endTime = payload.get("endTime")
  2222. if not endTime:
  2223. endTime = datetime.datetime.now()
  2224. else:
  2225. endTime = get_tomorrow_zero_time(datetime.datetime.strptime(endTime, "%Y-%m-%d"))
  2226. if not startTime:
  2227. startTime = get_zero_time(endTime)
  2228. else:
  2229. startTime = get_zero_time(datetime.datetime.strptime(startTime, "%Y-%m-%d"))
  2230. if startTime > endTime:
  2231. startTime = endTime
  2232. groupInfo = payload.get("group", dict())
  2233. deviceInfo = payload.get("device", dict())
  2234. filters = {
  2235. 'dateTimeAdded': {
  2236. '$gte': startTime,
  2237. '$lt': endTime
  2238. }
  2239. }
  2240. search_key = payload.get('searchKey', None)
  2241. if search_key:
  2242. if len(search_key) < 15:
  2243. dev = Device.get_dev_by_logicalCode(search_key)
  2244. if dev:
  2245. filters.update({'devNo': dev.devNo})
  2246. if 'devNo' not in filters:
  2247. filters.update({
  2248. 'orderNo': search_key
  2249. })
  2250. else:
  2251. # 查找的逻辑 自下从上查找 依次是 设备 --> 组 --> 当前查询人 --> 空查询
  2252. # TODO 这个地方的信息安全性 完全依赖上次调度的接口, 目前没有做检查 记得加上
  2253. if deviceInfo:
  2254. filters.update({"devNo": deviceInfo.get("devNo"), "ownerId": deviceInfo.get("ownerId")})
  2255. elif groupInfo:
  2256. filters.update({"groupId": groupInfo.get("groupId"), "ownerId": groupInfo.get("ownerId")})
  2257. else:
  2258. # TODO 这个地方有个BUG 经销商的ID 防止部分新加入的组合伙人 能看到之前组的经营统计信息
  2259. groupIds = list(set(Group.get_group_ids_of_dealer_and_partner(ownerId)))
  2260. groups = Group.get_groups_by_group_ids(groupIds)
  2261. dealer_id_list = list(set([group['ownerId'] for group in groups.values()]))
  2262. filters.update({
  2263. 'ownerId': {'$in': dealer_id_list},
  2264. 'groupId': {'$in': groupIds}
  2265. })
  2266. logger.debug('query consumes between {} and {}. filters = {}'.format(startTime, endTime, filters))
  2267. records = ConsumeRecord.objects.filter(__raw__=filters).order_by("-dateTimeAdded") # type: CustomQuerySet
  2268. count = records.count()
  2269. dataList = []
  2270. for rcd in records.paginate(pageIndex, pageSize):
  2271. try:
  2272. dataList.append(rcd.to_detail())
  2273. except Exception as e:
  2274. logger.exception(e)
  2275. continue
  2276. return JsonOkResponse(payload={"dataList": dataList, "total": count})
  2277. @permission_required(ROLE.dealer, ROLE.subaccount)
  2278. def discountRuleData(request):
  2279. # type: (WSGIRequest)->JsonResponse
  2280. groupId = request.GET.get('groupId', None)
  2281. ownerId = str(request.user.bossId)
  2282. if groupId is None:
  2283. ruleList = []
  2284. for k, v in request.user.format_default_discount.items():
  2285. ruleList.append({'ruleId': k, 'payAmount': k, 'coins': v})
  2286. return JsonResponse({"result": 1,
  2287. "description": None,
  2288. 'payload': {"ruleList": ruleList, "groupData": {}}})
  2289. else:
  2290. group = Group.get_group(groupId)
  2291. if group is None:
  2292. return JsonResponse({"result": 0, "description": u"找不到组", 'payload': {}})
  2293. devNos = Device.get_devNos_by_group([groupId])
  2294. group['equipmentCount'] = len(devNos)
  2295. if ownerId == group['ownerId']:
  2296. group['isManager'] = True
  2297. else:
  2298. group['isManager'] = False
  2299. ruleList = []
  2300. for k, v in group['ruleDict'].items():
  2301. ruleList.append({'ruleId': k, 'payAmount': k, 'coins': v})
  2302. return JsonResponse({"result": 1,
  2303. "description": None,
  2304. 'payload': {"ruleList": ruleList, "groupData": group}})
  2305. @permission_required(ROLE.dealer, ROLE.subaccount)
  2306. def discountCardRuleData(request):
  2307. """
  2308. 经销商端的卡优惠获取显示
  2309. # 新的规则修改为
  2310. 如果经销商设置有卡优惠规则 返还卡优惠规则
  2311. 如果经销商没有设置卡优惠规则 但是设置有金币优惠规则 返还金币优惠规则
  2312. 两个都没有设置 默认卡优惠规则
  2313. :param request:
  2314. :return:
  2315. """
  2316. groupId = request.GET.get("groupId", None)
  2317. # 没有组ID的情况获取的是经销商的默认 优惠套餐
  2318. ruleList = list()
  2319. if not groupId:
  2320. for k, v in request.user.format_card_discount.items():
  2321. ruleList.append({"ruleId": k, "payAmount": k, "coins": v})
  2322. return JsonOkResponse(payload={"ruleList": ruleList, "groupData": {}})
  2323. group = Group.get_group(groupId)
  2324. if not group:
  2325. return JsonErrorResponse(description=u"错误的地址信息")
  2326. # 经销商没有设置过卡的优惠规则
  2327. if not group.get("cardRuleDict"):
  2328. cardRuleDict = request.user.defaultCardDiscountConfig
  2329. Group.objects.filter(id=groupId).update(cardRuleDic=cardRuleDict)
  2330. Group.CacheMgr.invalid_group_cache([groupId])
  2331. group = Group.get_group(groupId)
  2332. devNos = Device.get_devNos_by_group([groupId])
  2333. ownerId = str(request.user.bossId)
  2334. group['equipmentCount'] = len(devNos)
  2335. if ownerId == group['ownerId']:
  2336. group['isManager'] = True
  2337. else:
  2338. group['isManager'] = False
  2339. ruleList = []
  2340. for k, v in group['cardRuleDict'].items():
  2341. ruleList.append({'ruleId': k, 'payAmount': k, 'coins': v})
  2342. return JsonResponse({"result": 1,
  2343. "description": None,
  2344. 'payload': {"ruleList": ruleList, "groupData": group}})
  2345. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  2346. @permission_required(ROLE.dealer, ROLE.subaccount)
  2347. def saveDiscountRule(request):
  2348. # type: (WSGIRequest)->JsonResponse
  2349. """
  2350. TODO TO REFACTOR
  2351. :param request:
  2352. :return:
  2353. """
  2354. currentDealer = request.user # type: cast(Dealer)
  2355. # 校验优惠规则
  2356. def check_rule_data(fields, rules):
  2357. for ruleDict in rules:
  2358. for field in fields:
  2359. if len(str(ruleDict[field])) > 12:
  2360. return False, u"%s数额超过限制" % ruleDict[field]
  2361. try:
  2362. float(ruleDict[field])
  2363. except ValueError:
  2364. return False, u"%s类型错误,请输入数字" % ruleDict[field]
  2365. return True, u''
  2366. def update_rule(ruleDict, rules):
  2367. isNewlyAdded = lambda d: d["payAmount"] not in ruleDict.keys()
  2368. if len(ruleDict) >= 10 and any(map(isNewlyAdded, rules)):
  2369. raise ParameterError(u'最多只能设置10条优惠充值信息')
  2370. for rule in rules:
  2371. if rule['ruleId']:
  2372. ruleDict.pop(str(rule['ruleId']), None)
  2373. if rule['ruleId'] != 0 and (float(rule['coins']) in ruleDict.values()):
  2374. raise ParameterError(u'同一套餐下,不能出现充不一样的钱,但是兑币的数目却相同')
  2375. ruleDict.update({str(rule['payAmount']): float(rule['coins'])})
  2376. return ruleDict
  2377. payload = json.loads(request.body) if request.body else {}
  2378. ruleList = payload.get('ruleData', None)
  2379. if ruleList is None:
  2380. return JsonErrorResponse(description=u'没有找到正确的规则')
  2381. status, msg = check_rule_data(["payAmount", "coins"], ruleList)
  2382. if not status:
  2383. return JsonErrorResponse(description=msg)
  2384. groupId = payload.get('groupId', None)
  2385. # groupId为空表示修改默认充值套餐
  2386. if groupId is None:
  2387. try:
  2388. newRuleDict = update_rule(currentDealer.format_default_discount, ruleList)
  2389. currentDealer.update(defaultDiscountConfig=newRuleDict)
  2390. return JsonResponse({"result": 1, "description": '', 'payload': {}})
  2391. except ParameterError as e:
  2392. return JsonErrorResponse(description=e.message)
  2393. else:
  2394. try:
  2395. group = Group.objects(id=groupId).first() # type: Group
  2396. if not group:
  2397. return JsonErrorResponse(description=u'组不存在,请刷新后再试')
  2398. isRecovery = payload.get('isRecovery', 'N')
  2399. if isRecovery == 'Y':
  2400. rule_dict = currentDealer.format_default_discount
  2401. else:
  2402. rule_dict = group.format_rule_dict
  2403. update_rule(rule_dict, ruleList)
  2404. Group.update_group(group_id=groupId, ruleDict=rule_dict)
  2405. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2406. except ParameterError as e:
  2407. return JsonErrorResponse(description=e.message)
  2408. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"更新错误"))
  2409. @permission_required(ROLE.dealer, ROLE.subaccount)
  2410. def saveDiscountCardData(request):
  2411. """
  2412. 保存卡优惠设置
  2413. :param request:
  2414. :return:
  2415. """
  2416. def _check(rules, fieldnames=None):
  2417. """
  2418. 校验 ruleList 的每一个字段和字段值
  2419. :param rules:
  2420. :param fieldnames:
  2421. :return:
  2422. """
  2423. if fieldnames is None:
  2424. fieldnames = ["payAmount", "coins"]
  2425. for ruleDict in rules:
  2426. for field in fieldnames:
  2427. if len(str(ruleDict[field])) > 12:
  2428. return False, u"%s数额超过限制" % ruleDict[field]
  2429. try:
  2430. float(ruleDict[field])
  2431. except ValueError:
  2432. return False, u"%s类型错误,请输入数字" % ruleDict[field]
  2433. return True, u""
  2434. def _update(ruleDict, rules):
  2435. """
  2436. 更新优惠套餐
  2437. :param ruleDict:
  2438. :param rules:
  2439. :return:
  2440. """
  2441. isNewlyAdded = lambda d: d["payAmount"] not in ruleDict.keys()
  2442. if len(ruleDict) >= 10 and any(map(isNewlyAdded, rules)):
  2443. raise ParameterError(u'最多只能设置10条优惠充值信息')
  2444. for rule in rules:
  2445. if rule['ruleId']:
  2446. ruleDict.pop(str(rule['ruleId']), None)
  2447. if rule['ruleId'] != 0 and (float(rule['coins']) in ruleDict.values()):
  2448. raise ParameterError(u'同一套餐下,不能出现充不一样的钱,但是兑币的数目却相同')
  2449. ruleDict.update({str(rule['payAmount']): float(rule['coins'])})
  2450. return ruleDict
  2451. payload = json.loads(request.body) if request.body else dict()
  2452. ruleList = payload.get("ruleData", None)
  2453. if ruleList is None:
  2454. return JsonErrorResponse(description=u"请设置正确的优惠规则")
  2455. status, msg = _check(ruleList)
  2456. if not status:
  2457. return JsonErrorResponse(description=msg)
  2458. groupId = payload.get("groupId", None)
  2459. if groupId is None:
  2460. try:
  2461. newDict = _update(request.user.format_card_discount, ruleList)
  2462. request.user.update(defaultCardDiscountConfig=newDict)
  2463. except ParameterError as e:
  2464. return JsonErrorResponse(description=e.message)
  2465. else:
  2466. return JsonOkResponse(payload={})
  2467. else:
  2468. try:
  2469. group = Group.objects(id=groupId).first() # type: Group
  2470. if not group:
  2471. return JsonErrorResponse(description=u'组不存在,请刷新后再试')
  2472. isRecovery = payload.get('isRecovery', 'N')
  2473. # if isRecovery == 'Y':
  2474. # rule_dict = request.user.format_card_discount
  2475. # else:
  2476. rule_dict = group.format_card_dict
  2477. newDict = _update(rule_dict, ruleList)
  2478. Group.update_group(group_id=groupId, cardRuleDict=newDict)
  2479. except ParameterError as e:
  2480. return JsonErrorResponse(description=e.message)
  2481. else:
  2482. return JsonOkResponse(payload={})
  2483. @permission_required(ROLE.dealer, ROLE.subaccount)
  2484. def delDiscountRule(request):
  2485. # type: (WSGIRequest)->JsonResponse
  2486. ruleId = request.POST.get('ruleId', None)
  2487. if not ruleId:
  2488. return JsonResponse({"result": 0, "description": u"缺少参数ruleId或为空", 'payload': {}})
  2489. groupId = request.POST.get('groupId', None)
  2490. if not groupId:
  2491. default_discount = request.user.format_default_discount
  2492. default_discount.pop(ruleId, None)
  2493. request.user.update(defaultDiscountConfig=default_discount)
  2494. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2495. else:
  2496. try:
  2497. group = Group.objects(id=str(groupId)).first()
  2498. if not group:
  2499. return JsonResponse({"result": 0, "description": u"组不存在,请刷新后再试", 'payload': {}})
  2500. rule_dict = group.format_rule_dict # type: dict
  2501. rule_dict.pop(ruleId, None)
  2502. Group.update_group(group_id=groupId, ruleDict=rule_dict)
  2503. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2504. except Exception, e:
  2505. logger.exception("update db error=%s,groupId=%s" % (e, groupId))
  2506. return JsonResponse({"result": 0, "description": u"更新异常,请重试", 'payload': {}})
  2507. @permission_required(ROLE.dealer, ROLE.subaccount)
  2508. def delDiscountCardData(request):
  2509. """
  2510. 删除卡优惠设置
  2511. :param request:
  2512. :return:
  2513. """
  2514. ruleId = request.POST.get('ruleId', None)
  2515. if not ruleId:
  2516. return JsonResponse({"result": 0, "description": u"缺少参数ruleId或为空", 'payload': {}})
  2517. groupId = request.POST.get('groupId', None)
  2518. if not groupId:
  2519. default_discount = request.user.format_card_discount
  2520. default_discount.pop(ruleId, None)
  2521. request.user.update(defaultCardDiscountConfig=default_discount)
  2522. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2523. else:
  2524. try:
  2525. group = Group.objects(id=str(groupId)).first()
  2526. if not group:
  2527. return JsonResponse({"result": 0, "description": u"组不存在,请刷新后再试", 'payload': {}})
  2528. rule_dict = group.format_card_dict # type: dict
  2529. rule_dict.pop(ruleId, None)
  2530. Group.update_group(group_id=groupId, cardRuleDict=rule_dict)
  2531. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2532. except Exception, e:
  2533. logger.exception("update db error=%s,groupId=%s" % (e, groupId))
  2534. return JsonResponse({"result": 0, "description": u"更新异常,请重试", 'payload': {}})
  2535. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取经销商信息错误'))
  2536. @permission_required(ROLE.dealer, ROLE.subaccount)
  2537. def accountInfo(request):
  2538. # type: (WSGIRequest)->JsonResponse
  2539. if check_role(request.user, ROLE.dealer):
  2540. dealer = Dealer.objects(id=str(request.user.bossId)).get() # type: Dealer
  2541. payload = dealer.to_dict()
  2542. else:
  2543. subaccount = SubAccount.objects(id=str(request.user.id)).get() # type: subaccount
  2544. payload = subaccount.to_dict()
  2545. agent = Agent.objects(id=payload['agentId']).first() # type: Agent
  2546. payload['servicePhone'] = agent.service_phone
  2547. payload['serviceQrcodeUrl'] = agent.serviceQrcodeUrl
  2548. return JsonResponse({"result": 1, "description": None, 'payload': payload})
  2549. ####`经销商金融版块(提现,银行卡信息)` ####################################################
  2550. @permission_required(ROLE.dealer, ROLE.subaccount)
  2551. def walletData(request):
  2552. # type: (WSGIRequest)->JsonResponse
  2553. dealerId = str(request.user.bossId)
  2554. dealer = Dealer.objects(id=dealerId).first() # type: Optional[Dealer]
  2555. if not dealer:
  2556. return JsonErrorResponse(description=u"没有找到经销商")
  2557. my_source_key = dealer.current_wallet_withdraw_source_key
  2558. inhouse_source_key = Agent.get_inhouse_prime_agent().current_wallet_withdraw_source_key
  2559. device_income_list = []
  2560. for source_key, balance in dealer.deviceBalance.iteritems():
  2561. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  2562. device_income_list.append({
  2563. 'id': source_key,
  2564. 'balance': balance.balance,
  2565. 'name': current_platform(source_key, my_source_key),
  2566. 'current': source_key == my_source_key
  2567. })
  2568. ad_income_list = []
  2569. for source_key, balance in dealer.adBalance.iteritems():
  2570. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  2571. ad_income_list.append({
  2572. 'id': source_key,
  2573. 'balance': balance.balance,
  2574. 'name': current_platform(source_key, inhouse_source_key),
  2575. 'current': source_key == inhouse_source_key
  2576. })
  2577. ledger_income_list = []
  2578. for source_key, balance in dealer.ledgerBalance.iteritems():
  2579. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  2580. ledger_income_list.append({
  2581. 'id': source_key,
  2582. 'balance': balance.balance,
  2583. 'name': current_platform(source_key, inhouse_source_key),
  2584. 'current': source_key == inhouse_source_key
  2585. })
  2586. payload = {
  2587. }
  2588. if len(device_income_list) > 0:
  2589. payload.update({
  2590. DEALER_INCOME_TYPE.DEVICE_INCOME: device_income_list
  2591. })
  2592. if len(ad_income_list) > 0:
  2593. payload.update({
  2594. DEALER_INCOME_TYPE.AD_INCOME: ad_income_list
  2595. })
  2596. if len(ledger_income_list) > 0:
  2597. payload.update({
  2598. DEALER_INCOME_TYPE.LEDGER_CONSUME: ledger_income_list
  2599. })
  2600. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  2601. # 经销商获取提现短信验证码
  2602. @error_tolerate(nil=DefaultJsonErrorResponse)
  2603. @permission_required(ROLE.dealer)
  2604. def getWithdrawCode(request):
  2605. # type: (WSGIRequest)->JsonResponse
  2606. currentDealer = request.user # type: Dealer
  2607. toNumber = request.user.username
  2608. agentId = request.user.agentId
  2609. agent = Agent.get_agent(agentId)
  2610. productName = agent['productName']
  2611. if not currentDealer.monitorPhone: # 没有监管的,直接发送验证码到本机
  2612. status, msg = dealerWithdrawSMSProvider.get(phoneNumber=toNumber,
  2613. productName=productName,
  2614. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  2615. else:
  2616. toNumber = currentDealer.monitorPhone
  2617. status, msg = dealerMonitorWithdrawSMSProvider.get(phoneNumber=toNumber,
  2618. productName=productName,
  2619. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  2620. if not status:
  2621. return JsonErrorResponse(description=msg)
  2622. else:
  2623. return JsonOkResponse()
  2624. @permission_required(ROLE.dealer)
  2625. def withdrawalsHistoryList(request):
  2626. # type: (WSGIRequest)->JsonResponse
  2627. """
  2628. 需要连同整个提现数据层整改
  2629. :param request:
  2630. :return:
  2631. """
  2632. current_user = request.user # type: Dealer
  2633. pageIndex = int(request.GET.get('pageIndex', 1))
  2634. pageSize = int(request.GET.get('pageSize', 10))
  2635. status = request.GET.get('status')
  2636. ownerId = str(request.user.bossId)
  2637. startTime = '2016-01-01'
  2638. startTime, _ = current_user.limit_filter_date(startTime, None)
  2639. startTime = datetime.datetime.strptime(startTime, "%Y-%m-%d")
  2640. if status:
  2641. records = WithdrawRecord.objects(ownerId=ownerId,
  2642. role=request.user.role,
  2643. status=status,
  2644. postTime__gte=startTime).order_by('-postTime')
  2645. else:
  2646. records = WithdrawRecord.objects(ownerId=ownerId,
  2647. role=request.user.role,
  2648. postTime__gte=startTime).order_by('-postTime')
  2649. return JsonResponse({
  2650. "result": 1,
  2651. "description": None,
  2652. 'payload': {
  2653. "total": records.count(),
  2654. "withdrawalTotal": RMB(records(status=WithdrawStatus.SUCCEEDED).sum('amount')),
  2655. "dataList": [
  2656. {
  2657. 'bankName': record.parentBankName,
  2658. 'paymentId': str(record.id),
  2659. 'withdrawalsDate': record.postTime.strftime("%Y-%m-%d %H:%M:%S"),
  2660. 'amount': record.amount,
  2661. 'statusText': translate_withdraw_state(record.status),
  2662. 'refunded': record.refunded
  2663. } for record in records.paginate(pageIndex, pageSize)
  2664. ]
  2665. }
  2666. })
  2667. @permission_required(ROLE.dealer)
  2668. def dealerWithdraw(request):
  2669. # type: (WSGIRequest)->JsonResponse
  2670. """
  2671. :param request:
  2672. :return:
  2673. """
  2674. currentDealer = request.user # type: cast(Dealer)
  2675. payload = json.loads(request.body)
  2676. open_id = payload.get('openId')
  2677. if not open_id:
  2678. return JsonResponse({"result": 0, "description": u'鉴权失败,请刷新后再试', 'payload': {}})
  2679. request.user.withdraw_open_id = open_id
  2680. amount = RMB(payload.get('amount', 0.0))
  2681. pay_type = payload.get('payType')
  2682. assert pay_type in (
  2683. WITHDRAW_PAY_TYPE.WECHAT, WITHDRAW_PAY_TYPE.BANK, WITHDRAW_PAY_TYPE.ALIPAY), 'not support this pay type'
  2684. assert amount > RMB(0), 'amount must be bigger than zero'
  2685. status, msg = request.user.withdraw_sms_provider.verify(phoneNumber=request.user.withdraw_sms_phone_number,
  2686. smsCode=payload.get('code'))
  2687. if not status:
  2688. return JsonResponse({"result": 0, "description": msg, 'payload': {}})
  2689. withdraw_service = DealerWithdrawService(payee=request.user,
  2690. income_type=payload.get('sourceType'),
  2691. amount=amount,
  2692. pay_type=pay_type,
  2693. bank_card_no=payload.get('bankAccount', ''))
  2694. result = withdraw_service.execute(source_key=payload.get('sourceId'), recurrent=False)
  2695. logger.debug('withdraw result is: {}'.format(result))
  2696. return JsonResponse(result)
  2697. @permission_required(ROLE.dealer, ROLE.subaccount)
  2698. def paymentInfo(request):
  2699. # type: (WSGIRequest)->JsonResponse
  2700. """
  2701. 展示提现页面数据
  2702. :param request:
  2703. :return:
  2704. """
  2705. ownerId = str(request.user.bossId)
  2706. paymentId = request.GET.get('paymentId', None)
  2707. if not paymentId:
  2708. return JsonErrorResponse(description=u'没有提供提现单ID')
  2709. record = WithdrawRecord.objects(id=str(paymentId)).first() # type: Optional[WithdrawRecord]
  2710. if not record:
  2711. return JsonErrorResponse(description=u"没有找到提现记录")
  2712. return JsonOkResponse(
  2713. payload={
  2714. 'type': record.parentBankName,
  2715. 'amount': record.amount,
  2716. 'preBalance': record.balance,
  2717. 'serviceFee': record.serviceFee,
  2718. 'actualPay': record.actualPay,
  2719. 'refunded': record.refunded,
  2720. 'statusText': translate_withdraw_state(record.status),
  2721. 'description': record.description,
  2722. 'withdrawalsDate': record.postTime.strftime("%Y-%m-%d %H:%M:%S")
  2723. }
  2724. )
  2725. @permission_required(ROLE.dealer)
  2726. def getDealerAutoWithdrawCode(request):
  2727. # type: (WSGIRequest)->JsonResponse
  2728. """
  2729. 经销商确认开启自动提现
  2730. :param request:
  2731. :return:
  2732. """
  2733. try:
  2734. phoneNumber = request.GET.get('phoneNumber', None)
  2735. if not phoneNumber:
  2736. return JsonErrorResponse(description=u'手机号码为空')
  2737. agent = Agent.get_agent(request.user.agentId)
  2738. productName = agent['productName']
  2739. status, msg = dealerAutoWithdrawSMSProvider.get(phoneNumber=phoneNumber,
  2740. productName=productName,
  2741. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  2742. if not status:
  2743. return JsonErrorResponse(description=msg)
  2744. else:
  2745. return JsonOkResponse()
  2746. except Exception as e:
  2747. logger.exception(e)
  2748. return JsonErrorResponse()
  2749. #### `Utils related` ###########################################################
  2750. @permission_required(ROLE.dealer, ROLE.subaccount)
  2751. def deviceMem(request):
  2752. # type: (WSGIRequest)->JsonResponse
  2753. logicalCode = request.GET.get('logicalCode')
  2754. if not logicalCode:
  2755. return JsonErrorResponse(description=u'未提供设备逻辑编码')
  2756. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  2757. dev = Device.get_dev(devNo)
  2758. return JsonResponse(dev)
  2759. @permission_required(ROLE.dealer, ROLE.subaccount)
  2760. def deviceInfo(request):
  2761. # type: (WSGIRequest)->JsonResponse
  2762. logicalCode = request.GET.get('logicalCode', '')
  2763. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  2764. dev = Device.get_dev(devNo)
  2765. if dev is None:
  2766. return JsonErrorResponse(description=u'设备不存在')
  2767. return JsonResponse(MessageSender.send(dev, DeviceCmdCode.GET_DEVINFO, {'IMEI': devNo}))
  2768. @permission_required(ROLE.dealer, ROLE.subaccount)
  2769. def getServiceInfo(request):
  2770. # type: (WSGIRequest)->JsonResponse
  2771. currentDealer = request.user.myBoss # type: Optional[Dealer]
  2772. if not currentDealer:
  2773. return JsonResponse({"result": 0, "description": u"没有找到经销商"})
  2774. value = {
  2775. "qrcodeUrl": currentDealer.qrcodeUrl,
  2776. "serviceName": currentDealer.serviceName,
  2777. "servicePhone": currentDealer.servicePhone
  2778. }
  2779. return JsonResponse({"result": 1, "description": "", 'payload': value})
  2780. @permission_required(ROLE.dealer)
  2781. def saveServiceInfo(request):
  2782. # type: (WSGIRequest)->JsonResponse
  2783. ownerId = request.user.bossId # type: ObjectId
  2784. qrcodeUrl = request.POST.get('qrcodeUrl')
  2785. serviceName = request.POST.get('serviceName')
  2786. if serviceName:
  2787. if NAME_RE.match(serviceName) is None:
  2788. logger.error('name formatting error, name=%s' % serviceName)
  2789. return JsonResponse({"result": 0, "description": u"请输入正确格式的名称, 2-20位"})
  2790. servicePhone = request.POST.get('servicePhone')
  2791. if servicePhone:
  2792. if PHONE_NUMBER_RE.match(servicePhone) is None:
  2793. logger.error('phone number format error, phone=%s' % servicePhone)
  2794. return JsonResponse({"result": 0, "description": u"请输入正确的手机号码"})
  2795. status, desc = dealerRegisterSMSProvider.verify(servicePhone, request.POST.get('code'))
  2796. if not status:
  2797. return JsonErrorResponse(desc)
  2798. result = Dealer.update_dealer(ownerId, qrcodeUrl=qrcodeUrl, serviceName=serviceName, servicePhone=servicePhone)
  2799. if not result:
  2800. return JsonResponse({"result": 0, "description": u"更新经销商服务信息错误"})
  2801. return JsonResponse({"result": 1, "description": "", 'payload': {}})
  2802. # : 报告老板
  2803. @permission_required(ROLE.dealer, ROLE.subaccount)
  2804. def userFeedbackRecords(request):
  2805. # type: (WSGIRequest)->JsonResponse
  2806. """
  2807. 获取用户反馈记录
  2808. :param request:
  2809. :return:
  2810. """
  2811. ownerId = str(request.user.bossId)
  2812. searchKey = request.GET.get('searchKey', '')
  2813. feedType = request.GET.get('feedType', '')
  2814. pageIndex = int(request.GET.get('pageIndex', '1'))
  2815. pageSize = int(request.GET.get('pageSize', '10'))
  2816. status = request.GET.get('status', None)
  2817. if status and status != 'null':
  2818. status = int(status)
  2819. else:
  2820. status = None
  2821. dateStart = request.GET.get('dateStart', '')
  2822. if dateStart == '':
  2823. startTime = '2000-01-01 00:00:00'
  2824. else:
  2825. startTime = dateStart + " 00:00:00"
  2826. dateEnd = request.GET.get('dateEnd', '')
  2827. if dateEnd == '':
  2828. endTime = '2100-01-01 00:00:00'
  2829. else:
  2830. endTime = dateEnd + " 23:59:59"
  2831. query = {
  2832. 'ownerId': str(ownerId),
  2833. '$and': [
  2834. {
  2835. 'createTime': {
  2836. '$gte': startTime
  2837. }
  2838. },
  2839. {
  2840. 'createTime': {
  2841. '$lte': endTime
  2842. }
  2843. },
  2844. ],
  2845. }
  2846. if feedType:
  2847. if feedType == 'other':
  2848. feed_type_list = ['refund', 'upper']
  2849. query.update({
  2850. 'feedType': {'$in': feed_type_list},
  2851. 'consumeRecordOrderNo': {'$in': [None, '']}
  2852. })
  2853. else:
  2854. feed_type_list = [feedType]
  2855. query.update({
  2856. 'feedType': {'$in': feed_type_list}
  2857. })
  2858. if status is not None:
  2859. query.update({
  2860. 'status': status
  2861. })
  2862. results = FeedBack.objects(__raw__ = query).search(searchKey).order_by('-createTime')
  2863. total = results.count()
  2864. rv = []
  2865. for item in results.paginate(pageIndex, pageSize): # type: FeedBack
  2866. rv.append(item.summary)
  2867. data = {'page': pageIndex, 'total': total, 'pageSize': pageSize, 'items': rv}
  2868. return JsonResponse({'result': 1, 'description': "", 'payload': data})
  2869. @permission_required(ROLE.dealer, ROLE.subaccount)
  2870. def userFeedbackInfo(request):
  2871. # type: (WSGIRequest)->JsonResponse
  2872. fdId = str(request.GET.get('id'))
  2873. fd = FeedBack.objects(id = fdId).first() # type: FeedBack
  2874. if not fd:
  2875. return JsonResponse({'result': 0, 'description': u"投诉订单不存在,请刷新页面重试", 'payload': {}})
  2876. else:
  2877. return JsonResponse({'result': 1, 'description': "", 'payload': fd.detail})
  2878. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'处理失败'))
  2879. @permission_required(ROLE.dealer, ROLE.subaccount)
  2880. def userFeedbackHandle(request):
  2881. # type: (WSGIRequest)->JsonResponse
  2882. """
  2883. :param request:
  2884. :return:
  2885. """
  2886. payload = json.loads(request.body) if request.body else {}
  2887. if not payload:
  2888. return JsonErrorResponse(description = u'传入数据为空')
  2889. action = payload.get('action')
  2890. if not action:
  2891. return JsonOkResponse()
  2892. dealerRemark = payload.get('dealerRemark', u'(未填写回复内容)')
  2893. dealerImgList = payload.get('dealerImgList', [])
  2894. options = {} if dealerRemark is None else {'dealerRemark': dealerRemark, 'dealerImgList': dealerImgList}
  2895. feedback = FeedBack.objects(id = payload['id']).first() # type: Optional[FeedBack]
  2896. if not feedback:
  2897. return JsonErrorResponse(description = u'没有找到该反馈单')
  2898. dealer = Dealer.objects(id = feedback.ownerId).first() # type: Optional[Dealer]
  2899. if not dealer:
  2900. return JsonErrorResponse(description = u'未找到该反馈单的经销商')
  2901. feedType = feedback.feedType
  2902. if feedback.my_logicalCode:
  2903. device = Device.objects(logicalCode = feedback.my_logicalCode).first() # type: Optional[Device]
  2904. else:
  2905. device = None
  2906. if not device:
  2907. return JsonErrorResponse(description = u'找不到相关设备')
  2908. wechat_mp_proxy = get_wechat_user_manager_mp_proxy(dealer) # type: WechatClientProxy
  2909. user = MyUser.objects(openId = feedback.openId, groupId = feedback.my_group_id).first() # type: Optional[MyUser]
  2910. if not user:
  2911. logger.warning('user<openId={}> not exists for feedback<id={}>'.format(feedback.openId, str(feedback.id)))
  2912. if action in ['close', 'reject']:
  2913. feedback.handle(action, **options)
  2914. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2915. 'title': u'您反馈的问题已经处理' if action == 'close' else u'您反馈的问题已经被驳回',
  2916. 'event': '%s:%s' % (feedback.message_type, feedback.description),
  2917. 'remark': '%s: %s' % (u'设备老板回复', dealerRemark),
  2918. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2919. }) if user else None
  2920. return JsonOkResponse()
  2921. elif action == 'stop':
  2922. assert feedType == 'fault', u'投诉类型错误'
  2923. device.set_fault()
  2924. feedback.handle(action, **options)
  2925. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2926. 'title': u'您反馈的问题已经处理',
  2927. 'event': u'设备已经暂停使用,等待维修中',
  2928. 'remark': '%s: %s' % (u'设备老板回复', dealerRemark),
  2929. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2930. }) if user else None
  2931. return JsonResponse({'result': 1, 'description': "", 'payload': {}})
  2932. elif action == 'refund':
  2933. if not user:
  2934. return JsonErrorResponse(description = u'用户不存在,无法派币')
  2935. agent = Agent.objects.get(id = request.user.agentId)
  2936. if 'coinIsMoney' in agent.features:
  2937. return JsonResponse({'result': 2, 'description': u"代理商的配置,不允许给用户派币", 'payload': {}})
  2938. refundCoins = VirtualCoin(payload.get('refundCoins'))
  2939. if refundCoins > VirtualCoin(0):
  2940. inced = user.incr_balance(refundCoins)
  2941. if not inced:
  2942. logger.error('failed to incr balance for %r' % (user,))
  2943. return JsonErrorResponse(description = u'退币失败')
  2944. RechargeRecord.from_feedback(feedback, refundCoins).save()
  2945. feedback.handle(action, **options)
  2946. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2947. 'title': u'您反馈的问题已经处理',
  2948. 'event': u'%s:%s' % (feedback.message_type, feedback.description),
  2949. 'remark': '%s: %s' % (u'设备老板回复', dealerRemark),
  2950. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2951. }) if user else None
  2952. return JsonOkResponse()
  2953. else:
  2954. logger.warning('invalid action<value={}> for feedback<id=>'.format(action, str(feedback.id)))
  2955. return JsonOkResponse()
  2956. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'处理失败'))
  2957. @permission_required(ROLE.dealer, ROLE.subaccount)
  2958. def userFeedbackBatchHandle(request):
  2959. # type: (WSGIRequest)->JsonResponse
  2960. """
  2961. :param request:
  2962. :return:
  2963. """
  2964. payload = json.loads(request.body) if request.body else {}
  2965. if not payload:
  2966. return JsonErrorResponse(description = u'传入数据为空')
  2967. dealerRemark = payload.get('dealerRemark')
  2968. options = {} if dealerRemark is None else {'dealerRemark': dealerRemark}
  2969. feedbacks = FeedBack.objects(id__in = payload['ids'])
  2970. if feedbacks.count() == 0:
  2971. return JsonErrorResponse(description = u'没有找到反馈单')
  2972. for feedback in feedbacks:
  2973. feedback.handle('close', **options)
  2974. dealer = Dealer.objects(id = feedback.ownerId).first() # type: Optional[Dealer]
  2975. if not dealer:
  2976. logger.warning(
  2977. 'not find this dealer<id={}> for feedback<id={}>'.format(feedback.ownerId, str(feedback.id)))
  2978. continue
  2979. wechat_mp_proxy = get_wechat_user_manager_mp_proxy(dealer) # type: WechatClientProxy
  2980. user = MyUser.objects(openId = feedback.openId, groupId = feedback.my_group_id).first() # type: Optional[MyUser]
  2981. if not user:
  2982. logger.warning(
  2983. 'not find this user<openId={}> for feedback<id={}>'.format(feedback.openId, str(feedback.id)))
  2984. continue
  2985. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2986. 'title': u'您反馈的问题已经处理',
  2987. 'event': '%s:%s' % (feedback.message_type, feedback.description),
  2988. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2989. })
  2990. return JsonOkResponse()
  2991. @error_tolerate(nil=DefaultJsonErrorResponse)
  2992. @permission_required(ROLE.dealer, ROLE.subaccount)
  2993. def getCustomerDetailInfo(request):
  2994. # type: (WSGIRequest)->JsonResponse
  2995. """
  2996. 获取用户部分详细信息,如累计充值
  2997. :param request:
  2998. :return:
  2999. """
  3000. customerOpenId = request.GET.get('id')
  3001. if not customerOpenId:
  3002. return JsonErrorResponse(description=u'传入用户ID为空,无法获取详情')
  3003. ownerId = request.user.bossId
  3004. groupIds = list(set(Group.get_group_ids_of_dealer_and_partner(ownerId)))
  3005. users = MyUser.get_collection().find({"openId": customerOpenId, "groupId": {"$in": groupIds}})
  3006. rechargeTotal = RMB(0)
  3007. bestowTotal = RMB(0)
  3008. consumptionTotal = RMB(0)
  3009. balance = RMB(0)
  3010. nickname = ""
  3011. phone = ""
  3012. openId = ""
  3013. idStr = ""
  3014. breakRuleTimes = 0
  3015. orderRemindType = 2
  3016. for user in users:
  3017. nickname = user.get('nickname', "")
  3018. balance += (RMB(user.get("chargeBalance", 0)) + RMB(user.get("bestowBalance", 0)))
  3019. rechargeTotal += RMB(user.get("total_recharged", 0))
  3020. bestowTotal += RMB(user.get("total_bestow", 0))
  3021. consumptionTotal += RMB(user.get("total_consumed", 0))
  3022. openId = user.get("openId", "")
  3023. idStr = str(user.get('_id', ''))
  3024. if user.get('blacklistConfig', {}).get('orderRemindType', 2) != 2:
  3025. orderRemindType = user['blacklistConfig']['orderRemindType']
  3026. if user.get('blacklistConfig', {}).get('breakRuleTimes', 0) != 0:
  3027. breakRuleTimes = user['blacklistConfig']['breakRuleTimes']
  3028. if breakRuleTimes > 0 and orderRemindType != 0:
  3029. orderRemindType = 0
  3030. us = MyUser.objects(openId=user['openId'], groupId__in=groupIds)
  3031. for _ in us:
  3032. _.blacklistConfig['orderRemindType'] = orderRemindType
  3033. _.save()
  3034. status = "black" if check_black_user(dealerId=str(ownerId), openId=openId) else "white"
  3035. if idStr:
  3036. user = MyUser.objects.filter(id=idStr).first()
  3037. phone = user.phone
  3038. return JsonResponse({
  3039. 'result': 1,
  3040. 'description': None,
  3041. 'payload': {
  3042. 'balance': balance,
  3043. 'nickname': nickname,
  3044. 'phone': phone,
  3045. 'rechargeTotal': rechargeTotal,
  3046. 'consumptionTotal': consumptionTotal,
  3047. 'status': status,
  3048. 'breakRuleTimes': breakRuleTimes,
  3049. 'orderRemindType': orderRemindType
  3050. }
  3051. })
  3052. @error_tolerate(nil=DefaultJsonErrorResponse)
  3053. @permission_required(ROLE.dealer, ROLE.subaccount)
  3054. def getCustomerListUnderDealer(request):
  3055. """ 获取经销商名下的用户 按照openId做归并 查询需要根据特性来决定是否做手机号码查询"""
  3056. pageIndex = int(request.GET.get('pageIndex', 1))
  3057. pageSize = int(request.GET.get('pageSize', 10))
  3058. searchKey = request.GET.get('searchKey', "")
  3059. sortKey = request.GET.get('sortName', 'last_login')
  3060. sortOrder = request.GET.get('sortType', 'des')
  3061. isNew = True if request.GET.get('isNew', 'false') == 'true' else False
  3062. ownerId = request.user.bossId
  3063. groupIds = Group.get_group_ids_of_dealer_and_partner(ownerId=ownerId)
  3064. # 获取用户默认头像
  3065. default_avatar = Agent.get_agent(request.user.agentId).get("productLogo")
  3066. sortFilters = True if sortOrder == "des" else False
  3067. groupFilters = {
  3068. "_id": "$openId",
  3069. "chargeBalance": {"$sum": "$chargeBalance"},
  3070. "bestowBalance": {"$sum": "$bestowBalance"},
  3071. "total_recharged": {"$sum": "$total_recharged"},
  3072. "total_bestow": {"$sum": "$total_bestow"},
  3073. "total_consumed": {"$sum": "$total_consumed"},
  3074. "nickname": {"$first": "$nickname"},
  3075. "sex": {"$first": "$sex"},
  3076. "avatar": {"$first": "$avatar"},
  3077. "openId": {"$first": "$openId"},
  3078. "last_login": {"$max": "$last_login"}
  3079. }
  3080. matchFilters = {
  3081. "groupId": {"$in": groupIds}
  3082. }
  3083. by_phone = False
  3084. by_user_id = False
  3085. by_others = False
  3086. if re.match(r'1[3-9][0-9]{9}$', searchKey):
  3087. by_phone = True
  3088. elif re.match(r'^[0-9]{5,10}$', searchKey):
  3089. by_user_id = True
  3090. else:
  3091. by_others = True
  3092. # 符合手机号码的正则
  3093. if by_phone or by_user_id:
  3094. if by_phone:
  3095. agent = Agent.objects.filter(id = str(request.user.myBoss.agentId)).first() # type: Agent
  3096. if agent.supports('user_identify'):
  3097. user = MyUser.objects.filter(phoneNumber = searchKey).first()
  3098. else:
  3099. user = UniqueUser.objects.filter(phone = searchKey).first() # type: UniqueUser
  3100. else:
  3101. user = UniqueUser.objects.filter(userId=searchKey).first() # type: UniqueUser
  3102. if not user:
  3103. return JsonErrorResponse(description=u"未查询到该用户")
  3104. matchFilters.update({
  3105. 'openId': user.openId
  3106. })
  3107. else:
  3108. startTime = request.GET.get('startTime', None)
  3109. endTime = request.GET.get('endTime', None)
  3110. if startTime:
  3111. startDataTime = to_datetime(startTime + ' 00:00:00')
  3112. now = datetime.datetime.now()
  3113. if not endTime:
  3114. endDateTime = now + datetime.timedelta(days=1)
  3115. else:
  3116. endDateTime = to_datetime(endTime, "%Y-%m-%d")
  3117. if endDateTime > now:
  3118. endDateTime = now
  3119. endDateTime = endDateTime + datetime.timedelta(days=1)
  3120. if startDataTime >= endDateTime:
  3121. endDateTime = startDataTime + datetime.timedelta(days=1)
  3122. timeFilters = {
  3123. "$gte": startDataTime,
  3124. "$lt": endDateTime
  3125. }
  3126. if isNew:
  3127. timeKey = "dateTimeAdded"
  3128. else:
  3129. timeKey = "last_login"
  3130. matchFilters.update({
  3131. timeKey: timeFilters
  3132. })
  3133. if searchKey:
  3134. matchFilters.update({
  3135. "nickname": {"$regex": "%s" % searchKey}
  3136. })
  3137. users = MyUser.get_collection().aggregate([
  3138. {"$match": matchFilters},
  3139. {"$group": groupFilters},
  3140. ])
  3141. totalUsers = list(users)
  3142. if sortKey == "last_login":
  3143. totalUsers.sort(key=lambda x: x.get(sortKey), reverse=sortFilters)
  3144. else:
  3145. totalUsers.sort(key=lambda x: VirtualCoin(x.get(sortKey)), reverse=sortFilters)
  3146. tempUsers = totalUsers[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  3147. for user in tempUsers:
  3148. if not user["avatar"]: user["avatar"] = default_avatar
  3149. if 'total_recharged' in user:
  3150. user['total_recharged'] = RMB(user['total_recharged'])
  3151. if 'total_consumed' in user:
  3152. user['total_consumed'] = RMB(user['total_consumed'])
  3153. if 'chargeBalance' or 'bestowBalance' in user:
  3154. user["chargeBalance"] = RMB(user.get("chargeBalance", 0))
  3155. user["bestowBalance"] = RMB(user.get("bestowBalance", 0))
  3156. user['balance'] = user['chargeBalance'] + user['bestowBalance']
  3157. return JsonResponse({
  3158. "result": 1,
  3159. "description": None,
  3160. "payload": {
  3161. "total": len(totalUsers),
  3162. "dataList": tempUsers
  3163. }
  3164. })
  3165. @error_tolerate(nil=DefaultJsonErrorResponse)
  3166. @permission_required(ROLE.dealer, ROLE.subaccount)
  3167. def getRechargeRecordByCustomer(request):
  3168. # type: (WSGIRequest)->JsonResponse
  3169. """
  3170. 由用户详情 查询用户的充值记录
  3171. :param request:
  3172. :return:
  3173. """
  3174. pageIndex = int(request.GET.get("pageIndex"))
  3175. pageSize = int(request.GET.get("pageSize"))
  3176. openId = request.GET.get("id")
  3177. cardId = request.GET.get("cardTicketId") # 直接查看某一张虚拟卡的充值记录
  3178. startTime = request.GET.get('startTime', Const.QUERY_START_DATE)
  3179. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  3180. if cardId:
  3181. orderNoList = VirtualCardRechargeRecord.get_link_orderNo_list(
  3182. cardId = cardId, startTime = to_datetime(startTime, '%Y-%m-%d'), endTime = to_datetime(endTime, '%Y-%m-%d'))
  3183. queryFilter = {
  3184. 'orderNo__in': orderNoList
  3185. }
  3186. else:
  3187. queryFilter = {
  3188. 'ownerId__in': Dealer.get_cooperative_dealer_ids(str(request.user.bossId)),
  3189. "openId": openId,
  3190. "result": "success",
  3191. "via__in": map(format, [
  3192. USER_RECHARGE_TYPE.RECHARGE,
  3193. USER_RECHARGE_TYPE.RECHARGE_CARD,
  3194. USER_RECHARGE_TYPE.RECHARGE_VIRTUAL_CARD,
  3195. USER_RECHARGE_TYPE.RECHARGE_CASH,
  3196. USER_RECHARGE_TYPE.RECHARGE_MONTHLY_PACKAGE
  3197. ]),
  3198. 'hint': [("openId", 1)]
  3199. }
  3200. records = ClientRechargeModelProxy.get_data_list(startTime=startTime, endTime=endTime, **queryFilter)
  3201. dataList = list()
  3202. for record in records.paginate(pageIndex, pageSize):
  3203. _data = {
  3204. "gateway": record.gateway or 'wechat',
  3205. "createdTime": record.created_date,
  3206. "totalFee": record.money,
  3207. "gatewayTradeNo": record.wxOrderNo,
  3208. "outTradeNo": record.orderNo,
  3209. "address": record.address,
  3210. "name": record.groupName,
  3211. "groupNumber": record.groupNumber,
  3212. "devTypeName": record.dev_type_name,
  3213. "logicalCode": record.logicalCode,
  3214. "isQuickPay": record.isQuickPay,
  3215. "result": getattr(record, "result", 'success'),
  3216. "description": getattr(record, "description", ''),
  3217. "via": record.via,
  3218. "coins": record.coins
  3219. }
  3220. if "refundOrder" in request.user.features:
  3221. _data["showRefund"] = (record.is_refund_available(request.user)) and (not record.has_refund_order)
  3222. dataList.append(_data)
  3223. total = pageIndex * pageSize if len(dataList) < pageSize else (pageIndex + 1) * pageSize
  3224. return JsonResponse({'result': 1, 'description': "", 'payload': {'dataList': dataList, 'total': total}})
  3225. @error_tolerate(nil=DefaultJsonErrorResponse)
  3226. @permission_required(ROLE.dealer, ROLE.subaccount)
  3227. def getConsumptionRecordByCustomer(request):
  3228. # type: (WSGIRequest)->JsonResponse
  3229. """
  3230. :param request:
  3231. :return:
  3232. """
  3233. pageIndex = int(request.GET.get("pageIndex", 1))
  3234. pageSize = int(request.GET.get("pageSize", 10))
  3235. openId = request.GET.get("id")
  3236. groupId = request.GET.get("groupId")
  3237. lastYear = datetime.date((datetime.date.today().year - 1), datetime.date.today().month,
  3238. datetime.date.today().day).strftime("%Y-%m-%d")
  3239. startTime = request.GET.get('startTime', lastYear)
  3240. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  3241. queryFilter = {"ownerId": str(request.user.bossId), "openId": openId}
  3242. if groupId:
  3243. queryFilter.update({"groupId": groupId})
  3244. records = ClientConsumeModelProxy.get_data_list(startTime=startTime, endTime=endTime, **queryFilter)
  3245. # 修改 列表仅仅展示基础数据 详细信息在详单中查询
  3246. dataList = []
  3247. for record in records.paginate(pageIndex, pageSize):
  3248. newData = {
  3249. "groupName": record.groupName,
  3250. "groupNumber": record.groupNumber,
  3251. "devTypeName": record.devTypeName,
  3252. "logicalCode": record.logicalCode,
  3253. "createdTime": record.dateTimeAdded,
  3254. "orderNo": record.orderNo,
  3255. "id": str(record.id),
  3256. "ownerId": record.ownerId
  3257. }
  3258. newData.update(record.service)
  3259. dev = Device.get_dev_by_logicalCode(record.logicalCode) # type: DeviceDict
  3260. if dev and dev.is_registered and dev.ownerId == record.ownerId:
  3261. if (record.devTypeCode or dev.devTypeCode) == Const.DEVICE_TYPE_CODE_HP_GATE: # 霍珀道闸分支
  3262. newData.update({'desc': record.servicedInfo.get('oper', u'未知')})
  3263. elif record.devTypeCode in support_policy_weifule + support_policy_device:
  3264. if record.status != ConsumeRecord.Status.FINISHED:
  3265. if (datetime.datetime.now() - record.dateTimeAdded).total_seconds() > 60 * 60 * 12:
  3266. newData.update({'desc': '超12小时未结束'})
  3267. if record.status == ConsumeRecord.Status.RUNNING:
  3268. newData.update({'showStopButton': True})
  3269. if record.status == ConsumeRecord.Status.END:
  3270. newData.update({'showStopButton': True})
  3271. else:
  3272. continue
  3273. dataList.append(newData)
  3274. total = pageIndex * pageSize if len(dataList) < pageSize else (pageIndex + 1) * pageSize
  3275. return JsonResponse({'result': 1, 'description': "", 'payload': {'dataList': dataList, 'total': total}})
  3276. @error_tolerate(nil=DefaultJsonErrorResponse)
  3277. @permission_required(ROLE.dealer, ROLE.subaccount)
  3278. def modifyCustomerBalance(request):
  3279. # type: (WSGIRequest)->JsonResponse
  3280. """
  3281. 给终端用户派币或扣币(通常情况不支持)
  3282. :param request:
  3283. :return:
  3284. """
  3285. currentDealer = request.user.myBoss # type: Optional[Dealer]
  3286. agent = Agent.objects.filter(id=str(currentDealer.agentId)).first() # type: Agent
  3287. if 'disable_dealer_onPoints_and_sendCoins' in agent.features:
  3288. return JsonResponse(
  3289. {'result': 0, 'description': '设备无法使用该功能奥, 如有问题, 请联系代理商', 'payload': {}})
  3290. payload = json.loads(request.body) if request.body else {}
  3291. if not payload: return JsonErrorResponse(description=u'传入数据为空')
  3292. coins = VirtualCoin(payload.get('coins', 0.0))
  3293. desc = payload.get('description')
  3294. customerOpenId = payload.get('userId')
  3295. groupId = payload.get('groupId')
  3296. ownerId = str(currentDealer.bossId)
  3297. operator = currentDealer.nickname
  3298. customer = MyUser.objects(groupId=groupId, openId=customerOpenId).first() # type: Optional[MyUser]
  3299. if not customer:
  3300. return JsonResponse({'result': 0, 'description': u'该用户不存在', 'payload': {}})
  3301. if coins < VirtualCoin(0) and -coins > customer.balance:
  3302. return JsonResponse({'result': 0, 'description': u'最多只能扣除掉%s个币' % customer.balance, 'payload': {}})
  3303. agent = Agent.objects.get(id=currentDealer.agentId)
  3304. if 'coinIsMoney' in agent.features:
  3305. return JsonResponse({'result': 0, 'description': u'代理商的配置,不允许给用户派币', 'payload': {}})
  3306. group = Group.get_group(groupId)
  3307. if group['ownerId'] != ownerId:
  3308. return JsonResponse({'result': 0, 'description': u'不是您家设备喔,不能派币', 'payload': {}})
  3309. payload = {
  3310. 'orderNo': str(uuid.uuid1()),
  3311. 'openId': customerOpenId,
  3312. 'coins': coins,
  3313. 'description': desc,
  3314. 'groupId': groupId,
  3315. 'groupName': group.groupName,
  3316. 'address': group.address,
  3317. 'ownerId': ownerId,
  3318. 'operator': operator,
  3319. 'result': 'success',
  3320. 'via': 'sendcoin'
  3321. }
  3322. record = RechargeRecord(**payload)
  3323. customer.recharge(RMB(0), RMB(coins))
  3324. record.save()
  3325. customer.account_recharge(record)
  3326. if coins > VirtualCoin(0):
  3327. try:
  3328. task_caller(
  3329. 'report_to_user_via_wechat', openId=customerOpenId,
  3330. dealerId=str(request.user.bossId),
  3331. templateName='refund_coins', **{
  3332. 'title': u'尊敬的客户,已经退回%s金币到您的余额,您下次可以接着使用。祝您生活愉快。' % coins,
  3333. 'backCount': u'金币:%s' % coins,
  3334. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  3335. }
  3336. )
  3337. except Exception as e:
  3338. logger.exception(e)
  3339. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  3340. @error_tolerate(nil=DefaultJsonErrorResponse)
  3341. @permission_required(ROLE.dealer, ROLE.subaccount)
  3342. def getModifyCustomerBalanceRecord(request):
  3343. # type: (WSGIRequest)->JsonResponse
  3344. """
  3345. 获取派币记录
  3346. :param request:
  3347. :return:
  3348. """
  3349. pageIndex = int(request.GET.get('pageIndex', 1))
  3350. pageSize = int(request.GET.get('pageSize', 10))
  3351. customerOpenId = request.GET.get('id', None)
  3352. user = MyUser.objects(openId=customerOpenId).first()
  3353. if not user:
  3354. records = RechargeRecord.objects(
  3355. ownerId=str(request.user.bossId),
  3356. via='sendcoin').order_by('-dateTimeAdded').skip((pageIndex - 1) * pageSize).limit(pageSize)
  3357. else:
  3358. records = RechargeRecord.objects(
  3359. ownerId=str(request.user.bossId),
  3360. openId=customerOpenId,
  3361. via='sendcoin').order_by('-dateTimeAdded').skip((pageIndex - 1) * pageSize).limit(pageSize)
  3362. dataList = []
  3363. if not user:
  3364. for r in records:
  3365. u = MyUser.objects(openId=r.openId).first()
  3366. if u is None:
  3367. logger.error('invalid openId, openId=%s' % r.openId)
  3368. continue
  3369. dataList.append({
  3370. 'name': u.nickname if u.nickname is not None else '',
  3371. 'avatar': u.avatar,
  3372. 'id': customerOpenId,
  3373. 'remarks': r.my_description,
  3374. 'operator': r.operator,
  3375. 'coins': r.coins,
  3376. 'groupName': r.groupName,
  3377. 'createdTime': r.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  3378. })
  3379. else:
  3380. dataList = [
  3381. {
  3382. 'name': user.nickname if user.nickname is not None else '',
  3383. 'avatar': user.avatar,
  3384. 'id': customerOpenId,
  3385. 'remarks': r.my_description,
  3386. 'operator': r.operator,
  3387. 'coins': r.coins,
  3388. 'groupName': r.groupName,
  3389. 'createdTime': r.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  3390. } for r in records
  3391. ]
  3392. count = records.count()
  3393. if count <= pageSize:
  3394. total = (pageIndex - 1) * pageSize + count
  3395. else:
  3396. total = (pageIndex - 1) * pageSize + 100
  3397. return JsonResponse(
  3398. {
  3399. 'result': 1,
  3400. 'description': None,
  3401. 'payload':
  3402. {
  3403. 'dataList': paginate(dataList, pageIndex, pageSize),
  3404. 'total': total,
  3405. 'sendCoinsTotal': VirtualCoin(records.sum('coins'))
  3406. }
  3407. }
  3408. )
  3409. # 导出派币记录
  3410. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取派币记录失败"))
  3411. @permission_required(ROLE.dealer)
  3412. def reportModifyCustomerBalanceRecord(request):
  3413. """
  3414. 导出派币记录
  3415. """
  3416. dealer = request.user
  3417. def get_offline_task_name(task_type, user, **kwargs):
  3418. # type: (basestring, Dealer, Dict)->basestring
  3419. tmp_list = [task_type, user.username]
  3420. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  3421. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  3422. if 'groupId' in kwargs and kwargs['groupId']:
  3423. address = Group.get_group(kwargs['groupId']).get('address', '')
  3424. tmp_list.append(u'地址_%s' % (address,))
  3425. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  3426. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  3427. return '-'.join(tmp_list).replace("/", "_")
  3428. query_dict = {
  3429. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  3430. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  3431. 'pageIndex': int(request.GET.get('pageIndex', 1)),
  3432. 'pageSize': int(request.GET.get('pageSize', 10)),
  3433. 'customerOpenId': request.GET.get('id', None),
  3434. "ownerId": str(request.user.bossId),
  3435. }
  3436. offline_task_name = get_offline_task_name(
  3437. task_type=u'地址用户充值消费情况统计报表',
  3438. user=dealer,
  3439. **query_dict)
  3440. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  3441. process_func_name='export_modify_customer_balance_record_excel_from_db',
  3442. task_type=OfflineTaskType.BUSINESS_REPORT,
  3443. userid=str(dealer.id),
  3444. role=ROLE.dealer)
  3445. task_caller(func_name=offline_task.process_func_name,
  3446. offline_task_id=str(offline_task.id),
  3447. filepath=file_path,
  3448. queryDict=query_dict)
  3449. return JsonResponse({
  3450. 'result': 1,
  3451. 'description': u"请前往离线任务查看任务处理情况",
  3452. 'payload': str(offline_task.id)})
  3453. @error_tolerate(nil=DefaultJsonErrorResponse)
  3454. @permission_required(ROLE.dealer, ROLE.subaccount)
  3455. def getRefundRecord(request):
  3456. # type: (WSGIRequest)->JsonResponse
  3457. """
  3458. 获取退币记录
  3459. :param request:
  3460. :return:
  3461. """
  3462. pageIndex = int(request.GET.get('pageIndex', 1))
  3463. pageSize = int(request.GET.get('pageSize', 10))
  3464. customerOpenId = request.GET.get('id', None)
  3465. if not customerOpenId:
  3466. return JsonErrorResponse(description=u'提交的用户id为空')
  3467. user = MyUser.objects(openId=customerOpenId).first().to_dict()
  3468. records = RechargeRecord.objects(ownerId=str(request.user.bossId), openId=customerOpenId, via='refund').order_by("-dateTimeAdded")
  3469. dealer = Dealer.objects(id=str(request.user.bossId)).get()
  3470. dataList = [
  3471. {
  3472. 'name': user['nickname'],
  3473. 'avatar': user['avatar'],
  3474. 'id': customerOpenId,
  3475. 'description': r.my_description,
  3476. 'operator': dealer.nickname,
  3477. 'coins': r.coins,
  3478. 'groupName': r.groupName,
  3479. 'createdTime': r.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  3480. } for r in records
  3481. ]
  3482. total = records.count()
  3483. return JsonResponse(
  3484. {
  3485. 'result': 1,
  3486. 'description': None,
  3487. 'payload':
  3488. {
  3489. 'dataList': paginate(dataList, pageIndex, pageSize),
  3490. 'total': total,
  3491. 'refundTotal': VirtualCoin(records.sum('coins'))
  3492. }
  3493. }
  3494. )
  3495. @error_tolerate(nil=DefaultJsonErrorResponse)
  3496. @permission_required(ROLE.dealer, ROLE.subaccount)
  3497. def payGateway(request):
  3498. # type: (WSGIRequest)->JsonResponse
  3499. current_user = request.user # type: Dealer
  3500. try:
  3501. # TODO # 此处流量卡传的是param 其他 加盟 api支付的都是传 params
  3502. payload = json.loads(request.GET.get('param') or request.GET.get('params'))
  3503. order_no = payload.get('orderNo')
  3504. if not order_no:
  3505. return JsonErrorResponse(u'参数错误,请刷新后再试')
  3506. record = DealerRechargeRecord.objects(orderNo=order_no).first() # type: DealerRechargeRecord
  3507. if not record:
  3508. return JsonErrorResponse(u'订单不存在,请刷新后再试')
  3509. payment_gateway = PaymentGateway.from_gateway_key(
  3510. record.gateway,
  3511. record.payGatewayKey,
  3512. record.payAppType) # type: Optional[WechatPaymentGateway, DlbPaymentGateway, SaobeiPaymentGateway, JDAggrePaymentGateway]
  3513. logger.info('dealer wechat charge: gateway = %s; orderNo = %s, totalFee = %s' % (
  3514. repr(payment_gateway), order_no, record.totalFee))
  3515. OrderCacheMgr(record).initial()
  3516. attach = {'dealerId': record.dealerId}
  3517. body = record.get_body()
  3518. # 转成以元为单位的钱,后面流程统一处理
  3519. money = RMB(record.totalFee) * Decimal('0.01')
  3520. if payment_gateway.pay_app_type == PayAppType.WECHAT:
  3521. data = payment_gateway.generate_js_payment_params(
  3522. payOpenId=payload.get('openId'),
  3523. out_trade_no=order_no,
  3524. notify_url=PAY_NOTIFY_URL.WECHAT_PAY_BACK,
  3525. money=money,
  3526. body=body,
  3527. attach=attach)
  3528. data.update({
  3529. 'outTradeNo': record.orderNo, 'adShow': current_user.ad_show
  3530. })
  3531. response = JsonResponse({'result': 1, 'description': '', 'payload': data})
  3532. else:
  3533. raise Exception(cn(u'不支持该支付类型'))
  3534. task_caller(func_name='poll_dealer_recharge_record',
  3535. delay=PollRecordDefine.DELAY_BEFORE,
  3536. expires=PollRecordDefine.TASK_EXPIRES,
  3537. record_id=str(record.id),
  3538. pay_app_type=payment_gateway.pay_app_type,
  3539. interval=PollRecordDefine.WAIT_EACH_ROUND,
  3540. total_count=PollRecordDefine.TOTAL_ROUNDS)
  3541. return response
  3542. except WeChatException as e:
  3543. logger.exception(e)
  3544. return JsonErrorResponse(description = e.tip)
  3545. except SaobeiException as e:
  3546. logger.exception(e)
  3547. return JsonErrorResponse(description = e.tip)
  3548. except Exception as e:
  3549. logger.exception(e)
  3550. return JsonErrorResponse(description=u'系统开小差了,请刷新后再试')
  3551. @error_tolerate(nil=DefaultJsonErrorResponse)
  3552. @permission_required(ROLE.dealer, ROLE.subaccount)
  3553. def getDeviceCardList(request):
  3554. # type: (WSGIRequest)->JsonResponse
  3555. def cmp_expire_time(x, y):
  3556. if not x['simExpireDate']:
  3557. return 1
  3558. if not y['simExpireDate']:
  3559. return -1
  3560. if x['simExpireDate'] > y['simExpireDate']:
  3561. return -1
  3562. elif x['simExpireDate'] < y['simExpireDate']:
  3563. return 1
  3564. else:
  3565. return 0
  3566. searchKey = request.GET.get('searchKey', '')
  3567. dealerId = str(request.user.bossId)
  3568. agent = Agent.objects(id=request.user.agentId).first() # type: Optional[Agent]
  3569. if not agent:
  3570. logger.error('agent<id={}> is not exist.'.format(request.user.agentId))
  3571. return JsonErrorResponse(description=u'系统错误')
  3572. groupIds = Group.get_group_ids_of_dealer(dealerId)
  3573. groupDict = Group.get_groups_by_group_ids(groupIds)
  3574. devNoList = Device.get_devNos_by_group(groupIds)
  3575. devices = Device.get_dev_by_nos(devNoList).values()
  3576. annualTrafficCost = request.user.annualTrafficCost
  3577. devList = []
  3578. for dev in devices: # type: DeviceDict
  3579. try:
  3580. if searchKey in dev['groupNumber'] or searchKey in dev.devNo or searchKey in dev[
  3581. 'remarks'] or searchKey in dev.logicalCode:
  3582. group = groupDict.get(dev.groupId)
  3583. if (settings.DEBUG and dev.logicalCode.startswith('DUMMY')) or dev.is_expired or dev.sim_expire_notify:
  3584. item = {
  3585. 'logicalCode': dev.logicalCode,
  3586. 'devNo': dev.devNo,
  3587. 'devTypeName': dev.devType['name'],
  3588. 'groupName': group['groupName'],
  3589. 'groupNumber': dev['groupNumber'],
  3590. 'groupId': group['groupId'],
  3591. 'simExpireDate': dev.fixedSimExpireDate,
  3592. 'channelType': dev.channelType
  3593. }
  3594. devList.append(item)
  3595. except Exception, e:
  3596. logger.exception('[device]some error=%s' % e)
  3597. continue
  3598. devList.sort(cmp=cmp_expire_time)
  3599. pageIndex = int(request.GET.get('pageIndex', 1))
  3600. pageSize = int(request.GET.get('pageSize', 100))
  3601. items = devList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  3602. devObjs = { obj.devNo: obj for obj in Device.objects.filter(devNo__in=[item['devNo'] for item in items])}
  3603. for item in items:
  3604. dev_obj = devObjs[item['devNo']] # type: Device
  3605. trafficCardCost = dev_obj.trafficCardCost
  3606. if not trafficCardCost:
  3607. if request.user.trafficCardCost:
  3608. trafficCardCost = request.user.trafficCardCost
  3609. else:
  3610. trafficCardCost = agent.trafficCardCost
  3611. item['price'] = trafficCardCost if trafficCardCost > annualTrafficCost else annualTrafficCost
  3612. items = sorted(items, key=lambda x:x['groupId'])
  3613. return JsonResponse({
  3614. 'result': 1,
  3615. 'description': None,
  3616. 'payload': {'page': pageIndex, 'total': len(devList), 'pageSize': pageSize, 'offset': 0,
  3617. 'items': items}
  3618. })
  3619. @error_tolerate(nil=DefaultJsonErrorResponse)
  3620. @permission_required(ROLE.dealer, ROLE.subaccount)
  3621. def getSimRechargeOrderList(request):
  3622. # type: (WSGIRequest)->JsonResponse
  3623. filterQuery = Q(
  3624. __raw__ = {
  3625. 'dealerId': str(request.user.bossId),
  3626. 'product': {'$in': [DealerRechargeRecord.ProductType.SimCard, DealerRechargeRecord.ProductType.AutoSimCard]}
  3627. })
  3628. status = request.GET.get('status', None)
  3629. if status:
  3630. filterQuery &= Q(__raw__={'status': status})
  3631. else:
  3632. filterQuery &= Q(
  3633. __raw__={'status': {'$nin': [DealerRechargeRecord.PayState.Cancel, DealerRechargeRecord.PayState.Close]}})
  3634. searchKey = request.GET.get('searchKey', '')
  3635. if searchKey:
  3636. pattern = Regex.from_native(re.compile('.*' + searchKey + '.*'))
  3637. filterQuery &= (Q(__raw__={'items': {'$elemMatch': {'name': {'$regex': pattern}}}}) | Q(
  3638. __raw__={'orderNo': {"$regex": pattern}}))
  3639. records = DealerRechargeRecord.objects(
  3640. __raw__=filterQuery.to_query(DealerRechargeRecord)).order_by("-createdTime")
  3641. items = []
  3642. for record in records: # type: DealerRechargeRecord
  3643. item = {
  3644. 'name': record.name,
  3645. 'totalFee': str(RMB(float(record['totalFee']) / 100)),
  3646. 'orderNo': record.orderNo,
  3647. 'status': record.status,
  3648. 'createdTime': record.createdTime,
  3649. 'finishedTime': record.finishedTime
  3650. }
  3651. items.append(item)
  3652. pageIndex = int(request.GET.get('pageIndex', 1))
  3653. pageSize = int(request.GET.get('pageSize', 10))
  3654. return JsonResponse({
  3655. 'result': 1,
  3656. 'description': '',
  3657. 'payload': {
  3658. 'page': pageIndex, 'total': len(items), 'pageSize': pageSize, 'offset': 0,
  3659. 'items': items[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  3660. }
  3661. })
  3662. @error_tolerate(nil=DefaultJsonErrorResponse)
  3663. @permission_required(ROLE.dealer, ROLE.subaccount)
  3664. def createSimRechargeOrder(request):
  3665. # type: (WSGIRequest)->JsonResponse
  3666. current_user = request.user # type: Dealer
  3667. devNoList = set(request.POST.getlist('list[]'))
  3668. payment_gateway = get_inhourse_wechat_env_pay_gateway(
  3669. ROLE.dealer) # type: Union[WechatPaymentGateway, JDAggrePaymentGateway]
  3670. record = create_dealer_sim_charge_order(payment_gateway, current_user, devNoList)
  3671. if record:
  3672. return JsonResponse({'result': 1, 'description': u'创建订单成功', 'payload': record.orderNo})
  3673. else:
  3674. return JsonErrorResponse(u'创建订单异常失败')
  3675. @error_tolerate(nil=DefaultJsonErrorResponse)
  3676. @permission_required(ROLE.dealer, ROLE.subaccount)
  3677. def cancelSimRechargeOrder(request):
  3678. # type: (WSGIRequest)->JsonResponse
  3679. try:
  3680. payload = json.loads(request.body) if request.body else {}
  3681. if not payload:
  3682. return JsonErrorResponse(description=u'数据不完整,请重试')
  3683. order_no = payload['orderNo']
  3684. order = DealerRechargeRecord.objects(orderNo=order_no).first() # type: DealerRechargeRecord
  3685. if not order:
  3686. return JsonErrorResponse(u'订单不存在,请刷新后再试')
  3687. if not order.is_unpay():
  3688. return JsonErrorResponse(u'订单已经处理,无法取消')
  3689. if order.cancel():
  3690. return JsonOkResponse('ok')
  3691. else:
  3692. return JsonErrorResponse(u'订单已经处理,无法取消')
  3693. except Exception as e:
  3694. logger.exception('unable to cancel dealer order, error=%s' % (e,))
  3695. return JsonErrorResponse(description=u"系统错误")
  3696. @error_tolerate(nil=DefaultJsonErrorResponse)
  3697. @permission_required(ROLE.dealer, ROLE.subaccount)
  3698. def getSimRechargeOrderDetail(request):
  3699. # type: (WSGIRequest)->JsonResponse
  3700. try:
  3701. orderNo = request.GET.get('orderNo')
  3702. order = DealerRechargeRecord.objects(orderNo = orderNo).first() # type: DealerRechargeRecord
  3703. if not order:
  3704. return JsonErrorResponse(u'订单不存在,请刷新后再试')
  3705. else:
  3706. return JsonResponse({'result': 1, 'description': '', 'payload':
  3707. {
  3708. 'orderNo': order.orderNo,
  3709. 'totalFee': '%.02f' % (float(order.totalFee) / 100),
  3710. 'status': order.status,
  3711. 'createdTime': order.createdTime,
  3712. 'items': order.items
  3713. }})
  3714. except Exception as e:
  3715. logger.exception('get dealer pay order list failure, error = %s' % (e,))
  3716. return JsonErrorResponse(description = u'查询订单失败')
  3717. @error_tolerate(nil=DefaultJsonErrorResponse)
  3718. def getOwnerAgents(request):
  3719. try:
  3720. username = request.GET.get('username')
  3721. managerId = request.GET.get('managerId')
  3722. logger.debug('getOwnerAgents: username = %s; managerId = %s' % (username, managerId))
  3723. agents = [str(a.id) for a in Agent.objects(managerId=str(managerId)).all()]
  3724. items = []
  3725. dealers = Dealer.get_collection().find({'username': username, 'agentId': {'$in': agents}})
  3726. for dealer in dealers:
  3727. agentId = dealer['agentId']
  3728. agent = Agent.get_agent(agentId)
  3729. item = {
  3730. 'agentId': agentId,
  3731. 'userHeadImg': agent['avatar'],
  3732. 'agentLogoUrl': agent['productLogo'],
  3733. 'agentBrandName': agent['productName'],
  3734. 'displayName': agent['productName']
  3735. }
  3736. items.append(item)
  3737. return JsonResponse({
  3738. 'result': 1,
  3739. 'description': None,
  3740. 'payload': {'total': len(items),
  3741. 'items': items}
  3742. })
  3743. except Exception as e:
  3744. logger.exception('get dealer owner agents failure, error = %s' % (e,))
  3745. return JsonErrorResponse(description=u'网络错误,请刷新后再试')
  3746. @error_tolerate(nil=DefaultJsonErrorResponse)
  3747. @permission_required(ROLE.dealer, ROLE.subaccount)
  3748. def getEquipmentTotal(request):
  3749. # type: (WSGIRequest)->JsonResponse
  3750. dealerId = str(request.user.bossId)
  3751. groupIds = Group.get_group_ids_of_dealer(dealerId)
  3752. devNoList = Device.get_devNos_by_group(groupIds)
  3753. return JsonResponse({'result': 1, 'description': '', 'payload': len(devNoList)})
  3754. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'设备类型不支持'))
  3755. @permission_required(ROLE.dealer, ROLE.subaccount)
  3756. def getPackageList(request):
  3757. # type: (WSGIRequest)->JsonResponse
  3758. devTypeId = request.GET.get('typeId', None)
  3759. if not devTypeId:
  3760. return JsonResponse({'result': 0, 'description': u'设备类型为空', 'payload': {}})
  3761. dealer = request.user.myBoss # type: Dealer
  3762. devType = DeviceType.objects.filter(id=str(devTypeId)).first() # type: DeviceType
  3763. if devType['code'] in support_policy_weifule + support_policy_device:
  3764. isTemp = request.GET.get('isTemp', None) == 'true'
  3765. from apps.web.core.models import DriverAdapter
  3766. adapter = DriverAdapter.get_driver_adapter(devType['code'], None)
  3767. if adapter.support_device_package:
  3768. payload = adapter.get_reg_model(dealer, devTypeId, isTemp=isTemp)
  3769. return JsonResponse({'result': 1, 'description': None, 'payload': payload})
  3770. dataList = {}
  3771. if devTypeId in dealer.defaultWashConfig:
  3772. dataList = dealer.defaultWashConfig[devTypeId]
  3773. if not dataList:
  3774. dataList = DeviceType.objects(id=str(devTypeId)).get().package
  3775. no_unit_list = filter(lambda x: x.get("unit") == None, dataList)
  3776. if len(no_unit_list) == len(dataList):
  3777. datalist = map(lambda x: (x.update({"unit": "分钟"}), x)[1], dataList)
  3778. displaySwitchs = {}
  3779. if hasattr(devType, "displayPriceSwitch"):
  3780. displaySwitchs.update({"displayPriceSwitch": devType.displayPriceSwitch})
  3781. if hasattr(devType, "displayCoinsSwitch"):
  3782. displaySwitchs.update({"displayCoinsSwitch": devType.displayCoinsSwitch})
  3783. if hasattr(devType, "displayTimeSwitch"):
  3784. displaySwitchs.update({"displayTimeSwitch": devType.displayTimeSwitch})
  3785. if hasattr(devType, "setPulseAble"):
  3786. displaySwitchs.update({"setPulseAble": devType.setPulseAble})
  3787. if hasattr(devType, "setBasePriceAble"):
  3788. displaySwitchs.update({"setBasePriceAble": devType.setBasePriceAble})
  3789. if devType['code'] in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG]:
  3790. displaySwitchs = {
  3791. 'displayPriceSwitch': True,
  3792. 'displayCoinsSwitch': False,
  3793. 'displayTimeSwitch': False,
  3794. 'setPulseAble': False,
  3795. 'setBasePriceAble': False,
  3796. }
  3797. return JsonResponse({'result': 1, 'description': None, 'payload': {'ruleList':dataList, 'displaySwitchs':displaySwitchs}})
  3798. # ## 经销商绑定微信(为了接受微信推送)
  3799. @permission_required(ROLE.dealer, ROLE.subaccount)
  3800. def getDealerBindWechatSMSCode(request):
  3801. # type: (WSGIRequest)->JsonResponse
  3802. """
  3803. :param request:
  3804. :return:
  3805. """
  3806. try:
  3807. phoneNumber = request.user.username
  3808. agent = Agent.get_agent(request.user.agentId)
  3809. productName = agent['productName']
  3810. if not phoneNumber:
  3811. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  3812. status, msg = dealerBindWechatSMSProvider.get(phoneNumber=phoneNumber,
  3813. productName=productName,
  3814. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  3815. if not status:
  3816. return JsonResponse({'result': 0, 'description': msg})
  3817. else:
  3818. return JsonResponse({'result': 1, 'description': ''})
  3819. except Exception, e:
  3820. logger.exception('unable to get %s' % e)
  3821. return JsonResponse({'result': 0, 'description': ''})
  3822. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误'))
  3823. @permission_required(ROLE.dealer, ROLE.subaccount)
  3824. def verifyNewWechatBinding(request):
  3825. # type: (WSGIRequest)->JsonResponse
  3826. """
  3827. 跳转到微信授权页面绑定
  3828. :param request:
  3829. :return:
  3830. """
  3831. currentDealer = request.user # type: cast(Dealer)
  3832. code = request.POST.get('code')
  3833. if not code:
  3834. return JsonErrorResponse(description=u'code未提供')
  3835. status, msg = dealerBindWechatSMSProvider.verify(phoneNumber=request.user.username, smsCode=code)
  3836. if not status:
  3837. return JsonErrorResponse(description=msg)
  3838. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_MANAGER)
  3839. return JsonResponse(
  3840. {
  3841. 'result': 1,
  3842. 'description': None,
  3843. 'payload': {
  3844. 'redirect_uri': auth_bridge.generate_auth_url_user_scope(
  3845. redirect_uri=DEALER_BIND_WECHAT_URL)
  3846. }
  3847. })
  3848. @error_tolerate(logger=logger, nil=DealerBindIdResponseRedirect(result='error'))
  3849. @permission_required(ROLE.dealer, ROLE.subaccount)
  3850. def verifyNewWechatBindingCallback(request):
  3851. # type: (WSGIRequest)->JsonResponse
  3852. """
  3853. 绑定后台openId
  3854. TODO: 加入变更记录
  3855. :param request:
  3856. :return:
  3857. """
  3858. auth_code = request.GET.get('code')
  3859. if not auth_code:
  3860. return JsonErrorResponse(description=u'未收到code,请刷新重试')
  3861. currentDealer = request.user # type: cast(Dealer)
  3862. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_MANAGER)
  3863. user_info = auth_bridge.get_user_info(auth_code=auth_code)
  3864. user_info_payload = {
  3865. 'avatar': user_info['avatar'],
  3866. 'country': user_info['country'],
  3867. 'province': user_info['province'],
  3868. 'city': user_info['city'],
  3869. 'sex': user_info['sex'],
  3870. 'nickname': user_info['nickname']
  3871. }
  3872. logger.debug('dealer(id=%s) is binding wechat for messaging, bridge=%s' % (str(request.user.bossId), auth_bridge))
  3873. dealerWechatBindingUpdated = request.user.update(
  3874. managerialAppId=auth_bridge.app.appid,
  3875. managerialOpenId=user_info['openId'],
  3876. wechatAuthUserInfo=user_info_payload,
  3877. managerialWechatBoundTime=datetime.datetime.now())
  3878. if dealerWechatBindingUpdated:
  3879. return DealerBindIdResponseRedirect(result='ok')
  3880. else:
  3881. return DealerBindIdResponseRedirect(result='error')
  3882. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误'))
  3883. @permission_required(ROLE.dealer, ROLE.subaccount)
  3884. def getBoundWechat(request):
  3885. # type: (WSGIRequest)->JsonResponse
  3886. """
  3887. 获取绑定后台openId的用户信息
  3888. :param request:
  3889. :return:
  3890. """
  3891. ownerId = str(request.user.bossId)
  3892. dealer = Dealer.objects(id=ownerId).get() # type: Dealer
  3893. return JsonResponse(
  3894. {
  3895. "result": 1,
  3896. "description": None,
  3897. 'payload': {
  3898. "bound": dealer.isManagerialOpenIdBound,
  3899. "avatar": dealer.wechatAuthUserInfo.get('avatar'),
  3900. "sex": dealer.wechatAuthUserInfo.get('sex'),
  3901. "nickname": dealer.wechatAuthUserInfo.get('nickname')
  3902. }
  3903. })
  3904. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  3905. def setAdShow(request):
  3906. # type: (WSGIRequest)->JsonResponse
  3907. try:
  3908. payload = json.loads(request.body) if request.body else {}
  3909. if not payload:
  3910. return JsonErrorResponse(description=u'数据不完整,请重试')
  3911. user = Dealer.objects.get(id=payload['id']) if 'id' in payload else request.user # type: Dealer
  3912. adShow = payload.get('adShow', user.adShow)
  3913. user.adShow = adShow
  3914. user.save()
  3915. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  3916. except DoesNotExist, e:
  3917. logger.exception("dealer does not exist, error = %s" % e)
  3918. return JsonResponse({"result": 0, "description": u'经销商不存在', 'payload': {}})
  3919. except Exception, e:
  3920. logger.exception("set adShow error = %s" % e)
  3921. return JsonResponse({"result": 0, "description": u'系统错误', 'payload': {}})
  3922. @permission_required(ROLE.manager)
  3923. def getDealerDetailList(request):
  3924. # type: (WSGIRequest)->JsonResponse
  3925. """
  3926. 厂商获取经销商详情
  3927. :param request:
  3928. :return:
  3929. """
  3930. def count_devices(ownerId):
  3931. devNoList = [device['devNo'] for device in
  3932. Device.get_collection().find({'ownerId': ownerId, 'groupId': {'$ne': ''}}, {'devNo': 1, '_id': 0})]
  3933. allCount = len(devNoList)
  3934. devDict = Device.get_dev_by_nos(devNoList)
  3935. if not devDict:
  3936. return 0, 0, 0
  3937. onlineCount = 0
  3938. for devNo, dev in devDict.items():
  3939. if dev["online"]:
  3940. onlineCount += 1
  3941. offlineCount = allCount - onlineCount
  3942. return onlineCount, offlineCount, allCount
  3943. mid = str(request.user.id)
  3944. pageIndex = int(request.GET.get('pageIndex', 1))
  3945. pageSize = int(request.GET.get('pageSize', 10))
  3946. agentId = request.GET.get('agentId', None)
  3947. searchKey = request.GET.get('searchKey', None)
  3948. dealers = Dealer.search(searchKey)
  3949. agentMap = {str(agent.id): agent.username for agent in Agent.objects(managerId=mid)}
  3950. agentIds = agentMap.keys()
  3951. if agentId:
  3952. dealers = dealers.filter(agentId=agentId)
  3953. elif agentIds:
  3954. dealers = dealers.filter(agentId__in=agentIds)
  3955. total = dealers.count()
  3956. dealers_per_page = dealers.skip((pageIndex - 1) * pageSize).limit(pageSize)
  3957. dataList = []
  3958. for d in dealers_per_page:
  3959. report = Accounting.getOwnerIncome(str(d.id), now=datetime.datetime.now())
  3960. onlineCount, offlineCount, allCount = count_devices(str(d.id))
  3961. hasZJFirePlatform = True
  3962. ZJFirePlatform = {}
  3963. try:
  3964. obj = Company.objects.get(ownerId=str(d.id))
  3965. ZJFirePlatform = {
  3966. 'companyName': obj.name,
  3967. 'companyCode': obj.code,
  3968. 'companyAddress': obj.address,
  3969. 'contactsName': obj.contactName,
  3970. 'contactsTel': obj.telephone,
  3971. 'deviceManufacturer': obj.manufacturer
  3972. }
  3973. hasZJFirePlatform = True
  3974. except Exception, e:
  3975. pass
  3976. now = datetime.datetime.now()
  3977. today = now.strftime(Const.DATE_FMT)
  3978. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(d.id), 'date':today}, {'daily':1, 'activedDevRatio':1})
  3979. if rcds.count() == 0:
  3980. todayIncome = 0
  3981. todayRechargeIncome = 0
  3982. todayChargeCardIncome = 0
  3983. else:
  3984. info = rcds[0]
  3985. todayIncome = info.get('daily', {}).get('totalIncome', 0)
  3986. income = info.get('daily', {}).get('income', {})
  3987. todayRechargeIncome = income.get('recharge', 0)
  3988. todayChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('virtualChargeCard', 0))
  3989. monthDay = MONTH_DATE_KEY.format(year=now.year, month=now.month)
  3990. rcds = DealerMonthlyStat.get_collection().find({'dealerId':ObjectId(d.id), 'date':monthDay}, {'addedUserCount':1})
  3991. if rcds.count() == 0:
  3992. userCountAddedThisMonth = 0
  3993. else:
  3994. info = rcds[0]
  3995. userCountAddedThisMonth = rcds[0].get('addedUserCount', 0)
  3996. detail = d.to_dict()
  3997. dataList.append({
  3998. 'id': str(d.id),
  3999. 'name': d.nickname,
  4000. 'tel': d.username,
  4001. 'agentInfo': agentMap.get(detail['agentId'], ''),
  4002. 'dateTimeAdded': d.dateTimeAdded,
  4003. 'lineCoins': report['lineCoins'],
  4004. 'payIncome': todayIncome,
  4005. 'todayRechargeIncome': todayRechargeIncome,
  4006. 'todayChargeCardIncome': todayChargeCardIncome,
  4007. 'userCount':d.userCount,
  4008. 'userCountAddedThisMonth':userCountAddedThisMonth,
  4009. 'devTotalNum': allCount,
  4010. 'offlineTotal': offlineCount,
  4011. 'onlineTotal': onlineCount,
  4012. 'detail': json_dumps(detail),
  4013. 'ZJFirePlatform': ZJFirePlatform,
  4014. 'hasZJFirePlatform': hasZJFirePlatform,
  4015. 'disableDevice': True if "dealerDisableDevice" in d.features else False
  4016. })
  4017. return JsonResponse({
  4018. 'result': 1,
  4019. 'description': '',
  4020. 'payload': {
  4021. 'total': total,
  4022. 'dataList': dataList
  4023. }
  4024. })
  4025. @permission_required(ROLE.manager)
  4026. def getDealerListByAgent(request):
  4027. # type: (WSGIRequest)->JsonResponse
  4028. """
  4029. :param request:
  4030. :return:
  4031. """
  4032. agentIds = json.loads(request.body).get('agentIds', [])
  4033. agents = {str(_.id): _.nickname for _ in Agent.objects(id__in=agentIds)}
  4034. if not agents: return JsonResponse({'result': 1, 'payload': []})
  4035. dataList = [
  4036. {
  4037. 'dealerName': _.nickname,
  4038. 'dealerId': str(_.id),
  4039. 'agentId': str(_.agentId),
  4040. 'agentName': agents[str(_.agentId)]
  4041. }
  4042. for _ in Dealer.objects(agentId__in=agentIds)
  4043. ]
  4044. return JsonResponse({'result': 1, 'payload': {'dataList': dataList, 'total': len(dataList)}})
  4045. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取设备列表失败'))
  4046. @permission_required(ROLE.dealer, ROLE.subaccount)
  4047. def equipmentList(request):
  4048. # type: (WSGIRequest)->JsonResponse
  4049. def _get_port_status(portDict):
  4050. allPorts = portDict.get("allPorts", 0)
  4051. usedPorts = portDict.get("usedPorts", 0)
  4052. usePorts = portDict.get("usePorts", 0)
  4053. return allPorts, usedPorts, usePorts
  4054. dealerId = str(request.user.bossId)
  4055. pageIndex = int(request.GET.get('pageIndex', 1))
  4056. pageSize = int(request.GET.get('pageSize', 10))
  4057. equipmentGroupId = request.GET.get('equipmentGroupId')
  4058. online = request.GET.get('online')
  4059. searchKey = request.GET.get('searchKey', '')
  4060. sort = request.GET.get('sort', 'logicalCode')
  4061. partnerGroupList = Group.get_group_ids_of_partner(dealerId)
  4062. ownGroupList = Group.get_group_ids_of_dealer(dealerId)
  4063. groupIds = partnerGroupList + ownGroupList
  4064. if not equipmentGroupId:
  4065. selectedGroupIds = groupIds
  4066. else:
  4067. selectedGroupIds = [equipmentGroupId]
  4068. if not online:
  4069. onlineStates = [0, 1]
  4070. else:
  4071. onlineStates = [int(online)]
  4072. groupDict = Group.get_groups_by_group_ids(selectedGroupIds)
  4073. devNoList = Device.get_devNos_by_group(selectedGroupIds)
  4074. devs = Device.get_dev_by_nos(devNoList).values()
  4075. devDict, deviceCount = {}, 0
  4076. devCacheMap = Device.get_many_dev_control_cache(devNoList)
  4077. showPortStatus = bool(request.user.feature_boolean_map.get("showPortStatus", None))
  4078. for dev in devs: # type: DeviceDict
  4079. if dev.online not in onlineStates:
  4080. continue
  4081. group = groupDict.get(dev['groupId'])
  4082. if group is None:
  4083. continue
  4084. if any(map(lambda _: searchKey in _, (dev['devNo'],
  4085. dev['remarks'],
  4086. dev['logicalCode'],
  4087. group['groupName'],
  4088. group['address']))):
  4089. isFault = dev.get('isFault', False)
  4090. isDND = dev.is_DND_now
  4091. item = {
  4092. 'id': dev.devNo,
  4093. 'logicalCode': dev.logicalCode,
  4094. 'name': group['groupName'],
  4095. 'groupId': group['groupId'],
  4096. 'type': dev.devType['name'],
  4097. 'typeId': dev.devType['id'],
  4098. 'devType': dev.devType,
  4099. 'unit': dev.devType.get('unit', DeviceType.unit.default),
  4100. 'online': dev.online,
  4101. 'signal': dev.signal,
  4102. 'timeBased': dev.devType.get('timeBased', DeviceType.timeBased.default),
  4103. 'autoRefundEnable': dev.devType.get('autoRefundEnable', DeviceType.autoRefundEnable.default),
  4104. 'channelType': dev.channelType,
  4105. 'isManager': False if dev['groupId'] in partnerGroupList else True,
  4106. 'serviceState': dev.get('serviceState', Const.ServiceState.Normal.name),
  4107. 'remarks': dev.get('remarks', Device.remarks.default),
  4108. 'status': dev.status,
  4109. 'statusInfo': dev.statusInfo,
  4110. 'isFault': isFault,
  4111. 'isDND': isDND,
  4112. 'offTimeDate': datetime.datetime.fromtimestamp(int(str(dev.offTime)[0:10])).strftime('%Y-%m-%d %H:%M:%S') if dev.offTime is not None else '',
  4113. 'tag': group.get("tag", ""),
  4114. "deviceWarning": dev.is_warning
  4115. }
  4116. # 最近离线时间小于2017年的都为空
  4117. offTimeYear = int(item['offTimeDate'][0:4])
  4118. if offTimeYear < 2017:
  4119. item['offTimeDate'] = ''
  4120. if showPortStatus:
  4121. # 这个地方需要添加 具体的端口 使用情况 故障、工作、空闲等 使用情况从缓存中直接读取,如果不存在 则没有,不去具体查询设备
  4122. devCache = devCacheMap.get(device_control_cache_key(dev["devNo"]), {})
  4123. allPorts, usedPorts, usePorts = _get_port_status(devCache)
  4124. hasPort = showPortStatus and bool(allPorts)
  4125. item.update({"hasPort": hasPort})
  4126. if hasPort: item.update(
  4127. {"portStatus":
  4128. {
  4129. "all": allPorts,
  4130. "idle": usePorts,
  4131. "used": usedPorts,
  4132. }
  4133. }
  4134. )
  4135. else:
  4136. item.update({"hasPort": False})
  4137. if not dev.online and Device.utils_is_expired(dev):
  4138. item.update({'simExpireDate': dev.formatSimExpireDate, 'simStatus': dev.simStatus})
  4139. if dev['groupId'] in devDict:
  4140. devDict[dev['groupId']].append(item)
  4141. else:
  4142. devDict[dev['groupId']] = [item]
  4143. # 近7日平均使用率
  4144. if dev.devType.get('features', {}).get('7_days_average_utilization_rate', False) is True:
  4145. nowDateTime = datetime.datetime.now()
  4146. sevenDaysAgoDateTime = nowDateTime - datetime.timedelta(days=7)
  4147. consumeRecords = ConsumeRecord.objects(devNo=dev.devNo, dateTimeAdded__gte=sevenDaysAgoDateTime, dateTimeAdded__lte=nowDateTime)
  4148. sevenDaysAverage = round(((float(consumeRecords.count()) / 7) / 10) * 100, 2)
  4149. item.update({'sevenDaysAverage': sevenDaysAverage})
  4150. deviceCount += 1
  4151. showGroups = paginate(sorted(devDict.keys(), reverse=False), pageSize=pageSize, pageIndex=pageIndex)
  4152. devList = []
  4153. for keyGrp in showGroups:
  4154. devList.extend(devDict[keyGrp])
  4155. if sort == 'logicalCode':
  4156. tempList = natural_sort(array=devList, key='logicalCode', reverse=False)
  4157. elif sort == 'devType':
  4158. tempList = sorted(devList, key=lambda x: x['devType']['name'])
  4159. elif sort == 'remarks':
  4160. tempList = sorted(devList, key=lambda x: x['remarks'], reverse=True)
  4161. elif sort == "tag":
  4162. tempList = devList
  4163. else:
  4164. raise InvalidParameter(u'搜索条件不合法')
  4165. if sort == "tag":
  4166. devList = sorted(tempList, key=lambda x: x['tag'], reverse=True)
  4167. else:
  4168. devList = sorted(tempList, key=lambda x: x['groupId'])
  4169. return JsonResponse({
  4170. "result": 1,
  4171. "description": None,
  4172. 'payload': {
  4173. "total": deviceCount,
  4174. "groupCount": len(devDict.keys()),
  4175. "dataList": devList
  4176. }
  4177. })
  4178. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取库存列表失败'))
  4179. @permission_required(ROLE.dealer, ROLE.subaccount)
  4180. def equipmentListForStock(request):
  4181. # type: (WSGIRequest)->JsonResponse
  4182. ownerId = str(request.user.bossId)
  4183. equipmentGroupId = request.GET.get('equipmentGroupId', 'all')
  4184. online = request.GET.get('online', 'all')
  4185. searchKey = request.GET.get('searchKey', '')
  4186. groupIds, devTempList = Device.filter(dealerId=ownerId, searchKey=searchKey, online=online,
  4187. equipmentGroupId=equipmentGroupId)
  4188. devList = []
  4189. for dev in devTempList:
  4190. if not dev.has_key('quantity'):
  4191. continue
  4192. devList.append(dev)
  4193. return JsonResponse({
  4194. "result": 1,
  4195. "description": None,
  4196. 'payload': {
  4197. "total": len(groupIds),
  4198. "groupCount": len(devList),
  4199. "dataList": devList
  4200. }
  4201. })
  4202. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'解绑失败'))
  4203. @permission_required(ROLE.dealer, ROLE.subaccount)
  4204. @request_limit_by_user(operation='unbindDevice', limit=100, logger=logger)
  4205. def unbindDevice(request):
  4206. def unbindDeviceDefault(request):
  4207. # type: (WSGIRequest)->JsonResponse
  4208. """
  4209. 经销商解绑设备
  4210. ..modified 去掉对代理商串货的限制
  4211. :param request:
  4212. :return:
  4213. """
  4214. owner_id = str(request.user.bossId)
  4215. devNo = request.POST.get('value', None)
  4216. if devNo is None:
  4217. return JsonResponse({"result": 0, "description": u"缺少参数", 'payload': {}})
  4218. dev = Device.get_dev(devNo) # type: DeviceDict
  4219. devType = dev['devType']
  4220. groupId = dev['groupId']
  4221. if dev is None:
  4222. return JsonResponse({"result": 0, "description": u"该设备不存在,请刷新后再试", 'payload': {}})
  4223. if not dev.is_registered:
  4224. return JsonResponse({"result": 0, "description": u"该设备没有注册,不需要解绑", 'payload': {}})
  4225. if dev.ownerId != owner_id:
  4226. return JsonResponse({"result": 0, "description": u"不是您的设备,不能够解绑", 'payload': {}})
  4227. # 如果是对接丰图平台的设备,将平台上的该设备删除
  4228. if dev.owner.supports("supportFengTu"):
  4229. from apps.web.api.ft_north.utils import deleteDeviceReport
  4230. deleteDeviceReport(dev.devNo)
  4231. if dev.owner.supports("supportBeiJingFengTai"):
  4232. from apps.web.south_intf.bj_north.utils import delete_device_info
  4233. delete_device_info(dev.devNo)
  4234. try:
  4235. Device.un_register(dev=dev, operator=request.user.human_id)
  4236. dealer = Dealer.objects.get(id=owner_id)
  4237. dealer.devCount -= 1
  4238. dealer.save()
  4239. except RentDeviceError as rde:
  4240. return JsonErrorResponse(rde.message)
  4241. except Exception as e:
  4242. logger.exception(
  4243. 'un register failure. error = %s, devNo = %s, ownerId = %s' % (e, devNo, str(request.user.bossId)))
  4244. return JsonResponse({"result": 0, "description": u"系统错误", 'payload': {}})
  4245. group = Group.get_group(groupId)
  4246. if group.get('swapFlag', False):
  4247. agentId = request.user.agentId
  4248. agent = Agent.objects(id=agentId).first()
  4249. if agent:
  4250. devNum = 0
  4251. if 'majorDeviceType' in devType and (u'直流' in devType['majorDeviceType'] or u'交流' in devType['majorDeviceType']):
  4252. devNum = -1
  4253. SwapGroup.update_swap_time_and_num(groupId, devNum)
  4254. SwapContract.update_swap_time_and_num(groupId, owner_id, agentId, agent.managerId, devNum)
  4255. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4256. current_user = request.user # type: UserSearchable
  4257. if not current_user.normal:
  4258. return JsonResponse({"result": 0, "description": u"账号异常,不能进行该操作", 'payload': {}})
  4259. return unbindDeviceDefault(request)
  4260. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'解绑失败'))
  4261. @permission_required(ROLE.dealer, ROLE.subaccount)
  4262. @request_limit_by_user(operation='unbindAllNode', limit=100, logger=logger)
  4263. def unbindAllNode(request):
  4264. # 获取主机的子节点
  4265. lc = request.POST.get('logicalCode', None)
  4266. master = Device.get_dev_by_l(lc) # type: DeviceDict
  4267. nodeList = master.deviceAdapter.get_node_list()
  4268. if not nodeList:
  4269. return JsonResponse({"result": 0, "description": u"该设备不存在,请刷新后再试", 'payload': {}})
  4270. owner_id = str(request.user.bossId)
  4271. # TODO 和刘崇确认 此处先简单修复 然后后续可能进行优化
  4272. # 进行检查 保证所有设备都是 该经销商的
  4273. errDevs = list()
  4274. for node in nodeList: # type: DeviceDict
  4275. if not node.is_registered:
  4276. continue
  4277. if node.ownerId != owner_id:
  4278. errDevs.append(node.logicalCode)
  4279. if errDevs:
  4280. return JsonErrorResponse(description=u"设备{} 不是您的设备 无法解绑".format(" ".join(errDevs)))
  4281. # 再解除经销商绑定
  4282. for node in nodeList:
  4283. if not node.is_registered:
  4284. continue
  4285. Device.un_register(dev=node, operator=request.user.human_id)
  4286. dealer = Dealer.objects.get(id=owner_id)
  4287. dealer.devCount -= 1
  4288. dealer.save()
  4289. return JsonOkResponse()
  4290. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除套餐失败'))
  4291. @permission_required(ROLE.dealer, ROLE.subaccount)
  4292. def delPackages(request):
  4293. # type: (WSGIRequest)->JsonResponse
  4294. curr_user = request.user # type: Union[Dealer, SubAccount]
  4295. if not curr_user.normal:
  4296. return JsonErrorResponse(description=u'账号异常,不能进行该操作')
  4297. devNo = request.POST.get('devNo', None)
  4298. ruleId = request.POST.get('ruleId', None)
  4299. if devNo is None or ruleId is None:
  4300. return JsonResponse({"result": 0, "description": u"缺少参数", 'payload': {}})
  4301. dev = Device.get_dev(devNo)
  4302. if dev is None:
  4303. return JsonResponse({"result": 0, "description": u"找不到设备", 'payload': {}})
  4304. try:
  4305. dev['washConfig'].pop(ruleId)
  4306. except Exception, e:
  4307. logger.exception('pop washconfig error=%s,ruleId=%s,devNo=%s' % (e, ruleId, devNo))
  4308. return JsonResponse({"result": 0, "description": u'该套餐已经被删除了,请刷新页面', 'payload': {}})
  4309. try:
  4310. Device.get_collection().update_one({'devNo': devNo}, {'$set': {'washConfig': dev['washConfig']}})
  4311. Device.invalid_device_cache(devNo)
  4312. except Exception, e:
  4313. logger.exception('update device washconfig error=%s,devNo=%s,washConfig=%s' % (e, devNo, dev['washConfig']))
  4314. return JsonResponse({"result": 0, "description": u'保存套餐出错,请稍候再试', 'payload': {}})
  4315. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4316. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取套餐失败'))
  4317. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  4318. def getPackages(request):
  4319. # type: (WSGIRequest)->JsonResponse
  4320. lc = request.GET.get('logicalCode', None)
  4321. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  4322. if dev is None:
  4323. return JsonErrorResponse(description=u"找不到设备")
  4324. maxCoins = dev.get('maxCoins', 4)
  4325. devNo = dev.devNo
  4326. # 设备没注册, 走脉冲测试
  4327. if not dev.ownerId:
  4328. devData = {
  4329. 'id': devNo,
  4330. 'maxCoins': maxCoins,
  4331. 'devNo': devNo,
  4332. 'type': u'脉冲',
  4333. 'typeCode': u'201',
  4334. 'groupName': u'测试',
  4335. 'groupNumber': 666
  4336. }
  4337. defaultWashconfig = {'1': {'coins': 1}, '2': {'coins': 2}, '3': {'coins': 3}, '4': {'coins': 4},
  4338. '5': {'coins': 5}}
  4339. ruleList = [
  4340. {
  4341. 'id': packageId,
  4342. 'name': u'测试',
  4343. 'coins': rule['coins'],
  4344. 'price': rule.get('price', rule['coins'])
  4345. } for packageId, rule in defaultWashconfig.items()
  4346. ]
  4347. return JsonResponse({"result": 1, "description": None, 'payload': {'devData': devData, 'ruleList': ruleList}})
  4348. group = Group.get_group(dev['groupId'])
  4349. if group is None:
  4350. return JsonErrorResponse(description=u'找不到设备')
  4351. if group['ownerId'] != str(request.user.bossId):
  4352. return JsonErrorResponse(description=u'找不到设备')
  4353. devData = {
  4354. 'id': devNo,
  4355. 'maxCoins': maxCoins,
  4356. 'isManager': True,
  4357. 'groupName': group['groupName'],
  4358. 'groupNumber': dev['groupNumber'],
  4359. 'devNo': devNo,
  4360. 'type': dev['devType']['name'],
  4361. 'typeCode': dev['devType']['code']
  4362. }
  4363. if "displaySwitchs" in dev["otherConf"]:
  4364. displaySwitchs = dev["otherConf"].get('displaySwitchs')
  4365. else:
  4366. displaySwitchs = {'displayCoinsSwitch': True,
  4367. 'displayTimeSwitch': True,
  4368. 'displayPriceSwitch': True,
  4369. "setPulseAble": False,
  4370. "setBasePriceAble": False}
  4371. if dev.channelType != DeviceChannelType.Channel_BT:
  4372. smartBox = ActionDeviceBuilder.create_action_device(dev)
  4373. try:
  4374. portDict = smartBox.dealer_get_port_status()
  4375. if portDict:
  4376. chargeIndex = {}
  4377. for index, info in portDict.items():
  4378. if "status" not in info:
  4379. continue
  4380. if info['status'] == Const.DEV_WORK_STATUS_IDLE:
  4381. chargeIndex[index] = 'idle'
  4382. elif info['status'] == Const.DEV_WORK_STATUS_WORKING:
  4383. chargeIndex[index] = 'busy'
  4384. elif info['status'] == Const.DEV_WORK_STATUS_FAULT:
  4385. chargeIndex[index] = 'fault'
  4386. elif info['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
  4387. chargeIndex[index] = 'ban'
  4388. elif info['status'] == Const.DEV_WORK_STATUS_CONNECTED:
  4389. chargeIndex[index] = 'connected'
  4390. elif info['status'] == Const.DEV_WORK_STATUS_FINISHED:
  4391. chargeIndex[index] = 'finished'
  4392. devData.update({'chargeIndex': chargeIndex})
  4393. except ServiceException, e:
  4394. return JsonErrorResponse(description=e.result.get('description'))
  4395. except Exception as e:
  4396. logger.exception(e)
  4397. return JsonErrorResponse(description=u'未知错误')
  4398. if dev["devType"]["code"] == Const.DEVICE_TYPE_CODE_HP_GATE:
  4399. if request.GET.get("isRemoteUpper", None):
  4400. ruleList = []
  4401. else:
  4402. tempList = sorted(dev["washConfig"].get("1", {}).items(), key=lambda x: x[0])
  4403. ruleList = [v for _, v in tempList]
  4404. chargeIndex = {}
  4405. if dev["otherConf"].get("controlEnter") in ("1", "2"):
  4406. chargeIndex["enter"] = "idle"
  4407. if dev["otherConf"].get("controlExit") in ("1", "2"):
  4408. chargeIndex["exit"] = "idle"
  4409. devData.update({'chargeIndex': chargeIndex})
  4410. if request.GET.get("isRemoteUpper", None):
  4411. ruleList = []
  4412. elif dev["devType"]["code"] in support_policy_weifule:
  4413. if dev.deviceAdapter.support_device_package:
  4414. payload = dev.deviceAdapter.dealer_show_package()
  4415. payload.update({"devData": devData})
  4416. return JsonOkResponse(payload=payload)
  4417. elif dev["devType"]["code"] in support_policy_device:
  4418. if dev.deviceAdapter.support_device_package:
  4419. payload = dev.deviceAdapter.dealer_show_package()
  4420. payload.update({"devData": devData})
  4421. return JsonOkResponse(payload=payload)
  4422. elif dev["devType"]["code"] in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG, Const.DEVICE_TYPE_CODE_CHARGE_XIAOKEDOU]:
  4423. if dev.deviceAdapter.support_device_package:
  4424. payload = dev.deviceAdapter.dealer_show_package()
  4425. payload.update({"devData": devData})
  4426. return JsonOkResponse(payload=payload)
  4427. else:
  4428. snRuleList = []
  4429. ruleList = []
  4430. for packageId, rule in dev['washConfig'].items():
  4431. item = {
  4432. 'id': packageId,
  4433. 'name': rule['name'],
  4434. 'coins': rule['coins'],
  4435. 'price': rule.get('price', rule['coins']),
  4436. 'time': rule.get('time', 20),
  4437. 'description': rule.get('description', ''),
  4438. 'imgList': rule.get('imgList', []),
  4439. 'unit': rule.get('unit', u'分钟'),
  4440. 'switch': rule.get('switch', True),
  4441. }
  4442. if rule.get('pulse'):
  4443. item.update({
  4444. 'pulse': rule.get('pulse'),
  4445. })
  4446. if rule.get('basePrice'):
  4447. item.update({
  4448. 'basePrice': rule.get('basePrice'),
  4449. })
  4450. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  4451. item.update({
  4452. 'billingMethod': rule['billingMethod'],
  4453. })
  4454. if 'sn' in rule:
  4455. item['sn'] = rule['sn']
  4456. ruleList.append(item)
  4457. ruleList = sorted(ruleList, key=lambda x: (x.get('sn'), x.get('id')))
  4458. payload = {"devData": devData, "ruleList": ruleList, 'displaySwitchs': displaySwitchs}
  4459. unit_price = dev.otherConf.get('unit_price', {})
  4460. if dev.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_WEIFULE2]:
  4461. try:
  4462. if not unit_price:
  4463. dev.deviceAdapter.set_dev_setting(dev.deviceAdapter.get_dev_setting())
  4464. unit_price = Device.get_dev_by_l(lc).otherConf.get('unit_price', {})
  4465. except:
  4466. pass
  4467. if unit_price:
  4468. payload.update({'unit_price': unit_price})
  4469. return JsonOkResponse(payload=payload)
  4470. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存套餐失败'))
  4471. @permission_required(ROLE.dealer, ROLE.subaccount)
  4472. def savePackages(request):
  4473. """
  4474. 保存套餐
  4475. :param request:
  4476. :return:
  4477. """
  4478. # 检测套餐单位一致性校验
  4479. def check_package_unit(typeCode, package):
  4480. # 电川汽车装有按金额启动,电量启动和充满自停的需求
  4481. if typeCode == Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING:
  4482. return True
  4483. if typeCode in skip_package_unit_verify_list:
  4484. return True
  4485. dic = map(lambda x: {'unit': x.get('unit') }, package)
  4486. res = reduce(lambda x, y: x if x == y else None, dic)
  4487. if res is None:
  4488. return False
  4489. else:
  4490. return True
  4491. # 检查套餐单位单位小数点后两位校验
  4492. def check_params_range(typeCode, package):
  4493. if typeCode in skip_package_range_verify_list:
  4494. return None
  4495. dic = map(lambda x: [x.get('time')], package)
  4496. res = reduce(lambda x, y: x + y, dic)
  4497. result = None
  4498. for item in res:
  4499. l = str(item).split(".")
  4500. if len(l) > 1 and len(l[1]) > 2:
  4501. result = (res.index(item) // 3) + 1
  4502. break
  4503. return result
  4504. # 套餐参数完整性校验
  4505. def check_params(typeCode, package):
  4506. if typeCode in skip_package_params_verify_list:
  4507. return True
  4508. lis = map(lambda x: [x.get('time'), x.get('price'), x.get('coins')], package)
  4509. res = reduce(lambda x, y: x + y, lis)
  4510. for i in res:
  4511. if i is None or float(i) < 0:
  4512. return False
  4513. return True
  4514. # 套餐和金币是否需要强制1:1
  4515. def check_price_equal_coin(_devDict, _package):
  4516. for _dev in _devDict.values():
  4517. # 非出租设备 不影响
  4518. if not _dev.isRent:
  4519. continue
  4520. for _rule in _package:
  4521. if RMB(_rule["price"]) != RMB(_rule["coins"]):
  4522. return False
  4523. return True
  4524. curr_user = request.user # type: Union[Dealer, SubAccount]
  4525. if not curr_user.normal:
  4526. return JsonErrorResponse(description=u'账号异常,不能进行该操作')
  4527. status, msg = ensure_all_fields_are_not_empty(
  4528. {k: v for k, v in request.POST.items() if k not in ('ruleId',)})
  4529. if not status:
  4530. return JsonErrorResponse(description=msg)
  4531. paras = json.loads(request.body) if request.body else {}
  4532. if not paras:
  4533. return JsonErrorResponse(description=u'提交数据为空')
  4534. if paras['logicalCode'].__class__.__name__ == 'list':
  4535. devNoList = [Device.get_devNo_by_logicalCode(lc) for lc in paras['logicalCode']]
  4536. else:
  4537. devNoList = [Device.get_devNo_by_logicalCode(paras['logicalCode'])]
  4538. devDict = Device.get_dev_by_nos(devNoList)
  4539. if not devDict:
  4540. return JsonErrorResponse(description=u'找不到设备')
  4541. typeCode = devDict.values()[0]['devType']['code']
  4542. if typeCode in support_policy_weifule:
  4543. dev = devDict.values()[0]
  4544. if dev.deviceAdapter.support_device_package:
  4545. try:
  4546. dev.deviceAdapter.format_device_package(**paras)
  4547. except ServiceException as e:
  4548. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  4549. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4550. elif typeCode in support_policy_device:
  4551. dev = devDict.values()[0]
  4552. if dev.deviceAdapter.support_device_package:
  4553. try:
  4554. dev.deviceAdapter.format_device_package(**paras)
  4555. except ServiceException as e:
  4556. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  4557. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4558. # 解析washConfig,如果需要下发设备,解析出来setConfig
  4559. serviceList = paras['serviceData']
  4560. displaySwitchs = paras.get('displaySwitchs', {'displayCoinsSwitch': True,
  4561. 'displayTimeSwitch': True,
  4562. 'displayPriceSwitch': True,
  4563. 'setPulseAble': False,
  4564. 'setBasePriceAble': False})
  4565. # 调整sn顺序
  4566. for item in serviceList:
  4567. item["sn"] = serviceList.index(item)
  4568. if not check_params(typeCode, serviceList):
  4569. return JsonErrorResponse(description=u'请完整的填写套餐中的所有参数')
  4570. if not check_package_unit(typeCode, serviceList):
  4571. return JsonErrorResponse(description=u'套餐用户获得参数单位配置需要一致')
  4572. f = check_params_range(typeCode, serviceList)
  4573. if f:
  4574. return JsonErrorResponse(description=u'第%s个套餐 用户获得参数应为小数点后两位' % f)
  4575. if not check_price_equal_coin(devDict, serviceList):
  4576. return JsonErrorResponse(description=u"套餐金币与价格必须相等!")
  4577. washConfig, setConfig = {}, {}
  4578. agent = Agent.objects.get(id=request.user.agentId)
  4579. existIds = []
  4580. for rule in serviceList:
  4581. if 'id' in rule:
  4582. existIds.append(rule['id'])
  4583. # 霍珀道闸 后付费模式 使用阶梯计费
  4584. if typeCode == Const.DEVICE_TYPE_CODE_HP_GATE:
  4585. rule = {str(index + 1): v for index, v in enumerate(serviceList)}
  4586. washConfig = {"1": rule}
  4587. elif typeCode in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE,Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG, Const.DEVICE_TYPE_CODE_CHARGE_XIAOKEDOU]:
  4588. dev = devDict.values()[0]
  4589. if dev.deviceAdapter.support_device_package:
  4590. try:
  4591. washConfig, displaySwitchs = dev.deviceAdapter.format_device_package(**paras)
  4592. except ServiceException as e:
  4593. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  4594. else:
  4595. for rule in serviceList:
  4596. if rule.has_key('coins') and rule.has_key('price'):
  4597. if not (is_number(rule['coins']) and is_number(rule['price']) and is_number(
  4598. rule.get('time', 0))):
  4599. return JsonErrorResponse(description=u'金币数目或者时间或者价格必须是数字')
  4600. else:
  4601. rule['coins'], rule['price'] = 0, 0 # 对于那种先不需要付费的,这个就直接是0
  4602. if RMB(rule['price']) >= request.user.maxPackagePrice:
  4603. return JsonErrorResponse(description=u'套餐金额超限')
  4604. if len(rule['name']) > 20:
  4605. return JsonErrorResponse(description=u'套餐名字只能取1-20位')
  4606. if typeCode == Const.DEVICE_TYPE_CODE_WASHER:
  4607. name = rule['name']
  4608. if name not in [Const.WASHER_BOX_SET_DTS, Const.WASHER_BOX_SET_KSX, Const.WASHER_BOX_SET_BZX,
  4609. Const.WASHER_BOX_SET_DWX, Const.WASHER_BOX_SET_JRKS, Const.WASHER_BOX_SET_JRBZ,
  4610. Const.WASHER_BOX_JRDW, Const.WASHER_BOX_SET_TQJ]:
  4611. return JsonErrorResponse(description=u'套餐名称只能是:桶清洁、单脱水、快速洗、标准洗、大物洗、加热快速洗、加热标准洗、加热大物洗。')
  4612. coins = rule['coins']
  4613. useTime = rule['time']
  4614. if name == Const.WASHER_BOX_SET_DTS:
  4615. setConfig[Const.WASHER_BOX_DTS] = {'price': int(coins), 'time': int(useTime)}
  4616. elif name == Const.WASHER_BOX_SET_KSX:
  4617. setConfig[Const.WASHER_BOX_KS] = {'price': int(coins), 'time': int(useTime)}
  4618. elif name == Const.WASHER_BOX_SET_BZX:
  4619. setConfig[Const.WASHER_BOX_BZ] = {'price': int(coins), 'time': int(useTime)}
  4620. elif name == Const.WASHER_BOX_SET_DWX:
  4621. setConfig[Const.WASHER_BOX_DW] = {'price': int(coins), 'time': int(useTime)}
  4622. elif name == Const.WASHER_BOX_SET_JRKS:
  4623. setConfig[Const.WASHER_BOX_JRKS] = {'price': int(coins), 'time': int(useTime)}
  4624. elif name == Const.WASHER_BOX_SET_JRBZ:
  4625. setConfig[Const.WASHER_BOX_JRBZ] = {'price': int(coins), 'time': int(useTime)}
  4626. elif name == Const.WASHER_BOX_SET_JRDW:
  4627. setConfig[Const.WASHER_BOX_JRDW] = {'price': int(coins), 'time': int(useTime)}
  4628. elif (typeCode == Const.DEVICE_TYPE_CODE_WASHER_CW) and \
  4629. (rule['name'] not in [u'标准洗', u'快速洗', u'强力洗', u'单脱水', u'轻柔洗', u'漂洗并脱水', u'自洁', u'能效-全载', u'能效-半载',
  4630. u'整机自检', u'电脑版自检']):
  4631. return JsonErrorResponse(description=u'套餐名称只能是:标准洗,快速洗,强力洗,单脱水,轻柔洗,漂洗并脱水,自洁,能效-全载,能效-半载,整机自检,电脑版自检')
  4632. elif typeCode == Const.DEVICE_TYPE_CODE_WASHER_SIMAIER:
  4633. if rule['name'] not in [u'加强洗', u'标准洗', u'快速洗', u'单脱水']:
  4634. return JsonErrorResponse(description=u'套餐名称只能是:加强洗,标准洗,快速洗,单脱水')
  4635. elif typeCode == Const.DEVICE_TYPE_CODE_HUITENG:
  4636. if rule['name'] not in [u'单脱水', u'快速洗', u'标准洗', u'大物洗']:
  4637. return JsonErrorResponse(description=u'套餐名称只能是:单脱水,快速洗,标准洗,大物洗')
  4638. elif typeCode == Const.DEVICE_TYPE_CODE_CAR_CHARGING_CY:
  4639. price = rule.get("price")
  4640. coins = rule.get("coins")
  4641. unit = rule.get("unit")
  4642. time = rule.get("time")
  4643. if price != coins:
  4644. return JsonErrorResponse(description=u'请将金币和套餐值设置相同')
  4645. if unit != u"次":
  4646. return JsonErrorResponse(description=u'计费单位只能是:次')
  4647. if int(time) != 1:
  4648. return JsonErrorResponse(description=u"计费次数只能是:1")
  4649. elif typeCode in [Const.DEVICE_TYPE_CODE_WASHER_CY_HS,Const.DEVICE_TYPE_CODE_WASHER_CY_HS_YUCHUAN]:
  4650. if rule['name'] not in [u'大物洗', u'标准洗', u'快速洗', u'单脱水']:
  4651. return JsonErrorResponse(description=u'套餐名称只能是:大物洗,标准洗,快速洗,单脱水')
  4652. if rule['unit'] != "分钟":
  4653. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4654. if rule["name"] == u"单脱水" and (int(rule["time"]) > 9 or int(rule["time"]) < 5):
  4655. return JsonErrorResponse(description=u"单脱水时间范围为5-9分钟")
  4656. if rule["name"] == u"快速洗" and (int(rule["time"]) > 32 or int(rule["time"]) < 20):
  4657. return JsonErrorResponse(description=u"快速洗时间范围为20-32分钟")
  4658. if rule["name"] == u"标准洗" and (int(rule["time"]) > 43 or int(rule["time"]) < 35):
  4659. return JsonErrorResponse(description=u"标准洗时间范围为35-43分钟")
  4660. if rule["name"] == u"大物洗" and (int(rule["time"]) > 53 or int(rule["time"]) < 45):
  4661. return JsonErrorResponse(description=u"大物洗时间范围为45-53分钟")
  4662. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4663. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4664. elif typeCode in [Const.DEVICE_TYPE_CODE_WASHER_CY_HJ]:
  4665. if rule['name'] not in [u'大物洗', u'标准洗', u'快速洗', u'单脱水']:
  4666. return JsonErrorResponse(description=u'套餐名称只能是:大物洗,标准洗,快速洗,单脱水')
  4667. if rule['unit'] != "分钟":
  4668. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4669. if rule["name"] == u"单脱水" and (int(rule["time"]) > 15 or int(rule["time"]) < 5):
  4670. return JsonErrorResponse(description=u"单脱水时间范围为5-15分钟")
  4671. if rule["name"] == u"快速洗" and (int(rule["time"]) > 35 or int(rule["time"]) < 20):
  4672. return JsonErrorResponse(description=u"快速洗时间范围为20-35分钟")
  4673. if rule["name"] == u"标准洗" and (int(rule["time"]) > 50 or int(rule["time"]) < 35):
  4674. return JsonErrorResponse(description=u"标准洗时间范围为35-50分钟")
  4675. if rule["name"] == u"大物洗" and (int(rule["time"]) > 65 or int(rule["time"]) < 50):
  4676. return JsonErrorResponse(description=u"大物洗时间范围为50-65分钟")
  4677. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4678. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4679. elif typeCode in [Const.DEVICE_TYPE_CODE_WASHER_CY_HJ_1]:
  4680. if rule['name'] not in [u'大物洗', u'标准洗', u'快速洗', u'单脱水']:
  4681. return JsonErrorResponse(description=u'套餐名称只能是:大物洗,标准洗,快速洗,单脱水')
  4682. if rule['unit'] != "分钟":
  4683. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4684. if rule["name"] == u"单脱水" and (int(rule["time"]) > 15 or int(rule["time"]) < 5):
  4685. return JsonErrorResponse(description=u"单脱水时间范围为5-15分钟")
  4686. if rule["name"] == u"快速洗" and (int(rule["time"]) > 35 or int(rule["time"]) < 18):
  4687. return JsonErrorResponse(description=u"快速洗时间范围为18-35分钟")
  4688. if rule["name"] == u"标准洗" and (int(rule["time"]) > 45 or int(rule["time"]) < 30):
  4689. return JsonErrorResponse(description=u"标准洗时间范围为30-45分钟")
  4690. if rule["name"] == u"大物洗" and (int(rule["time"]) > 55 or int(rule["time"]) < 40):
  4691. return JsonErrorResponse(description=u"大物洗时间范围为40-55分钟")
  4692. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4693. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4694. elif typeCode == "1003053":
  4695. if rule['name'] not in [u'加时烘干', u'快速烘干', u'标准烘干', u'特别烘干']:
  4696. return JsonErrorResponse(description=u'套餐名称只能是:加时烘干,快速烘干,标准烘干,特别烘干')
  4697. if rule['unit'] != "分钟":
  4698. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4699. if rule["name"] == u"加时烘干" and (int(rule["time"]) > 20 or int(rule["time"]) < 5):
  4700. return JsonErrorResponse(description=u"加时烘干时间范围为5-20分钟")
  4701. if rule["name"] == u"快速烘干" and (int(rule["time"]) > 40 or int(rule["time"]) < 20):
  4702. return JsonErrorResponse(description=u"快速洗时间范围为20-40分钟")
  4703. if rule["name"] == u"标准烘干" and (int(rule["time"]) > 50 or int(rule["time"]) < 30):
  4704. return JsonErrorResponse(description=u"标准洗时间范围为30-50分钟")
  4705. if rule["name"] == u"特别烘干" and (int(rule["time"]) > 70 or int(rule["time"]) < 50):
  4706. return JsonErrorResponse(description=u"大物洗时间范围为50-70分钟")
  4707. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4708. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4709. if 'id' in rule:
  4710. ruleId = rule['id']
  4711. else:
  4712. ruleId = list(set(range(1, 71)) - set([int(ruleId) for ruleId in washConfig.keys()]) - set(existIds))[0]
  4713. # TODO 需要统一类型.这里为云南霍博单独做
  4714. dealer = request.user # type: Dealer
  4715. if ('coins_be_float' not in agent.features) and (not dealer.supports('coins_be_float')):
  4716. if int(float(rule['coins'])) != float(rule['coins']):
  4717. return JsonErrorResponse(description=u'金币只能是整数')
  4718. washConfig[str(ruleId)] = {
  4719. 'name': rule['name'],
  4720. 'coins': int(float(rule['coins'])),
  4721. 'price': float(rule['price']),
  4722. 'time': float(rule.get('time', 0)),
  4723. 'description': rule.get('description', ''),
  4724. 'imgList': rule.get('imgList', []),
  4725. 'unit': rule.get('unit', u'分钟'),
  4726. 'switch': rule.get('switch', True),
  4727. 'sn': rule.get('sn'),
  4728. }
  4729. else:
  4730. washConfig[str(ruleId)] = {
  4731. 'name': rule['name'],
  4732. 'coins': float(rule['coins']),
  4733. 'price': float(rule['price']),
  4734. 'time': float(rule.get('time', 0)),
  4735. 'description': rule.get('description', ''),
  4736. 'imgList': rule.get('imgList', []),
  4737. 'unit': rule.get('unit', u'分钟'),
  4738. 'switch': rule.get('switch', True),
  4739. 'sn': rule.get('sn'),
  4740. }
  4741. if rule.get('pulse'):
  4742. washConfig[str(ruleId)].update({
  4743. 'pulse': rule.get('pulse'),
  4744. })
  4745. if rule.get('basePrice'):
  4746. washConfig[str(ruleId)].update({
  4747. 'basePrice': rule.get('basePrice'),
  4748. })
  4749. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  4750. washConfig[str(ruleId)].update({
  4751. 'billingMethod': rule['billingMethod'],
  4752. })
  4753. if rule.get('autoStop') != None:
  4754. washConfig[str(ruleId)].update({
  4755. 'basePrice': rule.get('basePrice'),
  4756. })
  4757. if rule.get('autoRefund') != None:
  4758. washConfig[str(ruleId)].update({
  4759. 'basePrice': rule.get('basePrice'),
  4760. })
  4761. if typeCode in [Const.DEVICE_TYPE_CODE_WASHER_CY_HS, Const.DEVICE_TYPE_CODE_WASHER_CY_HS_YUCHUAN, Const.DEVICE_TYPE_CODE_WASHER_CY_HS_HONGGAN]:
  4762. if len(serviceList) != 4:
  4763. return JsonErrorResponse(description=u'请勿增加或删除套餐')
  4764. # 如果设备直接可以下发套餐信息到设备,直接到设备上修改。比如串口洗衣机、串口的充电设备等
  4765. for devNo, dev in devDict.items():
  4766. if dev['devType']['code'] == Const.DEVICE_TYPE_CODE_WASHER:
  4767. smartBox = dev.deviceAdapter # type: WasherBox
  4768. try:
  4769. curConfig = smartBox.get_wash_config()
  4770. except ServiceException, e:
  4771. logger.exception('get washconfig to device=%s error=%s' % (devNo, e))
  4772. return JsonErrorResponse(description=u'读取设备套餐信息遇到错误:%s,请稍候再试试哦' % (e.result.get('description')))
  4773. try:
  4774. curConfig.update(setConfig)
  4775. smartBox.set_wash_config(curConfig)
  4776. except ServiceException, e:
  4777. logger.exception('set washconfig to device=%s error=%s' % (devNo, e))
  4778. return JsonErrorResponse(description=u'保存套餐到设备遇到错误:%s,请稍候再试试哦' % (e.result.get('description')))
  4779. if dev['devType']['code'] == Const.DEVICE_TYPE_CODE_HUITENG:
  4780. smartBox = dev.deviceAdapter # type: washerHTBox
  4781. cmdFlagDict = {u'单脱水': {'coins': '01', 'time': '09', 'baseTime': 5},
  4782. u'快速洗': {'coins': '02', 'time': '08', 'baseTime': 20},
  4783. u'标准洗': {'coins': '03', 'time': '07', 'baseTime': 35},
  4784. u'大物洗': {'coins': '04', 'time': '06', 'baseTime': 45}}
  4785. oldConfig = dev['washConfig']
  4786. for ruleId, rule in oldConfig.items():
  4787. try:
  4788. newRule = washConfig.get(ruleId)
  4789. if newRule['coins'] != rule['coins']:
  4790. smartBox.set_normal_value(cmdFlagDict[newRule['name']]['coins'], newRule['coins'])
  4791. if newRule['time'] != rule['time']:
  4792. baseTime = cmdFlagDict[newRule['name']]['baseTime']
  4793. if newRule['time'] < baseTime:
  4794. return JsonErrorResponse(description=u'您设置的套餐%s时间%s分钟,不能低于基础时间%s分钟' % (
  4795. newRule['name'], newRule['time'], baseTime))
  4796. addTime = newRule['time'] - baseTime
  4797. smartBox.set_normal_value(cmdFlagDict[newRule['name']]['time'], addTime)
  4798. except ServiceException, e:
  4799. return JsonErrorResponse(description=u'保存套餐到设备遇到错误:%s,请重试哦' % (e.result.get('description')))
  4800. if dev['devType']['code'] in [Const.DEVICE_TYPE_CODE_WASHER_CY_HS, Const.DEVICE_TYPE_CODE_WASHER_CY_HS_YUCHUAN]:
  4801. box = dev.deviceAdapter
  4802. washPriceMap = {
  4803. u"单脱水": "priceDt",
  4804. u"快速洗": "priceKs",
  4805. u"标准洗": "priceBz",
  4806. u"大物洗": "priceDw"
  4807. }
  4808. washTimeMap = {
  4809. u"单脱水": "timeDt",
  4810. u"快速洗": "timeKs",
  4811. u"标准洗": "timeBz",
  4812. u"大物洗": "timeDw"
  4813. }
  4814. priceData = {}
  4815. timeData = {}
  4816. for _, c in washConfig.items():
  4817. try:
  4818. priceData[washPriceMap.get(c.get("name"))] = c.get("coins")
  4819. timeData[washTimeMap.get(c.get("name"))] = c.get("time")
  4820. except Exception as e:
  4821. break
  4822. else:
  4823. try:
  4824. box.set_config_82(priceData)
  4825. box.set_config_83(timeData)
  4826. except ServiceException, e:
  4827. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  4828. # 烘干机
  4829. if dev['devType']['code'] == Const.DEVICE_TYPE_CODE_WASHER_CY_HS_HONGGAN:
  4830. box = dev.deviceAdapter
  4831. hongganPriceMap = {
  4832. u"加时烘干": "priceDt",
  4833. u"快速烘干": "priceKs",
  4834. u"标准烘干": "priceBz",
  4835. u"特别烘干": "priceDw"
  4836. }
  4837. hongganTimeMap = {
  4838. u"加时烘干": "timeDt",
  4839. u"快速烘干": "timeKs",
  4840. u"标准烘干": "timeBz",
  4841. u"特别烘干": "timeDw"
  4842. }
  4843. priceData = {}
  4844. timeData = {}
  4845. for _, c in washConfig.items():
  4846. try:
  4847. priceData[hongganPriceMap.get(c.get("name"))] = c.get("coins")
  4848. timeData[hongganTimeMap.get(c.get("name"))] = c.get("time")
  4849. except Exception as e:
  4850. break
  4851. else:
  4852. try:
  4853. box.set_config_82(priceData)
  4854. box.set_config_83(timeData)
  4855. except ServiceException, e:
  4856. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  4857. try:
  4858. dev['washConfig'] = washConfig
  4859. otherConf = dev.get('otherConf', {})
  4860. otherConf['displaySwitchs'] = displaySwitchs
  4861. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'washConfig': dev['washConfig'], 'otherConf':otherConf}})
  4862. request.user.defaultWashConfig[dev['devType']['id']] = dev['washConfig'].values()
  4863. request.user.save()
  4864. Device.invalid_device_cache(devNo)
  4865. except ServiceException, e:
  4866. logger.exception('update device washconfig error=%s,devNo=%s,washConfig=%s'
  4867. % (e, devNo, dev['washConfig']))
  4868. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  4869. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4870. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'设置默认组失败'))
  4871. @permission_required(ROLE.dealer, ROLE.subaccount)
  4872. def setDefaultGroup(request):
  4873. ownerId = str(request.user.bossId)
  4874. groupId = request.POST.get('groupId', None)
  4875. if groupId is None:
  4876. return JsonErrorResponse(description=u"缺少参数")
  4877. try:
  4878. success, description, group = Group.update_group(group_id=groupId, isDefault=True)
  4879. return JsonOkResponse() if success else JsonErrorResponse(description=description)
  4880. except Exception, e:
  4881. logger.exception('update error=%s' % e)
  4882. return JsonResponse({'result': 0, 'description': u"系统繁忙,请稍后再试", 'payload': {}})
  4883. @permission_required(ROLE.dealer, ROLE.subaccount)
  4884. def logout(request):
  4885. agentId = request.user.agentId
  4886. auth.logout(request)
  4887. response = JsonResponse({'result': 1, 'payload': agentId})
  4888. # 删除不在使用的COOKIE
  4889. response.delete_cookie(key='hasagent')
  4890. return response
  4891. @permission_required(ROLE.dealer, ROLE.subaccount)
  4892. def wxconfig(request):
  4893. url = request.GET.get('href')
  4894. if not url:
  4895. return JsonResponse({'result': 0, 'description': u'参数错误', 'payload': {}})
  4896. value = get_wx_config(request.user, url)
  4897. logger.exception('wx config url = %s' % url)
  4898. return JsonResponse({'result': 1, 'description': None, 'payload': {'wxconfig': value}})
  4899. @require_GET
  4900. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取库存详情失败'))
  4901. @permission_required(ROLE.dealer, ROLE.subaccount)
  4902. def stockDetails(request):
  4903. logicalCode = request.GET.get('logicalCode')
  4904. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  4905. dev = Device.get_dev(devNo)
  4906. if not dev:
  4907. return JsonErrorResponse(description=u'找不到设备')
  4908. return JsonResponse({'result': 1, "description": None, "payload": {"quantity": dev['quantity']}})
  4909. @require_POST
  4910. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新库存失败,请重试'))
  4911. @permission_required(ROLE.dealer, ROLE.subaccount)
  4912. def updateStockQuantity(request):
  4913. payload = json.loads(request.body)
  4914. lc = payload.get('logicalCode')
  4915. quantity = int(payload.get('quantity', 0))
  4916. devNo = Device.get_devNo_by_logicalCode(lc)
  4917. dev = Device.get_dev(devNo)
  4918. if dev['quantity'] > quantity:
  4919. stockType = 'remove'
  4920. stockNum = dev['quantity'] - quantity
  4921. else:
  4922. stockType = 'add'
  4923. stockNum = quantity - dev['quantity']
  4924. result = Device.update_field(dev_no=devNo, update=True, quantity=quantity, consumptionQuantity=0)
  4925. if not result:
  4926. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  4927. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  4928. StockRecord.get_collection().insert(
  4929. {'logicCode': lc, 'imei': dev['devNo'], 'stockType': stockType, 'stockTime': stockTime, 'number': stockNum})
  4930. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  4931. @permission_required(ROLE.dealer, ROLE.subaccount)
  4932. def getStockRecord(request):
  4933. lc = request.GET.get('logicalCode')
  4934. if not lc:
  4935. return JsonResponse({'result': 0, 'description': u'未接收到设备编码,请刷新重试', 'payload': {}})
  4936. pageIndex = int(request.GET.get('pageIndex', 1))
  4937. pageSize = int(request.GET.get('pageSize', 10))
  4938. startTime = defaultTodayDate(request.GET.get('startTime', None)) + ' ' + '00:00:00'
  4939. endTime = defaultTodayDate(request.GET.get('endTime', None)) + ' ' + '23:59:59'
  4940. rcds = StockRecord.get_collection().find({'logicCode': lc, 'stockTime': {'$gte': startTime, '$lte': endTime}}).sort(
  4941. 'stockTime', -1)
  4942. add, cost = 0, 0
  4943. sIndex = (pageIndex - 1) * pageSize
  4944. eIndex = pageIndex * pageSize
  4945. ii = 0
  4946. dataList = []
  4947. for rcd in rcds:
  4948. name = ''
  4949. if rcd['stockType'] == 'add':
  4950. add += rcd['number']
  4951. name = u'增加库存 ' + rcd.get('more', '')
  4952. elif rcd['stockType'] == 'remove':
  4953. cost += rcd['number']
  4954. name = u'减少库存 ' + rcd.get('more', '')
  4955. elif rcd['stockType'] == 'consume':
  4956. cost += rcd['number']
  4957. name = u'用户购买 ' + rcd.get('more', '')
  4958. elif rcd['stockType'] == 'adFree':
  4959. cost += rcd['number']
  4960. name = u'吸粉发放 ' + rcd.get('more', '')
  4961. if sIndex <= ii < eIndex:
  4962. dataList.append({'name': name, 'time': rcd['stockTime'], 'number': rcd['number']})
  4963. ii += 1
  4964. devNo = Device.get_devNo_by_logicalCode(lc)
  4965. dev = Device.get_dev(devNo)
  4966. para = {'total': ii, 'add': add, 'cost': cost, 'quantity': dev['quantity'], 'dataList': dataList}
  4967. return JsonResponse({'result': 1, 'description': None, 'payload': para})
  4968. @permission_required(ROLE.dealer, ROLE.subaccount)
  4969. def toggleSwitches(request):
  4970. paraDict = json.loads(request.body) if request.body else {}
  4971. if not paraDict:
  4972. return JsonErrorResponse(description=u'接收数据为空,请重试')
  4973. ownerId = request.user.bossId # type: ObjectId
  4974. if paraDict.get("hasTempPackage", None) == True:
  4975. paraDict["displayTempPackage"] = True
  4976. success = Dealer.update_dealer(ownerId, **paraDict)
  4977. if not success:
  4978. return JsonErrorResponse(description=u'更新失败,请重试')
  4979. else:
  4980. return JsonOkResponse()
  4981. @permission_required(ROLE.dealer, ROLE.subaccount)
  4982. def clearDeviceStatistics(request):
  4983. lc = request.POST.get('logicalCode')
  4984. devNo = Device.get_devNo_by_logicalCode(lc)
  4985. dev = Device.get_dev(devNo)
  4986. if not dev:
  4987. return JsonErrorResponse(description=u'找不到设备')
  4988. if dev['ownerId'] != str(request.user.bossId):
  4989. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  4990. if dev.get('devType', {}).get('code', '') not in [Const.DEVICE_TYPE_CODE_WASHCAR_LSHB]:
  4991. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  4992. try:
  4993. smartBox = ActionDeviceBuilder.create_action_device(dev)
  4994. smartBox.clear_dev_feecount()
  4995. except ServiceException, e:
  4996. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  4997. return JsonResponse({'result': 1, 'description': u'', 'payload': {}})
  4998. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  4999. @permission_required(ROLE.dealer, ROLE.subaccount)
  5000. def getDeviceFunction(request):
  5001. payload = json.loads(request.body)
  5002. lc = payload.get("logicalCode")
  5003. if isinstance(lc, list) and len(lc):
  5004. lc = lc[0]
  5005. else:
  5006. raise JsonErrorResponse(description=u"无效的设备编号")
  5007. devNo = Device.get_devNo_by_logicalCode(lc)
  5008. dev = Device.get_dev(devNo)
  5009. if not dev:
  5010. return JsonResponse({'result': 0, 'description': u'未找到该设备', 'payload': {}})
  5011. try:
  5012. smartBox = ActionDeviceBuilder.create_action_device(dev)
  5013. setConf = smartBox.get_dev_setting()
  5014. if setConf is None:
  5015. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  5016. if len(payload.get("logicalCode")) > 1:
  5017. serviceCache.set('lastsettingConf_owner%s' % (str(request.user.id)), setConf, 600)
  5018. else:
  5019. caches['devmgr'].set('settingConf_%s' % (devNo,), setConf, 600)
  5020. return JsonResponse({'result': 1, 'description': u'', 'payload': setConf})
  5021. except ServiceException, e:
  5022. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  5023. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  5024. @permission_required(ROLE.dealer, ROLE.subaccount)
  5025. def getDeviceFunctionForIC(request):
  5026. payload = json.loads(request.body)
  5027. lc = payload.get("logicalCode")
  5028. if isinstance(lc, list) and len(lc):
  5029. lc = lc[0]
  5030. else:
  5031. raise JsonErrorResponse(description=u"无效的设备编号")
  5032. devNo = Device.get_devNo_by_logicalCode(lc)
  5033. dev = Device.get_dev(devNo)
  5034. if not dev:
  5035. return JsonResponse({'result': 0, 'description': u'未找到该设备', 'payload': {}})
  5036. try:
  5037. smartBox = ActionDeviceBuilder.create_action_device(dev)
  5038. setConf = smartBox.get_IC_card_password()
  5039. if setConf is None:
  5040. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  5041. caches['devmgr'].set('settingConf_%s' % (devNo,), setConf, 600)
  5042. return JsonResponse({'result': 1, 'description': u'', 'payload': setConf})
  5043. except ServiceException, e:
  5044. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  5045. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  5046. @permission_required(ROLE.dealer, ROLE.subaccount)
  5047. def setDeviceFunction(request):
  5048. # type: (WSGIRequest)->JsonResponse
  5049. payload = json.loads(request.body)
  5050. lc = payload.get("logicalCode")
  5051. if isinstance(lc, list) and len(lc):
  5052. lc = lc[0]
  5053. else:
  5054. raise JsonErrorResponse(description=u"无效的设备编号")
  5055. requestBody = RequestBodyDict({"POST": payload})
  5056. devNo = Device.get_devNo_by_logicalCode(lc)
  5057. dev = Device.get_dev(devNo)
  5058. if not dev:
  5059. return JsonErrorResponse(description=u'找不到设备')
  5060. if dev['ownerId'] != str(request.user.bossId):
  5061. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  5062. lastSetConf = caches['devmgr'].get('settingConf_%s' % (devNo,))
  5063. box = ActionDeviceBuilder.create_action_device(dev)
  5064. try:
  5065. box.set_device_function(requestBody, lastSetConf)
  5066. except ServiceException, e:
  5067. logger.exception('set info to device=%s error=%s' % (devNo, e))
  5068. return JsonResponse(
  5069. {'result': 0, 'description': u'设置参数遇到错误:%s' % (e.result.get('description', '')), 'payload': {}})
  5070. if lastSetConf is not None:
  5071. caches['devmgr'].set('settingConf_%s' % devNo, lastSetConf)
  5072. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  5073. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  5074. @permission_required(ROLE.dealer, ROLE.subaccount)
  5075. def setDeviceFunctionParam(request):
  5076. # type: (WSGIRequest)->JsonResponse
  5077. updateConf = json.loads(request.body)
  5078. logicalCodes = updateConf.pop('logicalCode')
  5079. # 替代品 先将 request 和 adapter的功能函数解耦 后续逐步修改
  5080. requestBody = RequestBodyDict({"POST": updateConf})
  5081. if len(logicalCodes) > 1:
  5082. setMode = updateConf.pop('modifyMode', None)
  5083. dev = Device.get_dev_by_l(logicalCodes[0])
  5084. dev_owner = dev.ownerId
  5085. dev_type_code = dev.devType.get('code')
  5086. for logicalCode in logicalCodes[1:]:
  5087. dev = Device.get_dev_by_l(logicalCode)
  5088. if dev_owner != dev.ownerId or dev_type_code != dev.devType.get('code'):
  5089. return JsonErrorResponse(description=u"设备经销商不同或者不同类型设备")
  5090. beforeConf = serviceCache.get('lastsettingConf_owner%s' % (str(request.user.id))) # type: Dict
  5091. if not beforeConf:
  5092. return JsonErrorResponse(description=u"查询当前配置信息失败")
  5093. if setMode == 'diff':
  5094. # 找出发生改变的参数项
  5095. for key, oldValue in beforeConf.iteritems():
  5096. if key in updateConf and str(updateConf[key]) == str(oldValue):
  5097. updateConf.pop(key)
  5098. if not updateConf:
  5099. return JsonErrorResponse(description=u"您没有修改任何参数")
  5100. payload = {'updateConf': updateConf, 'lastSetConf': None, 'logicalCodes': logicalCodes}
  5101. else:
  5102. payload = {'updateConf': updateConf, 'lastSetConf': beforeConf, 'logicalCodes': logicalCodes}
  5103. payload.update({
  5104. 'operationId': '{}_{}'.format(str(request.user.id), int(time.time()))
  5105. })
  5106. from taskmanager.mediator import task_caller
  5107. task_caller('batch_set_device_params', **payload)
  5108. serviceCache.set(payload['operationId'], payload, 600)
  5109. return JsonResponse({'result': 1, 'description': None, 'payload': {'operationId': payload['operationId']}})
  5110. else:
  5111. logicalCode = logicalCodes[0]
  5112. dealer = Dealer.objects(id=str(request.user.id)).first()
  5113. if dealer is None:
  5114. return JsonErrorResponse(description=u"设备的经销商不存在")
  5115. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  5116. dev = Device.get_dev(devNo)
  5117. if dev is None:
  5118. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  5119. if dev['ownerId'] != str(request.user.bossId):
  5120. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  5121. beforeConf = caches['devmgr'].get('settingConf_%s' % (devNo,))
  5122. if not beforeConf:
  5123. try:
  5124. beforeConf = dev.deviceAdapter.get_dev_setting()
  5125. if not beforeConf:
  5126. return JsonResponse({'result': 0, 'description': u'当前设备不支持该操作', 'payload': {}})
  5127. except Exception as e:
  5128. logger.exception(e)
  5129. return JsonResponse({'result': 0, 'description': u'查询设备当前配置信息失败', 'payload': {}})
  5130. operation = OperatorLog.record_dev_setting_changes_log(
  5131. dealer, 'record_someone_set_devSettings', dev['logicalCode'], dev['devType']['code'],
  5132. {
  5133. 'beforeCacheStr': json.dumps(beforeConf), 'afterCacheStr': json.dumps(updateConf)
  5134. }) # type: OperatorLog
  5135. try:
  5136. dev.deviceAdapter.set_device_function_param(requestBody, beforeConf)
  5137. operation.update(content__status='success')
  5138. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  5139. except ServiceException, e:
  5140. logger.info('error happened, error=%s' % (e,))
  5141. operation.update(content__status='fail', content_desc=e.result.get('description'))
  5142. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  5143. except InvalidParameter as e:
  5144. logger.exception(e)
  5145. operation.update(content__status='fail', content_desc=e.message)
  5146. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5147. except Exception, e:
  5148. operation.update(content__status='fail', content_desc=u'系统异常')
  5149. logger.exception('error happened, error=%s' % (e,))
  5150. return JsonResponse({'result': 0, 'description': u'系统异常,请检查输入参数,或者稍后重试', 'payload': {}})
  5151. @permission_required(ROLE.dealer, ROLE.subaccount)
  5152. def deviceParamsResult(request):
  5153. user = request.user
  5154. operationId = request.GET.get('operationId', None)
  5155. if not operationId:
  5156. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  5157. payload = serviceCache.get(operationId, {})
  5158. if not payload:
  5159. operations = OperatorLog.objects.filter(operatorId=str(user.id),
  5160. role=user.role,
  5161. content__operationId=operationId)
  5162. dataList = list(map(lambda operation: {'id': str(operation.id), 'logicalCode': operation.content['logicalCode'],
  5163. 'status': operation.content.get('status')}, operations))
  5164. else:
  5165. logicalCodes = payload.get('logicalCodes', [])
  5166. operations = OperatorLog.objects.filter(operatorId=str(user.id),
  5167. role=user.role,
  5168. content__logicalCode__in=logicalCodes,
  5169. content__operationId=operationId)
  5170. dataList = list(map(lambda operation: {'id': str(operation.id), 'logicalCode': operation.content['logicalCode'],
  5171. 'status': operation.content.get('status')}, operations))
  5172. if len(operations) != len(logicalCodes):
  5173. leftLogicalCodes = set(logicalCodes) - set(operations.values_list('logicalCode'))
  5174. for logicalCode in leftLogicalCodes:
  5175. dataList.append({'id': None, 'logicalCode': logicalCode, 'status': 'waiting'})
  5176. return JsonResponse({'result': 1, 'description': None, 'payload': {'dataList':dataList}})
  5177. @permission_required(ROLE.dealer, ROLE.subaccount)
  5178. def retryingSettingsDeviceParams(request):
  5179. dev_oper_id = request.GET.get('id')
  5180. operation = OperatorLog.objects.filter(id=dev_oper_id).first() # type: OperatorLog
  5181. logicalCode = operation.content['logicalCode']
  5182. dev = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  5183. if not dev:
  5184. return JsonResponse({'result': 0, 'description': u'该设备不存在', 'payload': {}})
  5185. if dev.ownerId != request.user.bossId:
  5186. return JsonResponse({'result': 0, 'description': u'您无权操作该设备', 'payload': {}})
  5187. try:
  5188. if operation.operatorName == 'record_someone_set_devSettings':
  5189. updateConf = json.loads(operation.content.get('updateConfStr'))
  5190. beforeCacheStr = json.loads(operation.content.get('beforeCacheStr'))
  5191. requestBody = RequestBodyDict({"POST": updateConf})
  5192. dev.deviceAdapter.set_device_function(requestBody, beforeCacheStr)
  5193. dev.deviceAdapter.set_device_function_param(requestBody, beforeCacheStr)
  5194. elif operation.operatorName == 'setServerSetting':
  5195. payload = json.loads(operation.content.get('after'))
  5196. dev.deviceAdapter.set_server_setting(payload)
  5197. except ServiceException, e:
  5198. logger.info('error happened, error=%s' % (e,))
  5199. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  5200. except InvalidParameter as e:
  5201. logger.exception(e)
  5202. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5203. else:
  5204. operation.update(content__status='success')
  5205. return JsonResponse({'result': 1, 'description': '重试成功', 'payload': {'status': 'success'}})
  5206. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取卡列表失败'))
  5207. @permission_required(ROLE.dealer, ROLE.subaccount)
  5208. def getUserCardList(request):
  5209. pageIndex = int(request.GET.get('pageIndex', 1))
  5210. pageSize = int(request.GET.get('pageSize', 10))
  5211. searchKey = str(request.GET.get('searchKey', ''))
  5212. userId = str(request.GET.get('userId', ''))
  5213. equipmentGroupId = str(request.GET.get('equipmentGroupId'))
  5214. frozen = request.GET.get("frozen", None)
  5215. dealerId = str(request.user.bossId)
  5216. queryDict = {
  5217. "dealerId": dealerId,
  5218. 'openId': userId or {'$exists': True}
  5219. }
  5220. if frozen:
  5221. queryDict.update({"frozen": bool(int(frozen))})
  5222. if searchKey:
  5223. queryDict.update(search_query(['cardName', 'phone', "cardNo"], searchKey).to_query(Card))
  5224. if equipmentGroupId:
  5225. queryDict.update({'groupId': equipmentGroupId})
  5226. cards = Card.objects.filter(__raw__=queryDict).skip((pageIndex - 1) * pageSize).limit(pageSize)
  5227. dataList = list()
  5228. for card in cards: # type: Card
  5229. dataList.append({
  5230. "cardName": card.cardName,
  5231. "phone": card.phone,
  5232. "groupId": card.groupId,
  5233. "groupName": card.group.groupName if card.group else "",
  5234. "cardId": str(card.id),
  5235. "bindStatus": card.isBinded,
  5236. "dealerId": card.dealerId,
  5237. "remarks": card.remarks,
  5238. "balance": card.balance,
  5239. "cardNo": card.cardNo,
  5240. "frozen": int(card.frozen)
  5241. })
  5242. payload = {
  5243. "total": get_paginate(dataList, pageSize=pageSize, pageIndex=pageIndex),
  5244. "dataList": dataList,
  5245. "agentId": request.user.agentId
  5246. }
  5247. return JsonResponse({"result": 1, "description": "", "payload": payload})
  5248. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取详情失败'))
  5249. @permission_required(ROLE.dealer, ROLE.subaccount)
  5250. def getUserCard(request):
  5251. cardId = request.GET.get("cardId", "")
  5252. try:
  5253. card = Card.objects.get(id=cardId)
  5254. except DoesNotExist:
  5255. return JsonErrorResponse(description=u"无效的卡")
  5256. except Exception as e:
  5257. logger.exception(e)
  5258. return JsonErrorResponse(description=u"获取卡详情失败,请刷新页面试试")
  5259. if card.dealerId != str(request.user.bossId):
  5260. return JsonErrorResponse(u"获取详情失败")
  5261. group = card.group
  5262. data = {
  5263. "cardId": cardId,
  5264. "cardNo": card.cardNo,
  5265. "cardName": card.cardName,
  5266. "groupId": card.groupId,
  5267. "dealerId": card.dealerId,
  5268. "groupName": group.groupName if group is not None else '',
  5269. "frozen": card.frozen,
  5270. "phone": card.phone,
  5271. "status": card.status,
  5272. "bindStatus": card.isBinded,
  5273. "balance": "{:.2f}".format(float(card.balance)),
  5274. "chargeBalance": "{:.2f}".format(float(card.chargeBalance)),
  5275. "bestowBalance": "{:.2f}".format(float(card.bestowBalance)),
  5276. "cardType": card.cardType
  5277. }
  5278. return JsonOkResponse(payload=data)
  5279. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"编辑卡失败"))
  5280. @permission_required(ROLE.dealer, ROLE.subaccount)
  5281. def editCard(request):
  5282. """
  5283. 经销商端 编辑卡片信息 可编辑内容 为 绑定设备组 卡名称 联系方式
  5284. :param request:
  5285. :return:
  5286. """
  5287. payload = json.loads(request.body)
  5288. cardId = payload.get("cardId")
  5289. cardName = payload.get("cardName")
  5290. phone = payload.get("phone")
  5291. groupId = payload.get("groupId")
  5292. try:
  5293. card = Card.objects.get(id=cardId)
  5294. except DoesNotExist:
  5295. return JsonErrorResponse(description=u"修改卡失败")
  5296. if phone and not PHONE_NUMBER_RE.match(phone):
  5297. return JsonErrorResponse(description=u"手机号码输入错误")
  5298. if cardName and not NAME_RE.match(cardName):
  5299. return JsonErrorResponse(description=u"请输入正确格式的名称(2-20位)")
  5300. if card.dealerId != str(request.user.bossId):
  5301. return JsonErrorResponse(description=u"不是您的卡片,无权修改")
  5302. group = Group.get_group(groupId)
  5303. if not group:
  5304. return JsonErrorResponse(description=u"请选择正确的设备组")
  5305. if group.get("ownerId") != str(request.user.bossId):
  5306. return JsonErrorResponse(description=u"请选择正确的设备组")
  5307. card.cardName = cardName
  5308. card.phone = phone
  5309. card.groupId = groupId
  5310. card.save()
  5311. return JsonOkResponse()
  5312. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"录卡失败"))
  5313. @permission_required(ROLE.dealer, ROLE.subaccount)
  5314. def saveEntityCard(request):
  5315. # type: (WSGIRequest)->JsonResponse
  5316. payload = json.loads(request.body)
  5317. cardNo = payload.get('cardNo', '')
  5318. phone = payload.get('phone', '')
  5319. cardName = payload.get('cardName', '')
  5320. groupId = payload.get("groupId", "")
  5321. dealerId = str(request.user.bossId)
  5322. # 卡号前置去0
  5323. if cardNo.isdigit():
  5324. cardNo = str(int(cardNo))
  5325. if not cardNo or not Card.check_card_no(cardNo):
  5326. return JsonErrorResponse(description=u"卡号不符合规则,请输入正确的卡号")
  5327. groupIds = Group.get_group_ids_of_dealer(dealerId)
  5328. if not groupId or groupId not in groupIds:
  5329. return JsonErrorResponse(description=u"请选择正确的设备组")
  5330. if phone and not PHONE_NUMBER_RE.match(phone):
  5331. return JsonErrorResponse(description=u"手机号码输入错误")
  5332. if cardName and not NAME_RE.match(cardName):
  5333. return JsonResponse({"result": 0, "description": u"请输入正确格式的名称(2-20位)"})
  5334. agentId = request.user.agentId
  5335. # 基于卡号找 代理商下的卡 或者平台下的卡
  5336. card = Card.objects.filter(Q(agentId=agentId) | Q(agentId=''), cardNo=cardNo).first()
  5337. if not card:
  5338. card = Card(
  5339. cardNo=cardNo,
  5340. dealerId=dealerId,
  5341. agentId=agentId,
  5342. cardName=cardName,
  5343. groupId=groupId,
  5344. phone=phone,
  5345. openId=Const.DEFAULT_CARD_OPENID
  5346. ).save()
  5347. return JsonResponse({"result": 1, "description": u"录入成功", "payload": {'cardId':str(card.id)}})
  5348. else:
  5349. if card.dealerId: # 有经销商注册
  5350. if card.dealerId == dealerId:
  5351. return JsonErrorResponse(description=u"{} 卡已经被您收录,请不要重复收录".format(cardNo))
  5352. else:
  5353. return JsonErrorResponse(description="{} 卡已被其他经销商录入,请确认卡号不要重复".format(cardNo))
  5354. else: # 此代理商平台下没有经销商注册该卡片
  5355. card.dealerId = dealerId
  5356. card.agentId = agentId
  5357. card.cardName = cardName
  5358. card.groupId = groupId
  5359. card.phone = phone
  5360. card.openId = Const.DEFAULT_CARD_OPENID
  5361. card.save()
  5362. return JsonResponse({"result": 1, "description": u"录入成功", "payload": {'cardId': str(card.id)}})
  5363. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"补卡失败"))
  5364. @permission_required(ROLE.dealer, ROLE.subaccount)
  5365. def swapCardNo(request):
  5366. """
  5367. 补卡 需要生成补卡记录,不重新创建新卡 如果新卡的卡号已经存在但是没有绑定用户并且内部没余额
  5368. :param request:
  5369. :return:
  5370. """
  5371. payload = json.loads(request.body)
  5372. cardNo = payload.get("cardNo", "")
  5373. cardId = payload.get("cardId")
  5374. dealerId = str(request.user.bossId)
  5375. # 卡号前置去0
  5376. if cardNo.isdigit():
  5377. cardNo = str(int(cardNo))
  5378. if not Card.check_card_no(cardNo):
  5379. return JsonErrorResponse(description=u"无效的卡号,卡号长度不能超过10位")
  5380. try:
  5381. oldCard = Card.objects.get(id=cardId)
  5382. except DoesNotExist:
  5383. return JsonErrorResponse(description=u"查询旧卡失败")
  5384. if oldCard.cardNo == cardNo:
  5385. return JsonErrorResponse(description=u"卡号一致无需修改")
  5386. if oldCard.dealerId != dealerId:
  5387. return JsonErrorResponse(description=u"无权编辑此卡")
  5388. checkStatus, checkMsg = Card.check_swap_card_no(cardNo, dealerId, oldCard.agentId)
  5389. if not checkStatus:
  5390. return JsonErrorResponse(description=checkMsg)
  5391. # 直接将卡号更新掉,然后新建一条换卡记录
  5392. oldCard.update(cardNo=cardNo)
  5393. SwapCardRecord.add_record(oldCard.cardNo, cardNo, oldCard.agentId, str(request.user.id))
  5394. return JsonOkResponse()
  5395. @record_operation_behavior()
  5396. @permission_required(ROLE.dealer, ROLE.subaccount)
  5397. def deleteInitCard(request):
  5398. cardId = json.loads(request.body).get("cardId")
  5399. card = Card.objects.filter(id=cardId, dealerId=str(request.user.bossId)).first()
  5400. if not card:
  5401. return JsonResponse({"result": 0, "description": u"未找到该实体卡", "payload": {}})
  5402. updated = card.clear_card()
  5403. if not updated:
  5404. return JsonErrorResponse(description=u'操作失败')
  5405. return JsonResponse({"result": 1, "description": u"删除成功", "payload": {}})
  5406. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取卡记录失败'))
  5407. @permission_required(ROLE.dealer, ROLE.subaccount)
  5408. def getUserCardRecord(request):
  5409. # type: (WSGIRequest)->JsonResponse
  5410. pageIndex = int(request.GET.get('pageIndex', 1))
  5411. pageSize = int(request.GET.get('pageSize', 10))
  5412. startTime = request.GET.get('startTime', 10)
  5413. endTime = request.GET.get('endTime', 10)
  5414. cardId = request.GET.get('cardId', None)
  5415. type = request.GET.get('type', None)
  5416. card = Card.objects.get(id=cardId)
  5417. if type == "chargeCard":
  5418. dataList = []
  5419. # TODO zjl 订单统一 不要这样搞得很别扭
  5420. viaMap = {
  5421. u"退币": "refund",
  5422. u"充值": "chargeCard"
  5423. }
  5424. for item in CardRechargeRecord.get_collection().find({
  5425. 'cardId': cardId,
  5426. 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5427. '$lte': to_datetime(endTime + " 23:59:59")}}).sort("dateTimeAdded", -1):
  5428. data = {
  5429. "cardId": str(item['_id']),
  5430. "cardNo": card.cardNo,
  5431. "via": viaMap.get(item.get("remarks"), "chargeCard"),
  5432. "amount": item['money'],
  5433. "coins": item.get('coins', item['money']),
  5434. "address": item['address'],
  5435. "groupName": item['groupName'],
  5436. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'),
  5437. "rechargeType": item.get("rechargeType")
  5438. }
  5439. if item.has_key('preBalance'):
  5440. data.update({'preBalance': item['preBalance']})
  5441. if item.has_key('balance'):
  5442. data.update({'balance': item['balance']})
  5443. if item.get("remarks", None):
  5444. data.update({'remarks': item['remarks']})
  5445. if item.get("logicalCode"):
  5446. data.update({"devType": Device.get_dev_by_logicalCode(item['logicalCode']).get("devType", dict()).get("name", "")})
  5447. data.update({"logicalCode": item['logicalCode']})
  5448. dataList.append(data)
  5449. elif type == "consume":
  5450. dataList = []
  5451. rcds = CardConsumeRecord.get_collection().find(
  5452. {'cardId': cardId, 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5453. '$lte': to_datetime(endTime + " 23:59:59")}}).sort(
  5454. "dateTimeAdded", -1)
  5455. for item in rcds:
  5456. newData = {
  5457. "cardId": str(item['_id']),
  5458. "cardNo": card.cardNo,
  5459. "via": "consume",
  5460. "devType": item['devType'],
  5461. "amount": item['money'],
  5462. "logicalCode": item['logicalCode'],
  5463. "address": item['address'],
  5464. "groupName": item['groupName'],
  5465. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S')
  5466. }
  5467. if item.has_key('balance'):
  5468. newData.update({'balance': item['balance']})
  5469. newData.update(item.get('servicedInfo', {}))
  5470. dataList.append(newData)
  5471. elif type == 'order':
  5472. dataList = []
  5473. for item in CardRechargeOrder.get_collection().find({
  5474. 'cardId': cardId,
  5475. 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5476. '$lte': to_datetime(endTime + " 23:59:59")}}).sort("dateTimeAdded", -1):
  5477. data = {
  5478. "via": "order",
  5479. "amount": item['money'],
  5480. "coins": item.get('coins', item['money']),
  5481. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'),
  5482. "status": u'等待用户刷卡充值' if item['status'] == 'finishedPay' else u'充值完成',
  5483. "desc": item['remarks'],
  5484. "rechargeType": item.get("rechargeType")
  5485. }
  5486. if item.has_key('preBalance'):
  5487. data.update({'preBalance': item['preBalance']})
  5488. if item.has_key('balance'):
  5489. data.update({'balance': item['balance']})
  5490. dataList.append(data)
  5491. elif type == 'cardConsume':
  5492. card = Card.objects.filter(id=cardId).first()
  5493. dataList = []
  5494. orders = ConsumeRecord.get_collection().find({
  5495. 'openId': str(card.openId),
  5496. 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5497. '$lte': to_datetime(endTime + " 23:59:59")}}).sort("dateTimeAdded", -1)
  5498. for item in orders:
  5499. data = {
  5500. "via": "consume",
  5501. "amount":item.get('coin', item['money']),
  5502. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'),
  5503. "orderNo":item.get('orderNo'),
  5504. "status": u'完成',
  5505. "desc": item['remarks']
  5506. }
  5507. dataList.append(data)
  5508. else:
  5509. return JsonResponse({"result": 0, "description": u"查询类型错误", "payload": {}})
  5510. return JsonResponse(
  5511. {
  5512. "result": 1,
  5513. "description": "",
  5514. "payload": {
  5515. "total": len(dataList),
  5516. "dataList": dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  5517. }
  5518. })
  5519. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  5520. @permission_required(ROLE.dealer, ROLE.subaccount)
  5521. def getDeviceFunctionByKey(request):
  5522. # type: (WSGIRequest)->JsonResponse
  5523. try:
  5524. payload = json.loads(request.body)
  5525. key = payload.get('key', None)
  5526. # 兼容真谷多
  5527. port = payload.get("portIndex", None)
  5528. if port is not None:
  5529. key = port
  5530. logicalCode = payload.get('logicalCode', None)
  5531. if isinstance(logicalCode, list) and len(logicalCode):
  5532. logicalCode = logicalCode[0]
  5533. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  5534. dev = Device.get_dev(devNo)
  5535. lastSetConf = caches['devmgr'].get('settingConf_%s' % (devNo,))
  5536. if not lastSetConf:
  5537. lastSetConf = {}
  5538. box = ActionDeviceBuilder.create_action_device(dev)
  5539. payload = box.get_device_function_by_key(key)
  5540. if payload is not None:
  5541. if lastSetConf is None:
  5542. lastSetConf = payload
  5543. else:
  5544. lastSetConf.update(payload)
  5545. caches['devmgr'].set('settingConf_%s' % (devNo,), lastSetConf, 600)
  5546. return JsonResponse({"result": 1, "description": "", "payload": payload})
  5547. except ServiceException, e:
  5548. return JsonResponse({"result": 0, "description": e.result.get('description', ''), "payload": {}})
  5549. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'设置错误'))
  5550. @permission_required(ROLE.dealer, ROLE.subaccount)
  5551. def setDeviceFunctionByKey(request):
  5552. # type: (WSGIRequest)->JsonResponse
  5553. payload = json.loads(request.body)
  5554. logicalCode = payload.get('logicalCode', None)
  5555. if isinstance(logicalCode, list) and len(logicalCode):
  5556. logicalCode = logicalCode[0]
  5557. else:
  5558. return JsonErrorResponse(description=u"错误的二维码编号")
  5559. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  5560. dev = Device.get_dev(devNo)
  5561. keyName = payload.get('key', None)
  5562. if keyName is None:
  5563. return JsonResponse({"result": 0, "description": u'没有按下任何控制键', "payload": {}})
  5564. try:
  5565. box = ActionDeviceBuilder.create_action_device(dev)
  5566. box.press_down_key(keyName)
  5567. return JsonResponse({"result": 1, "description": '', "payload": {}})
  5568. except ServiceException, e:
  5569. logger.exception('cannot setDeviceFunctionByKey, error=%s' % (e.result.get('description', '').encode('utf-8'),))
  5570. return JsonResponse({"result": 0, "description": e.result.get('description', ''), "payload": {}})
  5571. @error_tolerate(nil=DefaultJsonErrorResponse)
  5572. @permission_required(ROLE.dealer, ROLE.subaccount)
  5573. def wechatEntry(request):
  5574. # type: (WSGIRequest)->JsonResponse
  5575. """
  5576. 必须每次都进行鉴权
  5577. :param request:
  5578. :return:
  5579. """
  5580. current_user = request.user # type: Dealer
  5581. if not check_role(current_user, ROLE.dealer):
  5582. return ErrorResponseRedirect(error = u'权限错误')
  5583. entryType = request.GET.get('type')
  5584. if entryType not in ['simCard', 'apiQuota', 'disableAdQuota']:
  5585. return ErrorResponseRedirect(error = u'参数错误(10001)')
  5586. if entryType == 'simCard': # 流量卡充值
  5587. my_agent = Agent.get_inhouse_prime_agent()
  5588. app = get_app(my_agent, APP_TYPE.WECHAT_ENV_PAY, role = ROLE.dealer)
  5589. elif entryType == 'apiQuota': # api设备配额数量充值
  5590. my_agent = Agent.get_inhouse_prime_agent()
  5591. app = get_app(my_agent, APP_TYPE.WECHAT_ENV_PAY, role=ROLE.dealer)
  5592. elif entryType == 'disableAdQuota': # api设备配额数量充值
  5593. my_agent = Agent.get_inhouse_prime_agent()
  5594. app = get_app(my_agent, APP_TYPE.WECHAT_ENV_PAY, role=ROLE.dealer)
  5595. else:
  5596. return ErrorResponseRedirect(error=u'参数错误(10002)')
  5597. if isinstance(app, SaobeiPayApp):
  5598. redirect = request.GET.get('redirect')
  5599. redirect = add_query(redirect, {
  5600. 'openId': ''
  5601. })
  5602. return FrontEndResponseRedirect(redirect)
  5603. elif isinstance(app, WechatPayApp):
  5604. auth_bridge = WechatAuthBridge(app) # type: WechatAuthBridge
  5605. else:
  5606. return ErrorResponseRedirect(error=u'参数错误(10003)')
  5607. auth_code = request.GET.get(auth_bridge.auth_code_key, None)
  5608. if auth_code:
  5609. openId = auth_bridge.authorize(auth_code)
  5610. if openId is not None:
  5611. redirect = base64.b64decode(request.GET.get('payload'))
  5612. redirect = add_query(redirect, {
  5613. 'openId': openId
  5614. })
  5615. return FrontEndResponseRedirect(redirect)
  5616. else:
  5617. return ErrorResponseRedirect(error=u'系统繁忙,请重试')
  5618. else:
  5619. redirect_url = concat_server_end_url(uri='/dealer/wechat/entry?type={}'.format(entryType))
  5620. return ExternalResponseRedirect(
  5621. auth_bridge.generate_auth_url_base_scope(
  5622. redirect_uri=redirect_url,
  5623. payload=base64.b64encode(request.GET.get('redirect'))))
  5624. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'冻结卡失败'))
  5625. @permission_required(ROLE.dealer, ROLE.subaccount)
  5626. def freezeCard(request):
  5627. # type: (WSGIRequest)->JsonResponse
  5628. payload = json.loads(request.body)
  5629. frozen = payload.get('frozen')
  5630. cardId = payload.get('id', '')
  5631. try:
  5632. card = Card.objects.get(id=cardId)
  5633. card.frozen = frozen
  5634. card.status = 'active'
  5635. card.save()
  5636. except Exception, e:
  5637. logger.exception(e.message)
  5638. return JsonResponse({"result": 0, "description": u'系统错误', "payload": {}})
  5639. return JsonResponse({"result": 1, "description": '', "payload": {}})
  5640. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误'))
  5641. @permission_required(ROLE.dealer, ROLE.subaccount)
  5642. def getWalletWithdrawInfo(request):
  5643. dealer = request.user # type: Dealer
  5644. if not is_dealer(dealer):
  5645. return ErrorResponseRedirect(error = u'子账号无提现权限')
  5646. source_key = request.GET.get('sourceId')
  5647. income_type = request.GET.get('sourceType')
  5648. phone = str(dealer.monitorPhone) if dealer.monitorPhone else str(dealer.username)
  5649. result = {
  5650. "result": 1,
  5651. "description": None,
  5652. 'payload': {
  5653. 'payOpenId': 'placeholder',
  5654. 'phone': phone,
  5655. 'balance': dealer.sub_balance(income_type, source_key),
  5656. 'withdrawFeeRatio': dealer.withdrawFeeRatio,
  5657. 'support': dealer.withdraw_support(source_key)
  5658. }
  5659. }
  5660. return JsonResponse(result)
  5661. @require_POST
  5662. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5663. @permission_required(ROLE.dealer, ROLE.subaccount)
  5664. def getFeatureList(request):
  5665. # type: (WSGIRequest)->JsonResponse
  5666. """
  5667. :param request:
  5668. :return:
  5669. """
  5670. currentUser = request.user # type: Dealer
  5671. payload = json.loads(request.body)
  5672. queryList = payload.get('list', [])
  5673. resultFeatures = currentUser.query_feature_by_list(queryList)
  5674. if 'blackListManage' in currentUser.features:
  5675. resultFeatures.update({'blackListManage': True})
  5676. return JsonOkResponse(payload=resultFeatures)
  5677. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5678. @permission_required(ROLE.dealer, ROLE.subaccount)
  5679. def getOnsaleTypeList(request):
  5680. # type: (WSGIRequest)->JsonResponse
  5681. dataList = []
  5682. for typeName, info in OnSale.onsaleTypeDict.items():
  5683. dataList.append(
  5684. {
  5685. 'typeName': typeName,
  5686. 'desc': info['desc'],
  5687. 'img': info['img']
  5688. }
  5689. )
  5690. return JsonResponse({'result': 1, 'description': '', 'payload': {'total': len(dataList), 'dataList': dataList}})
  5691. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5692. @permission_required(ROLE.dealer, ROLE.subaccount)
  5693. def getOnsaleList(request):
  5694. # type: (WSGIRequest)->JsonResponse
  5695. """
  5696. 列出所有 经销商的活动尚未删除的
  5697. :param request:
  5698. :return:
  5699. """
  5700. pageIndex = int(request.GET.get('pageIndex', 1))
  5701. pageSize = int(request.GET.get('pageSize', 10))
  5702. searchKey = request.GET.get('searchKey', None)
  5703. dealerId = str(request.user.bossId)
  5704. onsales = OnSale.objects.filter(dealerId=dealerId, name__startswith=searchKey).order_by("-id")
  5705. dataList = [_obj.to_dict() for _obj in onsales[(pageIndex - 1) * pageSize: pageIndex * pageSize]]
  5706. return JsonOkResponse(payload={"total": len(dataList), "dataList": dataList})
  5707. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5708. @permission_required(ROLE.dealer, ROLE.subaccount)
  5709. def createOnsale(request):
  5710. # type: (WSGIRequest)->JsonResponse
  5711. dealerId = str(request.user.bossId)
  5712. payload = json.loads(request.body) if request.body else {}
  5713. if not payload:
  5714. return JsonErrorResponse(description=u'传入数据为空')
  5715. payload['startTime'] = to_datetime(payload['startTime'] + ' 00:00:00')
  5716. payload['endTime'] = to_datetime(payload['endTime'] + ' 23:59:59')
  5717. onsale = OnSale(**payload)
  5718. name = onsale.name
  5719. # 检查活动的名称
  5720. count = OnSale.objects.filter(dealerId=dealerId, name=name).count()
  5721. if count > 0:
  5722. return JsonResponse({'result': 0, 'description': u'活动名称重复,优惠活动的名称必须唯一', 'payload': {}})
  5723. # 检查下该经销商是否符合资格配置该活动
  5724. if onsale.onsaleType == u"京东新人1分购":
  5725. dealer = Dealer.objects.get(id=dealerId)
  5726. if not dealer.isJosEnable():
  5727. return JsonResponse({"result": 0, "description": u"抱歉,您暂时无法配置此项活动,详情请咨询平台方"})
  5728. # 检查活动的设备类型是否匹配
  5729. onsaleType = onsale.onsaleType
  5730. expression = OnSale.onsaleTypeDict[onsaleType]['expression']
  5731. onsale.onClickUrl = OnSale.onsaleTypeDict[onsaleType]['onClickUrl']
  5732. onsale.showType = OnSale.onsaleTypeDict[onsaleType]['showType']
  5733. if expression:
  5734. for lc in onsale.logicalCodeList:
  5735. dev = Device.get_dev_by_logicalCode(lc)
  5736. if dev is None:
  5737. continue
  5738. if not eval(expression):
  5739. return JsonResponse({'result': 0, 'description': u'编码为:%s的设备类型不符合本次活动的要求,请去掉该设备哦' % lc, 'payload': {}})
  5740. onsale.dealerId = str(request.user.bossId)
  5741. onsale.save()
  5742. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  5743. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5744. @permission_required(ROLE.dealer, ROLE.subaccount)
  5745. def deleteOnsale(request):
  5746. # type: (WSGIRequest)->JsonResponse
  5747. payload = json.loads(request.body)
  5748. onsaleId = payload.get('id')
  5749. if not onsaleId:
  5750. return JsonErrorResponse(description=u'数据不完整,请刷新')
  5751. obj = OnSale.objects.get(id=onsaleId)
  5752. obj.delete()
  5753. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  5754. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,删除失败,请您重试'))
  5755. @permission_required(ROLE.dealer, ROLE.subaccount)
  5756. def editOnsale(request):
  5757. # type: (WSGIRequest)->JsonResponse
  5758. payload = json.loads(request.body) if request.body else {}
  5759. if not payload:
  5760. return JsonErrorResponse(description=u'发送的编辑数据为空')
  5761. payload['startTime'] = to_datetime(payload['startTime'] + ' 00:00:00')
  5762. payload['endTime'] = to_datetime(payload['endTime'] + ' 23:59:59')
  5763. obj = OnSale.objects.get(id=payload['id'])
  5764. obj.update(**payload)
  5765. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  5766. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5767. @permission_required(ROLE.dealer, ROLE.subaccount)
  5768. def getOnsaleRecord(request):
  5769. # type: (WSGIRequest)->JsonResponse
  5770. pageIndex = int(request.GET.get('pageIndex', 1))
  5771. pageSize = int(request.GET.get('pageSize', 10))
  5772. startTimeStr = request.GET.get('startTime', None)
  5773. if not startTimeStr:
  5774. return JsonErrorResponse(description=u'数据为空,请重试')
  5775. startTime = to_datetime(startTimeStr + ' 00:00:00')
  5776. endTimeStr = request.GET.get('endTime', 10)
  5777. endTime = to_datetime(endTimeStr + ' 23:59:59')
  5778. onsaleId = request.GET.get('onsaleId', None)
  5779. rcds = OnSaleRecord.objects.filter(onsaleId=onsaleId, addedTime__gte=startTime, addedTime__lte=endTime)
  5780. dataList = []
  5781. countDict = {}
  5782. for rcd in rcds:
  5783. data = {'clickTime': rcd.addedTime.strftime(Const.DATETIME_FMT)}
  5784. desc = u'用户:%s,' % rcd.nickName
  5785. if rcd.onsaleDetail.has_key('coins'):
  5786. desc += u' 领取%s个金币' % rcd.onsaleDetail['coins']
  5787. if rcd.onsaleDetail.has_key('duration'):
  5788. desc += u' 启动免费体验%s分钟' % rcd.onsaleDetail['duration']
  5789. if rcd.onsaleDetail.has_key('phoneNumber'):
  5790. desc += u' 手机号码:%s' % rcd.onsaleDetail['phoneNumber']
  5791. data['description'] = desc
  5792. data.update(rcd.onsaleDetail)
  5793. for k, v in rcd.onsaleDetail.items():
  5794. countKey = '%sTotal' % k
  5795. if countDict.has_key(countKey):
  5796. countDict[countKey] += v
  5797. else:
  5798. countDict[countKey] = v
  5799. dataList.append(data)
  5800. return JsonResponse(
  5801. {
  5802. 'result': 1,
  5803. 'description': '',
  5804. 'payload':
  5805. {
  5806. 'total': len(dataList),
  5807. 'dataList': dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize],
  5808. 'countDict': countDict
  5809. }
  5810. })
  5811. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'创意文件存储失败,请重新试试'))
  5812. @permission_required(ROLE.dealer, ROLE.subaccount)
  5813. def uploadCreative(request):
  5814. # type: (WSGIRequest)->JsonResponse
  5815. files = request.FILES.getlist('file')
  5816. if not len(files):
  5817. return JsonResponse({'result': 0, 'description': u'未找到上传的创意文件,请重新试试', 'payload': {}})
  5818. uploader = AliOssFileUploader(inputFile=request.FILES.getlist('file')[0], uploadType='creative')
  5819. logger.info('[uploadItemPic] %s is being used' % (repr(uploader),))
  5820. try:
  5821. outputUrl = uploader.upload()
  5822. return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl})
  5823. except InvalidFileSize, e:
  5824. logger.info(
  5825. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  5826. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5827. except InvalidFileName, e:
  5828. logger.info(
  5829. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  5830. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5831. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'状态更新错误,请刷新页面重新试试'))
  5832. @permission_required(ROLE.dealer, ROLE.subaccount)
  5833. def toggleOnsale(request):
  5834. # type: (WSGIRequest)->JsonResponse
  5835. payload = json.loads(request.body)
  5836. status = payload.get('status')
  5837. onsaleId = payload.get('id')
  5838. onsale = OnSale.objects.get(id=onsaleId)
  5839. onsale.status = status
  5840. onsale.save()
  5841. return JsonResponse({'result': 1, 'description': '', 'payload': ''})
  5842. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取价格失败,请刷新页面重新试试'))
  5843. @permission_required(ROLE.dealer, ROLE.subaccount)
  5844. def getPricePerHour(request):
  5845. # type: (WSGIRequest)->JsonResponse
  5846. lc = request.GET.get('logicalCode')
  5847. dev = Device.objects.get(logicalCode=lc)
  5848. return JsonResponse({'result': 1, 'description': '', 'payload': dev.otherConf.get('pricePerHour', 2.0)})
  5849. @permission_required(ROLE.dealer, ROLE.subaccount)
  5850. def setBatchDevsSwitch(request):
  5851. # type: (WSGIRequest)->JsonResponse
  5852. data = json.loads(request.body) if request.body else {}
  5853. if not data:
  5854. return JsonErrorResponse(u'数据为空,请重试')
  5855. lcs = data['logicalCodes']
  5856. isFault = data['isFault']
  5857. objs = Device.objects.filter(devNo__in=lcs)
  5858. for obj in objs:
  5859. dev = Device.get_dev(obj.devNo)
  5860. obj.isFault = isFault
  5861. try:
  5862. box = ActionDeviceBuilder.create_action_device(dev)
  5863. box.set_dev_fault(isFault)
  5864. obj.save()
  5865. Device.invalid_device_cache(obj.devNo)
  5866. except Exception as e:
  5867. logger.exception(e)
  5868. continue
  5869. return JsonResponse({"result": 1, "description": "", "payload": {}})
  5870. # 批量设置退费保护时间
  5871. @permission_required(ROLE.dealer, ROLE.subaccount)
  5872. def setBatchRefundProtectionTime(request):
  5873. # type: (WSGIRequest)->JsonResponse
  5874. data = json.loads(request.body) if request.body else {}
  5875. if not data:
  5876. return JsonErrorResponse(u'数据为空,请重试')
  5877. lcs = data['logicalCodes']
  5878. refundProtectionTime = data['refundProtectionTime']
  5879. try:
  5880. Device.objects.filter(devNo__in=lcs).update(refundProtectionTime=refundProtectionTime).select_for_update()
  5881. except Exception as e:
  5882. logger.exception(e)
  5883. @permission_required(ROLE.dealer, ROLE.subaccount)
  5884. def getCardTicketTypeList(request):
  5885. # type: (WSGIRequest)->JsonResponse
  5886. objs = VirtualCard.objects.filter(ownerId=str(request.user.bossId))
  5887. dataList = []
  5888. for obj in objs:
  5889. # if '*' in obj.groupIDs:
  5890. # groupIds = Group.get_group_ids_of_dealer(str(request.user.id))
  5891. # else:
  5892. # groupIds = obj.groupIds
  5893. data = {
  5894. 'cardName': obj.cardName,
  5895. 'price': obj.price,
  5896. 'groupIds': obj.groupIds,
  5897. 'periodDays': obj.periodDays,
  5898. 'expiredTime': obj.expiredTime.strftime('%Y-%m-%d'),
  5899. 'dayQuota': obj.dayQuota,
  5900. 'quota': obj.quota,
  5901. 'userLimit': obj.userLimit,
  5902. 'userDesc': obj.userDesc,
  5903. 'dealerDesc': obj.dealerDesc
  5904. }
  5905. dataList.append(data)
  5906. return JsonResponse({"result": 1, "description": '', "payload": {'datalist': dataList}})
  5907. @error_tolerate(nil=JsonErrorResponse(u"获取虚拟卡列表失败"))
  5908. @permission_required(ROLE.dealer, ROLE.subaccount)
  5909. def getCardTicketList(request):
  5910. """
  5911. 经销商 优惠卡卷列表
  5912. 可通过卡名称搜索
  5913. 可通过 售卡状态 卡使用地址进行筛选
  5914. :param request:
  5915. :return:
  5916. """
  5917. pageIndex = int(request.GET.get('pageIndex', 1))
  5918. pageSize = int(request.GET.get('pageSize', 10))
  5919. status = request.GET.get("status") # 卡状态
  5920. groupId = request.GET.get("groupId") # 地址ID
  5921. searchKey = request.GET.get("searchKey") # 卡名称
  5922. # 没有传递状态 则是全部的可用状态
  5923. statusList = [int(status)] if status else [0, 1]
  5924. filters = {"ownerId": str(request.user.bossId), "status__in": statusList}
  5925. # 传递了地址的情况 则全选地址的 和单独选择的都要算上
  5926. if groupId:
  5927. filters.update({"groupIds__in": ["*", groupId]})
  5928. objs = VirtualCard.objects.filter(**filters)
  5929. if searchKey:
  5930. objs = objs.search(searchKey, ["cardName"])
  5931. total = objs.count()
  5932. dataList = []
  5933. for obj in objs.skip((pageIndex - 1) * pageSize).limit(pageSize):
  5934. dataList.append(obj.to_dict())
  5935. return JsonResponse({"result": 1, "description": '', "payload": {'total': total, 'pageSize': pageSize, 'dataList': dataList}})
  5936. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'添加失败,请重新试试'))
  5937. @permission_required(ROLE.dealer, ROLE.subaccount)
  5938. def addTicketCard(request):
  5939. def sort_quota(qArray): # type:(list) -> list
  5940. # 首先检查单位是否重复 对于重复的单位叠加处理
  5941. qDict = defaultdict(int)
  5942. for _item in qArray:
  5943. _count, _unit = _item["count"], _item["unit"]
  5944. qDict[_unit] += int(_count)
  5945. if len(qDict) != len(qArray):
  5946. raise ServiceException({"result": 2, "description": u"额度设置错误,额度单位重复"})
  5947. return sorted(qArray, key=lambda x: x["unit"])
  5948. if not request.body:
  5949. return JsonErrorResponse(description=u'传入数据为空')
  5950. payload = json.loads(request.body)
  5951. cardId = payload.get("cardId")
  5952. cardName = payload["cardName"]
  5953. userDesc = payload["userDesc"]
  5954. userLimit = int(payload["userLimit"])
  5955. periodDays = float(payload["periodDays"])
  5956. try:
  5957. expiredTime = to_datetime(payload['expiredTime'] + ' 23:59:59')
  5958. except Exception as e:
  5959. expiredTime = to_datetime(payload['expiredTime'])
  5960. devTypeList = payload["devTypeList"]
  5961. groups = ['*'] if payload['groups'] == '*' else [grp['groupId'] for grp in payload['groups']]
  5962. price = RMB(payload["price"])
  5963. power = int(payload["power"])
  5964. try:
  5965. dayQuota = sort_quota(payload["dayQuota"])
  5966. quota = sort_quota(payload["quota"])
  5967. except ServiceException as e:
  5968. return JsonErrorResponse(description=e.result["description"])
  5969. if cardId:
  5970. try:
  5971. card = VirtualCard.objects.get(id=cardId)
  5972. except DoesNotExist:
  5973. return JsonErrorResponse(description=u"编辑虚拟卡卷失败")
  5974. if card.ownerId != str(request.user.bossId):
  5975. return JsonErrorResponse(description=u"保存失败,请重新尝试")
  5976. else:
  5977. card = VirtualCard()
  5978. card.update(
  5979. cardName=cardName, userDesc=userDesc, userLimit=userLimit, periodDays=periodDays,
  5980. expiredTime=expiredTime, devTypeList=devTypeList, groupIds=groups, price=price,
  5981. power=power, dayQuota=dayQuota, quota=quota, ownerId=str(request.user.bossId),
  5982. upsert=True
  5983. )
  5984. return JsonOkResponse()
  5985. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除失败,请重新试试'))
  5986. @permission_required(ROLE.dealer, ROLE.subaccount)
  5987. def deleteCardTicket(request):
  5988. # type: (WSGIRequest)->JsonResponse
  5989. if not request.body: return JsonErrorResponse(description=u'传入数据为空')
  5990. payload = json.loads(request.body)
  5991. cardId = payload['id']
  5992. try:
  5993. VirtualCard.get_collection().update({'_id': ObjectId(cardId)}, {'$set': {'status':-1}})
  5994. return JsonResponse({"result": 1, "description": "", "payload": {}})
  5995. except Exception as e:
  5996. logger.exception('update error=%s' % e)
  5997. return JsonResponse({"result": 0, "description": u"删除失败,请您稍后重试", "payload": {}})
  5998. @permission_required(ROLE.dealer, ROLE.subaccount)
  5999. def switchCardTicket(request):
  6000. # type: (WSGIRequest)->JsonResponse
  6001. if not request.body: return JsonErrorResponse(description=u'传入数据为空')
  6002. payload = json.loads(request.body)
  6003. cardId = payload['id']
  6004. try:
  6005. vCard = VirtualCard.objects.get(id=cardId)
  6006. vCard.status = 1 if vCard.status == 0 else 0
  6007. vCard.save()
  6008. return JsonResponse({"result": 1, "description": "", "payload": {}})
  6009. except Exception as e:
  6010. logger.exception('switchCardTicket error=%s' % e)
  6011. return JsonResponse({"result": 0, "description": u"切换虚拟卡的状态失败,请您刷新页面后重试", "payload": {}})
  6012. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除失败,请重新试试'))
  6013. @permission_required(ROLE.dealer, ROLE.subaccount)
  6014. def delUserVirtualCard(request):
  6015. payload = json.loads(request.body)
  6016. cardId = payload.get("cardId")
  6017. if not cardId:
  6018. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6019. try:
  6020. vCard = UserVirtualCard.objects.get(id=cardId)
  6021. except DoesNotExist:
  6022. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6023. if vCard.dealerId != str(request.user.id):
  6024. return JsonErrorResponse(u"不是您的虚拟卡,无权删除")
  6025. record = AdjustUserVirtualCardRecord(
  6026. cardId=cardId,
  6027. cardNo=vCard.cardNo,
  6028. beforeAdjust=vCard.expiredTime,
  6029. operator=str(request.user.id),
  6030. dealerId=str(request.user.bossId),
  6031. adjustType=TYPE_ADJUST_USER_VIRTUAL_CARD.DELETE,
  6032. oldQuota=vCard.quota,
  6033. adjustQuota=[{"count": 0, "unit": vCard.quota[0].get("unit")}]
  6034. )
  6035. vCard.delete()
  6036. record.save()
  6037. return JsonOkResponse(description=u"删除成功")
  6038. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'调整失败,请重新试试'))
  6039. @permission_required(ROLE.dealer, ROLE.subaccount)
  6040. def adjustUserVirtualCardTime(request):
  6041. payload = json.loads(request.body)
  6042. cardId = payload.get("cardId", "")
  6043. days = int(payload.get("days", 0))
  6044. if not days:
  6045. return JsonErrorResponse(description=u"您调整的时间没有变化")
  6046. if not cardId:
  6047. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6048. try:
  6049. vCard = UserVirtualCard.objects.get(id=cardId)
  6050. except DoesNotExist:
  6051. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6052. if vCard.dealerId != str(request.user.id):
  6053. return JsonErrorResponse(u"不是您的虚拟卡,无权修改")
  6054. record = AdjustUserVirtualCardRecord(
  6055. cardId=cardId,
  6056. cardNo=vCard.cardNo,
  6057. beforeAdjust=vCard.expiredTime,
  6058. operator=str(request.user.id),
  6059. dealerId=str(request.user.bossId),
  6060. adjustType=TYPE_ADJUST_USER_VIRTUAL_CARD.ADJUST_DAYS,
  6061. adjustDays=days,
  6062. oldQuota=vCard.quota,
  6063. adjustQuota=[{"count": 0, "unit": vCard.quota[0].get("unit")}]
  6064. )
  6065. vCard.expiredTime = vCard.expiredTime + datetime.timedelta(days=days)
  6066. vCard.save()
  6067. record.save()
  6068. return JsonOkResponse(description=u"操作成功,虚拟卡{}过期调整过期时间{}天".format(str(vCard.id), days))
  6069. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'调整失败,请重新试试'))
  6070. @permission_required(ROLE.dealer, ROLE.subaccount)
  6071. def adjustUserVirtualCardQuota(request):
  6072. """
  6073. 调整虚拟卡额度
  6074. :param request:
  6075. :return:
  6076. """
  6077. payload = json.loads(request.body)
  6078. cardId = payload.get("cardId", "")
  6079. quota = payload.get("quota")
  6080. dayQuota = payload.get("dayQuota")
  6081. if not cardId:
  6082. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6083. if not all([quota, dayQuota]):
  6084. return JsonErrorResponse(description="参数不全")
  6085. try:
  6086. vCard = UserVirtualCard.objects.get(id=cardId)
  6087. except DoesNotExist:
  6088. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6089. vCard.quota = quota
  6090. vCard.dayQuota = dayQuota
  6091. for _item in vCard.quota:
  6092. _item["count"] = float(_item["count"])
  6093. for _item in vCard.dayQuota:
  6094. _item["count"] = float(_item["count"])
  6095. vCard.save()
  6096. return JsonOkResponse(description=u"操作成功,虚拟卡{}调整额度成功")
  6097. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"调整失败,请重新试试"))
  6098. @permission_required(ROLE.dealer, ROLE.subaccount)
  6099. def adjustUserVirtualState(request):
  6100. """
  6101. 修改虚拟卡 的状态 主要是冻结/非冻结 霍珀需求
  6102. 这个操作状态就不放入调整记录了
  6103. :param request:
  6104. :return:
  6105. """
  6106. payload = json.loads(request.body)
  6107. cardId = payload.get("id", "")
  6108. if not cardId:
  6109. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6110. try:
  6111. vCard = UserVirtualCard.objects.get(id=cardId)
  6112. except DoesNotExist:
  6113. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6114. if vCard.status in ["normal", "warning"]:
  6115. vCard.status = "frozen"
  6116. else:
  6117. vCard.status = "normal"
  6118. vCard.save()
  6119. return JsonOkResponse(description=u"操作成功")
  6120. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'读取失败,请重新试试'))
  6121. @permission_required(ROLE.dealer, ROLE.subaccount)
  6122. def userVirtualCardAdjustRecord(request):
  6123. pageIndex = int(request.GET.get("pageIndex", 1))
  6124. pageSize = int(request.GET.get("pageSize", 10))
  6125. searchKey = request.GET.get("searchKey")
  6126. _type = request.GET.get("type")
  6127. startTime = request.GET.get("startTime")
  6128. endTime = request.GET.get("endTime")
  6129. matchFilters = {"dealerId": str(request.user.bossId)}
  6130. if _type:
  6131. if _type not in Const.TYPE_ADJUST_USER_VIRTUAL_CARD.choices():
  6132. return JsonErrorResponse(description=u"筛选种类错误,无此相关记录")
  6133. else:
  6134. matchFilters.update({"adjustType": _type})
  6135. if startTime:
  6136. startDataTime = to_datetime(startTime + ' 00:00:00', "%Y-%m-%d %H:%M:%S")
  6137. now = datetime.datetime.now()
  6138. if not endTime:
  6139. endDateTime = now + datetime.timedelta(days=1)
  6140. else:
  6141. endDateTime = to_datetime(endTime, "%Y-%m-%d")
  6142. if endDateTime > now:
  6143. endDateTime = now
  6144. endDateTime = endDateTime + datetime.timedelta(days=1)
  6145. if startDataTime >= endDateTime:
  6146. endDateTime = startDataTime + datetime.timedelta(days=1)
  6147. matchFilters.update(
  6148. {
  6149. "dateTimeAdded": {
  6150. "$gte": startDataTime,
  6151. "$lte": endDateTime
  6152. }
  6153. }
  6154. )
  6155. if searchKey:
  6156. matchFilters.update({
  6157. "cardNo": searchKey
  6158. })
  6159. records = AdjustUserVirtualCardRecord.get_collection().find(
  6160. matchFilters
  6161. ).sort(
  6162. [("dateTimeAdded", -1)]
  6163. ).skip(
  6164. pageSize * (pageIndex - 1)
  6165. ).limit(
  6166. pageSize
  6167. )
  6168. data = []
  6169. for record in records:
  6170. oldQuota = record.get("oldQuota")[0]
  6171. adjustQuota = record.get("adjustQuota")[0]
  6172. newQuota = {
  6173. "count" :oldQuota.get("count") + adjustQuota.get("count"),
  6174. "unit": oldQuota.get("unit")
  6175. }
  6176. dealerId = record.get("operator")
  6177. dealer = Dealer.get_dealer(dealerId)
  6178. operator = dealer.get("nickname") or dealer.get("username")
  6179. data.append(
  6180. {
  6181. "cardId": record.get("cardId"),
  6182. "cardNo": record.get("cardNo"),
  6183. "beforeAdjustExpired": record.get("beforeAdjust").strftime("%Y-%m-%d %H:%M:%S"),
  6184. "afterAdjustExpired": (record.get("beforeAdjust") + datetime.timedelta(days=record.get("adjustDays"))).strftime("%Y-%m-%d %H:%M:%S"),
  6185. "beforeAdjustQuota": "{} {}".format(oldQuota.get("count"), oldQuota.get("unit")),
  6186. "afterAdjustQuota": "{} {}".format(newQuota.get("count"), oldQuota.get("unit")),
  6187. "operator": operator,
  6188. "adjustType": record.get("adjustType"),
  6189. "adjustDate": record.get("dateTimeAdded")
  6190. }
  6191. )
  6192. return JsonOkResponse(payload={"total": 10000, "dataList": data})
  6193. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'读取失败,请重新试试'))
  6194. @permission_required(ROLE.dealer, ROLE.subaccount)
  6195. def getUserCardTicketList(request):
  6196. """
  6197. 经销商获取 已经发售的虚拟卡
  6198. 可以通过卡号搜索
  6199. 可以通过根据发卡地址来筛选 groupId
  6200. 可以通过卡类型筛选 dealerCardTypeId
  6201. 可以通过卡的状态来筛选 status 0(没过期 ) 1(过期)
  6202. :param request:
  6203. :return:
  6204. """
  6205. pageIndex = int(request.GET.get('pageIndex', 1))
  6206. pageSize = int(request.GET.get('pageSize', 10))
  6207. searchKey = request.GET.get('searchKey', '')
  6208. dealerCardTypeId = request.GET.get("dealerCardTypeId")
  6209. status = request.GET.get("status")
  6210. groupId = request.GET.get("groupId")
  6211. userId = str(request.GET.get('userId', ''))
  6212. isEmptyCard = int(request.GET.get('isEmptyCard', 0))
  6213. if isEmptyCard:
  6214. objs = VirtualCardBuilder.find_dealer_virtual_card(str(request.user.id)).order_by('-id')
  6215. else:
  6216. filters = {
  6217. "dealerId": str(request.user.bossId)
  6218. }
  6219. # 添加筛选条件
  6220. if userId:
  6221. filters.update({"openIds__contains": userId})
  6222. if groupId:
  6223. filters.update({"groupIds__in": ["*", groupId]})
  6224. if dealerCardTypeId:
  6225. filters.update({"cardTypeId": dealerCardTypeId})
  6226. if status:
  6227. nowTime = datetime.datetime.now()
  6228. status = int(status)
  6229. filters.update({"expiredTime__gt": nowTime}) if status else filters.update({"expiredTime__lt": nowTime})
  6230. objs = UserVirtualCard.objects.filter(**filters).order_by('-startTime')
  6231. if searchKey:
  6232. objs = objs.search(searchKey)
  6233. total = objs.count()
  6234. dataList = []
  6235. for obj in objs.skip((pageIndex - 1) * pageSize).limit(pageSize):
  6236. data = obj.to_dict()
  6237. data.update(obj.quotaInfo)
  6238. dataList.append(data)
  6239. return JsonResponse({"result": 1, "description": '', "payload": {'total': total, 'dataList': dataList}})
  6240. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"读取失败,请重新试试"))
  6241. @permission_required(ROLE.dealer, ROLE.subaccount)
  6242. def getUserCardTicketDetail(request):
  6243. """
  6244. 获取用户的
  6245. :param request:
  6246. :return:
  6247. """
  6248. cardId = request.GET.get("cardId", "")
  6249. try:
  6250. vCard = UserVirtualCard.objects.get(id=cardId)
  6251. except DoesNotExist:
  6252. return JsonErrorResponse(description=u"查询错误,请刷新页面重试")
  6253. data = vCard.to_detail()
  6254. data.update({"frozenState": not vCard.status in ["normal", "warning"]})
  6255. return JsonOkResponse(payload=data)
  6256. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"备注失败,请重新试试"))
  6257. @permission_required(ROLE.dealer, ROLE.subaccount)
  6258. def remarkUserVirtual(request):
  6259. """
  6260. 霍珀需求 经销商为已发卡卷添加备注
  6261. :param request:
  6262. :return:
  6263. """
  6264. payload = json.loads(request.body)
  6265. cardId = payload.get("cardId")
  6266. remark = payload.get("remark")
  6267. dealerId = str(request.user.bossId)
  6268. try:
  6269. vCard = UserVirtualCard.objects.get(id=cardId)
  6270. except DoesNotExist:
  6271. return JsonErrorResponse(description=u"虚拟卡备注失败,请刷新页面试试")
  6272. if vCard.dealerId != dealerId:
  6273. return JsonErrorResponse(description=u"不是您的虚拟卡您无权修改")
  6274. vCard.update(remark=remark)
  6275. return JsonOkResponse()
  6276. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'读取失败,请重新试试'))
  6277. @permission_required(ROLE.dealer, ROLE.subaccount)
  6278. def getElcPriceModList(request):
  6279. dealerId = str(request.user.bossId)
  6280. objs = ElecPriceTemplate.objects.filter(ownerId=dealerId)
  6281. resultList = [{'id': str(obj.id), 'name': obj.name, 'price': obj.priceList} for obj in objs]
  6282. return JsonResponse({"result": 1, "description": '', "payload": resultList})
  6283. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存失败,请重新试试'))
  6284. @permission_required(ROLE.dealer, ROLE.subaccount)
  6285. def saveElcPriceMod(request):
  6286. dealerId = str(request.user.bossId)
  6287. payload = json.loads(request.body)
  6288. priceList = payload['price']
  6289. logicalCode = payload['logicalCode']
  6290. newName = payload.get('name', None)
  6291. dev = Device.get_dev_by_logicalCode(logicalCode)
  6292. group = Group.get_group(dev['groupId'])
  6293. if newName is None:
  6294. newName = group['groupName'] + datetime.datetime.now().strftime('%Y%m%d%H%M%S')
  6295. newObj = ElecPriceTemplate(ownerId=dealerId,
  6296. name=newName,
  6297. priceList=priceList)
  6298. newObj.save()
  6299. return JsonResponse({"result": 1, "description": '', "payload": None})
  6300. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存失败,请重新试试'))
  6301. @permission_required(ROLE.dealer, ROLE.subaccount)
  6302. def saveDeviceElcPrice(request):
  6303. """
  6304. 这个是 用心汽车桩专用的 保存汽车的电价设置
  6305. """
  6306. payload = json.loads(request.body)
  6307. priceList = payload['price']
  6308. logicalCode = payload['logicalCode']
  6309. from apps.web.core.device_define.yongxin import DefaultParams
  6310. if len(priceList) != DefaultParams.DEFAULT_ELEC_PRICE_INTERVAL_NUM:
  6311. return JsonErrorResponse(description=u"电价参数设置错误,请重新试试")
  6312. if filter(lambda x: int(x * 100) > DefaultParams.DEFAULT_MAX_ELEC_PRICE, priceList):
  6313. return JsonErrorResponse(description=u"电价最大为2.55元")
  6314. device = Device.objects.get(logicalCode=logicalCode)
  6315. device.otherConf['priceList'] = priceList
  6316. device.save()
  6317. Device.invalid_device_cache(device.devNo)
  6318. return JsonOkResponse()
  6319. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除电价失败,请重新试试'))
  6320. @permission_required(ROLE.dealer, ROLE.subaccount)
  6321. def deleteElcPriceMod(request):
  6322. payload = json.loads(request.body)
  6323. ids = [ObjectId(_) for _ in payload['id']]
  6324. ElecPriceTemplate.get_collection().remove({'_id': {'$in': ids}})
  6325. return JsonResponse({"result": 1, "description": '', "payload": None})
  6326. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'上传的商品图片存储失败,请重新试试'))
  6327. @permission_required(ROLE.dealer, ROLE.subaccount)
  6328. def uploadItemPic(request):
  6329. # type: (WSGIRequest)->JsonResponse
  6330. files = request.FILES.getlist('file')
  6331. if not len(files):
  6332. return JsonResponse({'result': 0, 'description': u'未找到上传的商品图片,请重新试试', 'payload': {}})
  6333. uploader = AliOssFileUploader(inputFile=request.FILES.getlist('file')[0], uploadType='item')
  6334. logger.info('[uploadItemPic] %s is being used' % (repr(uploader),))
  6335. try:
  6336. outputUrl = uploader.upload()
  6337. return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl})
  6338. except InvalidFileSize, e:
  6339. logger.info(
  6340. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  6341. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  6342. except InvalidFileName, e:
  6343. logger.info(
  6344. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  6345. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  6346. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'编辑商品类型失败,请重新试试'))
  6347. @permission_required(ROLE.dealer, ROLE.subaccount)
  6348. def addEditItemType(request):
  6349. payload = json.loads(request.body)
  6350. ownerId = str(request.user.bossId)
  6351. itemId = payload.get('id', None)
  6352. title = payload.get('name', None)
  6353. desc = payload.get('description', None)
  6354. picUrl = payload.get('img', "")
  6355. price = 100 * payload.get('price')
  6356. try:
  6357. if itemId is not None:
  6358. obj = ItemType.objects.get(id=itemId)
  6359. obj.title, obj.desc, obj.picUrl, obj.price = title, desc, picUrl, price
  6360. obj.save()
  6361. else:
  6362. newObj = ItemType(ownerId=ownerId, title=title, desc=desc, picUrl=picUrl, price=price)
  6363. newObj.save()
  6364. itemId = str(newObj.id)
  6365. except DoesNotExist:
  6366. newObj = ItemType(ownerId=ownerId, title=title, desc=desc, picUrl=picUrl, price=price)
  6367. newObj.save()
  6368. itemId = str(newObj.id)
  6369. except Exception as e:
  6370. logger.exception(e)
  6371. return JsonErrorResponse(description=u'未知错误')
  6372. return JsonResponse({"result": 1, "description": '', "payload": {"id": itemId}})
  6373. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除商品类型失败,请重新试试'))
  6374. @permission_required(ROLE.dealer, ROLE.subaccount)
  6375. def deleteItemType(request):
  6376. payload = json.loads(request.body)
  6377. ids = payload.get('ids', [])
  6378. itemIds = [ObjectId(obj) for obj in ids]
  6379. try:
  6380. ItemType.get_collection().remove({'_id': {'$in': itemIds}})
  6381. except Exception as e:
  6382. logger.exception(e)
  6383. return JsonErrorResponse(description=u'未知错误')
  6384. return JsonResponse({"result": 1, "description": '', "payload": None})
  6385. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取商品类型失败,请重新试试'))
  6386. @permission_required(ROLE.dealer, ROLE.subaccount)
  6387. def getItemTypes(request):
  6388. ownerId = str(request.user.bossId)
  6389. itemTypeId = request.GET.get('itemTypeId', '')
  6390. if itemTypeId:
  6391. objs = ItemType.objects.filter(ownerId=ownerId, id=itemTypeId)
  6392. else:
  6393. objs = ItemType.objects.filter(ownerId=ownerId)
  6394. dataList = [{'id': str(obj.id),
  6395. 'name': obj.title,
  6396. 'description': obj.desc,
  6397. 'img': obj.picUrl,
  6398. 'price': float(obj.price) / 100.0} for obj in objs
  6399. ]
  6400. return JsonResponse({"result": 1, "description": '', "payload": {'dataList': dataList}})
  6401. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'编辑格子失败'))
  6402. @permission_required(ROLE.dealer, ROLE.subaccount)
  6403. def addEditCell(request):
  6404. payload = json.loads(request.body)
  6405. logicalCode = payload.get('logicalCode')
  6406. cellId = payload.get('id', None)
  6407. cellNo = payload.get('cellNo')
  6408. boardNo = int(payload.get('boardNo'))
  6409. lockNo = int(payload.get('lockNo'))
  6410. itemTitle = payload.get('itemTitle', '')
  6411. itemDesc = payload.get('itemDesc', '')
  6412. itemPicUrl = payload.get('itemPicUrl', '')
  6413. itemPrice = payload.get('itemPrice') * 100
  6414. try:
  6415. if cellId is not None:
  6416. obj = Cell.objects.get(id=cellId)
  6417. obj.cellNo, obj.boardNo, obj.lockNo, obj.itemTitle, obj.itemDesc, obj.itemPicUrl, obj.itemPrice = cellNo, boardNo, lockNo, itemTitle, itemDesc, itemPicUrl, itemPrice
  6418. obj.save()
  6419. else:
  6420. newObj = Cell(logicalCode=logicalCode, cellNo=cellNo, boardNo=boardNo, lockNo=lockNo, itemTitle=itemTitle,
  6421. itemDesc=itemDesc, itemPicUrl=itemPicUrl, itemPrice=itemPrice)
  6422. newObj.save()
  6423. cellId = str(newObj.id)
  6424. except DoesNotExist, e:
  6425. newObj = Cell(logicalCode=logicalCode, cellNo=cellNo, boardNo=boardNo, lockNo=lockNo, itemTitle=itemTitle,
  6426. itemDesc=itemDesc, itemPicUrl=itemPicUrl, itemPrice=itemPrice)
  6427. newObj.save()
  6428. cellId = str(newObj.id)
  6429. except Exception, e:
  6430. return JsonErrorResponse(description=u'未知错误')
  6431. # 重新挂上washConfig套餐信息
  6432. cells = Cell.objects.filter(logicalCode=logicalCode)
  6433. washConfig = {}
  6434. for cell in cells:
  6435. washConfig[str(cell.id)] = {
  6436. 'name': cell.cellNo,
  6437. 'coins': float(cell.itemPrice / 100.0),
  6438. 'price': float(cell.itemPrice / 100.0),
  6439. 'time': 1,
  6440. 'description': cell.itemTitle,
  6441. 'imgList': [cell.itemPicUrl],
  6442. 'unit': u'次'
  6443. }
  6444. dev = Device.get_dev_by_logicalCode(logicalCode)
  6445. dev['washConfig'] = washConfig
  6446. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'washConfig': dev['washConfig']}})
  6447. Device.invalid_device_cache(dev['devNo'])
  6448. return JsonResponse({"result": 1, "description": '', "payload": {"id": cellId}})
  6449. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6450. @permission_required(ROLE.dealer, ROLE.subaccount)
  6451. def deleteCell(request):
  6452. payload = json.loads(request.body)
  6453. logicalCode = payload.get('logicalCode')
  6454. cellIds = payload.get('ids')
  6455. Cell.objects(id__in=cellIds).delete()
  6456. # 重新挂上washConfig套餐信息
  6457. cells = Cell.objects.filter(logicalCode=logicalCode)
  6458. washConfig = {}
  6459. for cell in cells:
  6460. washConfig[str(cell.id)] = {
  6461. 'name': cell.cellNo,
  6462. 'coins': float(cell.itemPrice / 100.0),
  6463. 'price': float(cell.itemPrice / 100.0),
  6464. 'time': 1,
  6465. 'description': cell.itemTitle,
  6466. 'imgList': [],
  6467. 'unit': u'次'
  6468. }
  6469. dev = Device.get_dev_by_logicalCode(logicalCode)
  6470. dev['washConfig'] = washConfig
  6471. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'washConfig': dev['washConfig']}})
  6472. Device.invalid_device_cache(dev['devNo'])
  6473. return JsonResponse({"result": 1, "description": '', "payload": None})
  6474. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'查询格子失败'))
  6475. @permission_required(ROLE.dealer, ROLE.subaccount)
  6476. def getDeviceCells(request):
  6477. logicalCode = request.GET.get('logicalCode')
  6478. pageIndex = int(request.GET.get('pageIndex', 1))
  6479. pageSize = int(request.GET.get('pageSize', 30))
  6480. objs = Cell.objects.filter(logicalCode=logicalCode)
  6481. dev = Device.get_dev_by_logicalCode(logicalCode)
  6482. box = ActionDeviceBuilder.create_action_device(dev)
  6483. lockStatusDict = box.get_all_lock_status()
  6484. dataList = []
  6485. quantity, consumptionQuantity = 0, 0
  6486. for obj in objs:
  6487. dataList.append(
  6488. {
  6489. 'id': str(obj.id), 'cellNo': obj.cellNo, 'boardNo': obj.boardNo,
  6490. 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle,
  6491. 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl,
  6492. 'itemPrice': round(obj.itemPrice / 100.0, 2),
  6493. 'lockStatus': lockStatusDict.get(obj.cellNo, 'close'),
  6494. 'quantity': 1 if obj.itemStatus == 'full' else 0
  6495. }
  6496. )
  6497. if obj.itemStatus == 'full':
  6498. quantity += 1
  6499. else:
  6500. consumptionQuantity += 1
  6501. dev['quantity'] = quantity
  6502. dev['consumptionQuantity'] = consumptionQuantity
  6503. Device.update_field(
  6504. dev_no=dev['devNo'],
  6505. update=True,
  6506. quantity=quantity,
  6507. consumptionQuantity=consumptionQuantity)
  6508. return JsonResponse({'result': 1, 'description': '',
  6509. 'payload': {'dataList': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]}})
  6510. def openManyCells(dev, strIds):
  6511. ids = [ObjectId(id) for id in strIds]
  6512. cellDict = {}
  6513. cells = Cell.objects.filter(id__in=ids)
  6514. for cell in cells:
  6515. if cellDict.has_key(str(cell.boardNo)):
  6516. cellDict[str(cell.boardNo)].append(cell.lockNo)
  6517. else:
  6518. cellDict[str(cell.boardNo)] = [cell.lockNo]
  6519. box = ActionDeviceBuilder.create_action_device(dev)
  6520. for boardNo, lockNos in cellDict.items():
  6521. try:
  6522. box.open_many_locks(boardNo, lockNos)
  6523. except Exception as e:
  6524. logger.exception(e)
  6525. return JsonResponse({"result": 0, "description": u'打开格子失败', "payload": None})
  6526. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6527. @permission_required(ROLE.dealer, ROLE.subaccount)
  6528. def addGoodsToDeviceCell(request):
  6529. payload = json.loads(request.body)
  6530. logicalCode = payload['logicalCode']
  6531. dev = Device.get_dev_by_logicalCode(logicalCode)
  6532. openManyCells(dev, payload['ids'])
  6533. ids = [ObjectId(strId) for strId in payload['ids']]
  6534. cells = Cell.objects.filter(id__in=ids)
  6535. for cell in cells:
  6536. cell.itemStatus = 'full'
  6537. try:
  6538. cell.save()
  6539. # 增加一条补货记录
  6540. newStock = StockRecord(
  6541. logicCode=dev['logicalCode'],
  6542. imei=dev['devNo'],
  6543. stockType='add',
  6544. stockTime=datetime.datetime.now().strftime(Const.DATETIME_FMT),
  6545. number=1,
  6546. more="%s:%s" % (cell.cellNo, cell.itemTitle)
  6547. )
  6548. newStock.save()
  6549. except Exception, e:
  6550. continue
  6551. Cell.update_dev_quantity_from_cell(dev)
  6552. return JsonResponse({"result": 1, "description": '', "payload": None})
  6553. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6554. @permission_required(ROLE.dealer, ROLE.subaccount)
  6555. def unlockCell(request):
  6556. payload = json.loads(request.body)
  6557. logicalCode = payload.get('logicalCode')
  6558. ids = payload.get('id')
  6559. dev = Device.get_dev_by_logicalCode(logicalCode)
  6560. openManyCells(dev, ids)
  6561. return JsonResponse({"result": 1, "description": '', "payload": None})
  6562. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6563. @permission_required(ROLE.dealer, ROLE.subaccount)
  6564. def getDeviceCellsFromDB(request):
  6565. logicalCode = request.GET.get('logicalCode')
  6566. pageIndex = int(request.GET.get('pageIndex', 1))
  6567. pageSize = int(request.GET.get('pageSize', 30))
  6568. objs = Cell.objects.filter(logicalCode=logicalCode)
  6569. dataList = []
  6570. quantity, consumptionQuantity = 0, 0
  6571. for obj in objs:
  6572. dataList.append(
  6573. {'id': str(obj.id), 'cellNo': obj.cellNo, 'boardNo': obj.boardNo,
  6574. 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle,
  6575. 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl,
  6576. 'itemPrice': round(obj.itemPrice / 100.0, 2),
  6577. # 'lockStatus':lockStatusDict.get(obj.cellNo,'close'),
  6578. 'quantity': 1 if obj.itemStatus == 'full' else 0}
  6579. )
  6580. if obj.itemStatus == 'full':
  6581. quantity += 1
  6582. else:
  6583. consumptionQuantity += 1
  6584. # TODO 为啥这两个参数只打内存,不更新到数据库
  6585. Device.get_and_update_device_cache(
  6586. dev_no=Device.get_dev_by_logicalCode(logicalCode)['devNo'],
  6587. quantity=quantity,
  6588. consumptionQuantity=consumptionQuantity)
  6589. return JsonResponse({'result': 1, 'description': '',
  6590. 'payload': {'dataList': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]}})
  6591. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取列表失败'))
  6592. @permission_required(ROLE.dealer, ROLE.subaccount)
  6593. def getOfflineTaskList(request):
  6594. # type: (WSGIRequest)->JsonResponse
  6595. current_user = request.user # type: Dealer
  6596. page_index = int(request.GET.get('pageIndex', 1))
  6597. page_size = int(request.GET.get('pageSize', 10))
  6598. search_key = request.GET.get('searchKey', None)
  6599. tasks = OfflineTask.objects(ownerId=current_user.id,
  6600. role=current_user.role).search(search_key).order_by('-dateTimeAdded')
  6601. total = tasks.count()
  6602. return JsonOkResponse(
  6603. payload={
  6604. 'dataList': [t.to_dict() for t in tasks.paginate(pageSize=page_size, pageIndex=page_index)],
  6605. 'total': total
  6606. })
  6607. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6608. @permission_required(ROLE.dealer, ROLE.subaccount)
  6609. def exportBusinessStats(request):
  6610. """
  6611. 经销商的手机 导出报表
  6612. :param request:
  6613. :return:
  6614. """
  6615. dealer = request.user # type: Dealer
  6616. request_get = request.GET.copy()
  6617. if 'kind' not in request_get:
  6618. request_get['kind'] = 'income'
  6619. if 'time' in request_get and (('startTime' not in request_get) or ('endTime' not in request_get)):
  6620. # 将月份转换成开始时间为1号,结束时间为当月最后一天,因为需要一个前闭后闭区间,所以最后一天日期减一天
  6621. request_get['startTime'] = datetime.datetime.strptime(request_get.pop('time')[0], "%Y-%m")
  6622. request_get['endTime'] = request_get['startTime'] + relativedelta(months=1) - datetime.timedelta(days=1)
  6623. request_get['startTime'] = request_get['startTime'].strftime(Const.DATE_FMT)
  6624. request_get['endTime'] = request_get['endTime'].strftime(Const.DATE_FMT)
  6625. query = prepare_query(request_get) # type: Query
  6626. def get_offline_task_name(task_type, user, **kwargs):
  6627. # type: (basestring, Dealer, Dict)->basestring
  6628. type_desc_map = {
  6629. 'income': u'收益',
  6630. 'consume': u'消费',
  6631. 'monthly_bill': u'月度'
  6632. }
  6633. tmp_list = [task_type, type_desc_map.get(kwargs['kind']), user.username]
  6634. if 'logicalCode' in kwargs:
  6635. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  6636. if 'groupId' in kwargs:
  6637. address = Group.get_group(kwargs['groupId']).get('address', '')
  6638. tmp_list.append(u'地址_%s' % (address,))
  6639. if 'source' in kwargs:
  6640. kind = kwargs.get('kind')
  6641. if kind == 'income':
  6642. source_translation = DEALER_INCOME_SOURCE_TRANSLATION.get(kwargs['source'])
  6643. elif kind == 'consume':
  6644. source_translation = DEALER_CONSUMPTION_AGG_KIND_TRANSLATION.get(kwargs['source'])
  6645. else:
  6646. source_translation = None
  6647. if source_translation:
  6648. tmp_list.append(source_translation)
  6649. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  6650. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  6651. return '-'.join(tmp_list).replace("/", "_")
  6652. # 此处生成的是 报表文件的名称
  6653. offline_task_name = get_offline_task_name(
  6654. task_type=OfflineTaskType.BUSINESS_REPORT,
  6655. user=dealer,
  6656. **query.raw)
  6657. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  6658. process_func_name='generate_business_stats_report_by_dealer',
  6659. task_type=OfflineTaskType.BUSINESS_REPORT,
  6660. userid=str(dealer.id),
  6661. role=ROLE.dealer)
  6662. queryAttrs = query.attrs
  6663. queryAttrs['dateTimeAdded__lte'] = dt_to_timestamp(queryAttrs['dateTimeAdded__lte'])
  6664. queryAttrs['dateTimeAdded__gte'] = dt_to_timestamp(queryAttrs['dateTimeAdded__gte'])
  6665. queryAttrs['dealerId'] = str(dealer.id)
  6666. task_caller(func_name=offline_task.process_func_name,
  6667. offline_task_id=str(offline_task.id),
  6668. filePath=file_path,
  6669. queryAttrs=queryAttrs)
  6670. return JsonOkResponse(payload=str(offline_task.id))
  6671. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6672. @permission_required(ROLE.dealer, ROLE.subaccount)
  6673. def exportAllTicketList(request):
  6674. """
  6675. 经销商的下的所以虚拟卡
  6676. :param request:
  6677. :return:
  6678. """
  6679. dealer = request.user # type: Dealer
  6680. timeStr = arrow.now().format('YYYY-MM-DD_HH:mm:ss')
  6681. offline_task_name = '已发虚拟卡_{}_{}_{}'.format(dealer.username, timeStr, random.randint(100000, 999999))
  6682. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  6683. process_func_name='export_vcard_info_excel_from_db',
  6684. task_type=OfflineTaskType.BUSINESS_REPORT,
  6685. userid=str(dealer.id),
  6686. role=ROLE.dealer)
  6687. queryDict = {}
  6688. queryDict['dealerId'] = str(dealer.id)
  6689. task_caller(func_name=offline_task.process_func_name,
  6690. offline_task_id=str(offline_task.id),
  6691. filepath=file_path,
  6692. queryDict=queryDict)
  6693. return JsonOkResponse(payload=str(offline_task.id))
  6694. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取收益列表失败"))
  6695. @permission_required(ROLE.dealer)
  6696. def getGroupUserAccountInfo(request):
  6697. """
  6698. 经销商下所有地址的用户充值,消费,余额情况
  6699. """
  6700. dealer = request.user # type: Dealer
  6701. def get_offline_task_name(task_type, user, **kwargs):
  6702. # type: (basestring, Dealer, Dict)->basestring
  6703. tmp_list = [task_type, user.username]
  6704. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  6705. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  6706. if 'groupId' in kwargs and kwargs['groupId']:
  6707. address = Group.get_group(kwargs['groupId']).get('address', '')
  6708. tmp_list.append(u'地址_%s' % (address,))
  6709. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  6710. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  6711. return '-'.join(tmp_list).replace("/", "_")
  6712. query_dict = {
  6713. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  6714. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  6715. 'ownerId': str(dealer.id)
  6716. }
  6717. offline_task_name = get_offline_task_name(
  6718. task_type=u'地址用户充值消费情况统计报表',
  6719. user=dealer,
  6720. **query_dict)
  6721. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  6722. process_func_name='export_group_user_account_excel_form_db',
  6723. task_type=OfflineTaskType.BUSINESS_REPORT,
  6724. userid=str(dealer.id),
  6725. role=ROLE.dealer)
  6726. task_caller(func_name=offline_task.process_func_name,
  6727. offline_task_id=str(offline_task.id),
  6728. filepath=file_path,
  6729. queryDict=query_dict)
  6730. return JsonResponse({
  6731. 'result': 1,
  6732. 'description': u"请前往离线任务查看任务处理情况",
  6733. 'payload': str(offline_task.id)})
  6734. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6735. @permission_required(ROLE.dealer, ROLE.subaccount)
  6736. def getOfflineTaskStatus(request):
  6737. # type: (WSGIRequest)->JsonResponse
  6738. """
  6739. :param request:
  6740. :return:
  6741. """
  6742. task_id = request.GET.get('id')
  6743. if not task_id:
  6744. return JsonErrorResponse(description=u'查询ID为空')
  6745. task = OfflineTask.objects(id=str(task_id)).get() # type: OfflineTask
  6746. return JsonOkResponse(payload=task.status)
  6747. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6748. @permission_required(ROLE.dealer, ROLE.subaccount)
  6749. def getSubAccountList(request):
  6750. pageIndex = int(request.GET.get('pageIndex', 1))
  6751. pageSize = int(request.GET.get('pageSize', 10))
  6752. subaccounts = SubAccount.objects.filter(bossId=str(request.user.bossId))
  6753. total = subaccounts.count()
  6754. dataList = []
  6755. for obj in subaccounts.skip((pageIndex - 1) * pageSize).limit(pageSize):
  6756. if obj.bossId == str(obj.id):
  6757. continue
  6758. dataList.append({
  6759. 'username': obj.username,
  6760. 'permissionList': obj.permissionList,
  6761. 'nickname': obj.nickname,
  6762. 'id': str(obj.id)
  6763. })
  6764. return JsonOkResponse(payload={'agentId': request.user.agentId, 'dataList': dataList, 'total': total})
  6765. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6766. @permission_required(ROLE.dealer, ROLE.subaccount)
  6767. def addEditSubAccount(request):
  6768. bossId = request.user.bossId
  6769. payload = json.loads(request.body)
  6770. strId = payload.get('id', None)
  6771. if strId is None:
  6772. username = payload['username']
  6773. code = payload['code']
  6774. status, desc = dealerRegisterSMSProvider.verify(username, code)
  6775. if not status:
  6776. return JsonErrorResponse(desc)
  6777. count = SubAccount.objects.filter(username=username, bossId=str(bossId)).count()
  6778. if count > 0:
  6779. return JsonResponse({"result": 0, "description": u'该手机号已经是子账号了,不允许重复配置该手机号为子账号', "payload": None})
  6780. password = payload['password']
  6781. if (not password) or len(password) < 6:
  6782. return JsonResponse({"result": 0, "description": u'必须输入密码,密码长度不能小于6', "payload": None})
  6783. nickname = payload['nickname']
  6784. if not nickname:
  6785. return JsonResponse({"result": 0, "description": u'必须配置昵称', "payload": None})
  6786. newObj = SubAccount(
  6787. username=username,
  6788. nickname=nickname,
  6789. password=make_password(password),
  6790. permissionList=payload.get('permissionList', []),
  6791. agentId=request.user.agentId,
  6792. bossId=bossId
  6793. )
  6794. newObj.save()
  6795. return JsonOkResponse(payload={'id': str(newObj.id)})
  6796. else:
  6797. username = payload['username']
  6798. try:
  6799. obj = SubAccount.objects.get(id=strId)
  6800. except DoesNotExist:
  6801. return JsonResponse({"result": 0, "description": u'并未找到该子账号,可能已经被删除了', "payload": None})
  6802. password = payload['password']
  6803. if (not password) or len(password) < 6:
  6804. return JsonResponse({"result": 0, "description": u'必须输入密码,密码长度不能小于6', "payload": None})
  6805. nickname = payload['nickname']
  6806. if not nickname:
  6807. return JsonResponse({"result": 0, "description": u'必须配置昵称', "payload": None})
  6808. obj.username = username
  6809. obj.nickname = nickname
  6810. obj.permissionList = payload.get('permissionList', [])
  6811. obj.save()
  6812. obj.set_password(password)
  6813. return JsonOkResponse(payload={'id': str(obj.id)})
  6814. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6815. @permission_required(ROLE.dealer, ROLE.subaccount)
  6816. def deleteSubAccount(request):
  6817. payload = json.loads(request.body)
  6818. idsTemp = payload.get('ids', [])
  6819. ids = [ObjectId(_) for _ in idsTemp]
  6820. SubAccount.objects.filter(id__in=ids).delete()
  6821. return JsonResponse({"result": 1, "description": '', "payload": None})
  6822. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6823. @permission_required(ROLE.dealer, ROLE.subaccount)
  6824. def getAccountPermission(request):
  6825. # 授权经销商用户
  6826. if check_role(request.user, ROLE.dealer):
  6827. permissions = hasattr(request, 'permissions') and getattr(request, 'permissions') # type: dict
  6828. if permissions:
  6829. permissions.update({'role': 'dealerWorker'})
  6830. return JsonOkResponse(payload=permissions)
  6831. # 获取经销商或者子账号所属经销商权限
  6832. mainMenu, homepageData = request.user.myBoss.query_home_page_layout()
  6833. # 调整子账号权限
  6834. if check_role(request.user, ROLE.subaccount):
  6835. for pm in request.user.permissionList:
  6836. if pm in ['today_income', 'today_pay_income', 'today_ad_income', 'offline_coins']:
  6837. homepageData[pm] = True
  6838. else:
  6839. mainMenu[pm] = True
  6840. leftHomepage = list(set(Const.HOME_PAGE_DATA_LIST.keys()) - set(request.user.permissionList))
  6841. for pm in leftHomepage:
  6842. homepageData[pm] = False
  6843. leftMainmenu = list(set(Const.MAIN_MENU_LIST.keys()) - set(request.user.permissionList))
  6844. for pm in leftMainmenu:
  6845. mainMenu[pm] = False
  6846. return JsonOkResponse(payload={'role': request.user.role, 'homepageData': homepageData, 'mainMenu': mainMenu})
  6847. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6848. @permission_required(ROLE.dealer)
  6849. def getAccountPermissionById(request):
  6850. strId = request.GET.get('id', None)
  6851. subList = SubAccount.objects.get(id=strId).permissionList
  6852. mainMenu, homepageData = request.user.query_home_page_layout()
  6853. for menu, value in mainMenu.iteritems():
  6854. if not value:
  6855. continue
  6856. if menu in subList:
  6857. mainMenu[menu] = True
  6858. else:
  6859. mainMenu[menu] = False
  6860. mainMenu['sim_card'] = False # sim卡充值不允许给子账号操作
  6861. for menu, value in homepageData.iteritems():
  6862. if not value:
  6863. continue
  6864. if menu in subList:
  6865. homepageData[menu] = True
  6866. else:
  6867. homepageData[menu] = False
  6868. return JsonOkResponse(payload={'homepageData': homepageData, 'mainMenu': mainMenu})
  6869. @permission_required(ROLE.dealer)
  6870. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6871. def subAccountRegisterCode(request):
  6872. # type: (WSGIRequest)->JsonResponse
  6873. payload = json.loads(request.body)
  6874. phoneNumber = payload.get('username', None)
  6875. agent = Agent.get_agent(request.user.agentId)
  6876. productName = agent['productName']
  6877. if not phoneNumber:
  6878. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  6879. if len(SubAccount.objects.filter(username=phoneNumber, bossId=str(request.user.id))):
  6880. return JsonResponse({'result': 0, 'description': u'该手机号已经是您的子账号了'})
  6881. status, msg = dealerRegisterSMSProvider.get(phoneNumber=phoneNumber,
  6882. productName=productName,
  6883. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  6884. if not status:
  6885. return JsonResponse({'result': 0, 'description': msg})
  6886. else:
  6887. return JsonResponse({'result': 1, 'description': ''})
  6888. @permission_required(ROLE.dealer)
  6889. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6890. def saveAccountPermission(request):
  6891. payload = json.loads(request.body)
  6892. subId = payload.get('id')
  6893. homepageData = payload.get('homepageData', [])
  6894. mainMenu = payload.get('mainMenu', [])
  6895. obj = SubAccount.objects.get(id=subId)
  6896. perList = []
  6897. for k, v in homepageData.items():
  6898. if v:
  6899. perList.append(k)
  6900. for k, v in mainMenu.items():
  6901. if v:
  6902. perList.append(k)
  6903. obj.permissionList = perList
  6904. obj.save()
  6905. return JsonResponse({'result': 1, 'description': ''})
  6906. @permission_required(ROLE.dealer)
  6907. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6908. def getAlarmList(request):
  6909. # type: (WSGIRequest)->JsonResponse
  6910. pageIndex = int(request.GET.get('pageIndex', 1))
  6911. pageSize = int(request.GET.get('pageSize', 10))
  6912. queryset = FaultRecord.objects(dealerId=str(request.user.id), status=FAULT_RECORD_STATUS.INIT).order_by('-createdTime')
  6913. records = queryset.paginate(pageIndex=pageIndex, pageSize=pageSize) # type: Iterable[FaultRecord]
  6914. total = queryset.count()
  6915. return JsonOkResponse(payload={'dataList': [ _.to_dict() for _ in records ], 'total': total})
  6916. @permission_required(ROLE.dealer)
  6917. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6918. def handleAlarm(request):
  6919. # type: (WSGIRequest)->JsonResponse
  6920. payload = json.loads(request.body)
  6921. id_ = payload.get('id')
  6922. if id_ is None:
  6923. return JsonErrorResponse(description=u'id未传入')
  6924. status = payload.get('status')
  6925. if status is None:
  6926. return JsonErrorResponse(description=u'处理状态未传入')
  6927. dealedDetail = payload.get("dealedDetail", "")
  6928. if type(id_) == list:
  6929. id_list = id_
  6930. else:
  6931. id_list = [id_]
  6932. for item_id in id_list:
  6933. alarm = FaultRecord.objects(id=item_id).get() # type: FaultRecord
  6934. alarm.set_status(status=status, dealedDetail=dealedDetail)
  6935. if status == "handled":
  6936. task_caller(
  6937. "send_to_xf_fault_handle",
  6938. devNo=alarm.imei,
  6939. faultId=str(alarm.id)
  6940. )
  6941. handler_event_to_zhejiang(id_list[0])
  6942. dev = Device.get_dev(alarm.imei)
  6943. box = ActionDeviceBuilder.create_action_device(dev)
  6944. if box.isHaveFaultHandle:
  6945. try:
  6946. box.faultHandle(alarm=alarm)
  6947. except:
  6948. pass
  6949. return JsonOkResponse()
  6950. @permission_required(ROLE.dealer)
  6951. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6952. def checkAlarm(request):
  6953. # type: (WSGIRequest)->JsonResponse
  6954. id_ = request.GET.get('id')
  6955. if id_ is None:
  6956. return JsonErrorResponse(description=u'id未传入')
  6957. alarm = FaultRecord.objects(id=id_).get() # type: FaultRecord
  6958. dev = Device.get_dev(alarm.imei)
  6959. box = ActionDeviceBuilder.create_action_device(dev)
  6960. try:
  6961. desc = box.check_alarm(alarm)
  6962. except ServiceException , e:
  6963. return JsonResponse({"result": 0, "description": e.result.get('description'), 'payload': {}})
  6964. except Exception, e:
  6965. return JsonResponse({"result": 0, "description": u'系统异常,检查告警失败', 'payload': {}})
  6966. return JsonResponse({"result": 1, "description": desc, 'payload': {}})
  6967. @permission_required(ROLE.dealer)
  6968. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6969. def withdrawEntry(request):
  6970. # type: (WSGIRequest)->JsonResponse
  6971. user = request.user # type: Dealer
  6972. if not check_role(user, ROLE.dealer):
  6973. return ErrorResponseRedirect(error=u'权限错误')
  6974. source_key = request.GET.get('sourceId')
  6975. if not WithdrawGateway.is_ledger(source_key):
  6976. return ErrorResponseRedirect(error=u'系统配置错误,请联系平台客服(10003)')
  6977. source_type = request.GET.get('sourceType')
  6978. assert source_type in DEALER_INCOME_TYPE.choices(), 'invalid dealer income type'
  6979. if source_key not in user.balance_dict(source_type):
  6980. return ErrorResponseRedirect(error=u'提现参数错误,请刷新后重试')
  6981. is_ledger, withdraw_gateway_list = Agent.withdraw_gateway_list(source_key)
  6982. if not is_ledger:
  6983. return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10005)')
  6984. wechat_withdraw_gateway = withdraw_gateway_list['wechat']
  6985. if not wechat_withdraw_gateway:
  6986. return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10006)')
  6987. code = request.GET.get('code', None)
  6988. if not code:
  6989. redirect = request.GET.get('redirect')
  6990. return ExternalResponseRedirect(
  6991. WechatAuthBridge(wechat_withdraw_gateway.app).generate_auth_url_base_scope(
  6992. concat_server_end_url(
  6993. uri='/dealer/withdraw/entry?sourceType={source_type}&sourceId={source_key}'.format(
  6994. source_type=source_type,
  6995. source_key=source_key
  6996. )), payload=base64.b64encode(redirect)))
  6997. else:
  6998. auth_bridge = WechatAuthBridge(wechat_withdraw_gateway.app)
  6999. openId = auth_bridge.authorize(code)
  7000. if openId is not None:
  7001. redirect = base64.b64decode(request.GET.get('payload'))
  7002. redirect = add_query(redirect, {
  7003. 'sourceType': source_type,
  7004. 'sourceId': source_key,
  7005. 'openId': openId
  7006. })
  7007. return FrontEndResponseRedirect(redirect)
  7008. else:
  7009. return ErrorResponseRedirect(error=u'微信授权失败,请刷新后重试')
  7010. @permission_required(ROLE.dealer)
  7011. def ActivateUser(request):
  7012. """
  7013. 安骑的 用户缴纳金额后 经销商激活
  7014. 需要查询对应的 推荐人,如果存在推荐人,将其金币数量增加固定数量
  7015. """
  7016. user = request.user
  7017. payload = json.loads(request.body)
  7018. _id = payload.get("id", "") # 存有用户激活信息的ID
  7019. status = payload.get("status", "")
  7020. remarks = payload.get("remarks", "")
  7021. groupIds = Group.get_group_ids_of_dealer(str(user.id)) # 获取该经销商下的所有的groupId
  7022. customer = MyUser.objects.get(id=_id)
  7023. if int(status) == 2: # 2表示用户信息激活状态为成功
  7024. MyUser.set_active_info(
  7025. {"isMember": True,
  7026. "status": status,
  7027. "remarks": remarks},
  7028. openId=customer.openId,
  7029. agentId=customer.agentId,
  7030. groupId__in=groupIds
  7031. )
  7032. # TODO zjl 这一部分任务查询时间任过长,没有索引, 是否考虑设置异步任务触发
  7033. recommender = MyUser.get_active_info(openId=customer.openId, agentId=customer.agentId, groupId__in=groupIds).get("recommender") # 推荐人
  7034. if recommender:
  7035. groupList = Group.get_groups_of_dealer(user.id)
  7036. recommender = MyUser.objects.get(phoneNumber=recommender)
  7037. if recommender.groupId not in groupList: # 添加对于当前的recommender的验证 要是同一个经销商下的
  7038. logger.info("uninvalid recommender dealer=%s, recommender=%s" % (user.nickname, recommender.nickname))
  7039. else:
  7040. coins = 10 # TODO zjl 添加推荐人金币 金币设置值
  7041. update = recommender.incr_balance(VirtualCoin(coins))
  7042. if not update:
  7043. logger.info("recommender %s get coins faild." % recommender.nickname)
  7044. else:
  7045. # 添加一条充值记录
  7046. orderNo = str(uuid.uuid1())
  7047. try:
  7048. newRcd = RechargeRecord(orderNo=orderNo,
  7049. coins=coins,
  7050. money=0.00,
  7051. openId=recommender.openId,
  7052. wxOrderNo=u'活动赠币',
  7053. nickname=recommender.nickname,
  7054. result='success',
  7055. via='sendcoin',
  7056. operator=str(user.id))
  7057. newRcd.save()
  7058. except Exception as e:
  7059. logger.exception('update record for feedback coins error=%s,orderNo=%s' % (e, orderNo))
  7060. return JsonOkResponse(u"会员录入成功,可以正常使用换电柜")
  7061. elif int(status) == 3: # 3表示用户信息激活状态为失败
  7062. MyUser.set_active_info(
  7063. {"isMember": False,
  7064. "status": status,
  7065. "remarks": remarks,
  7066. "auditTime": datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S")},
  7067. openId=customer.openId,
  7068. agentId=customer.agentId,
  7069. groupId__in=groupIds
  7070. )
  7071. return JsonOkResponse(u"已拒绝该用户")
  7072. else:
  7073. logger.error("uninvalid status : %s" % status)
  7074. return JsonErrorResponse(u"无效的审核状态")
  7075. @permission_required(ROLE.dealer)
  7076. def delUserActiveInfo(request):
  7077. user = request.user
  7078. payload = json.loads(request.body)
  7079. ids = payload.get("ids", "")
  7080. # 删除该经销商下的该用户的激活信息
  7081. customers = MyUser.objects.filter(id__in=ids)
  7082. groupIds = Group.get_group_ids_of_dealer(str(user.id))
  7083. for customer in customers:
  7084. MyUser.del_active_info(
  7085. openId=customer.openId,
  7086. agentId=customer.agentId,
  7087. groupId__in=groupIds
  7088. )
  7089. return JsonOkResponse()
  7090. @permission_required(ROLE.dealer)
  7091. def getUserIdentifyList(request):
  7092. """
  7093. 获取临时用户 待激活用户
  7094. """
  7095. pageIndex = int(request.GET.get("pageIndex", 1))
  7096. pageSize = int(request.GET.get("pageSize", 10))
  7097. searchKey = request.GET.get("searchKey")
  7098. status = request.GET.get("status")
  7099. if status in ("", "null"):
  7100. statusList = [0, 1, 2, 3]
  7101. else:
  7102. statusList = [int(status)]
  7103. groupList = Group.get_group_ids_of_dealer(request.user.id)
  7104. query = {
  7105. "groupId": {"$in": groupList},
  7106. "extra.active.status": {"$in": statusList}
  7107. }
  7108. if searchKey:
  7109. query.update(search_query(['nickname', 'phoneNumber'], searchKey).to_query(MyUser))
  7110. results = MyUser.get_collection().find(
  7111. query,
  7112. {
  7113. "nickname": 1,
  7114. "openId": 1,
  7115. "phoneNumber": 1,
  7116. "avatar": 1,
  7117. "extra.active": 1
  7118. }
  7119. ).skip(
  7120. (pageIndex - 1) * pageSize
  7121. ).limit(
  7122. pageSize
  7123. )
  7124. tempUsers = []
  7125. for user in results:
  7126. userDict = dict()
  7127. userDict["id"] = str(user["_id"])
  7128. # userDict["phoneNumber"] = user["phoneNumber"]
  7129. userDict["userNickname"] = user.get("nickname", "")
  7130. userDict["avatarUrl"] = user.get("avatar", "")
  7131. userDict.update(
  7132. user["extra"]["active"]
  7133. )
  7134. tempUsers.append(userDict)
  7135. data = {
  7136. "page": pageIndex,
  7137. # "total": 2 * pageSize if len(tempUsers) >= pageSize else pageSize,
  7138. "total": 10000,
  7139. "pageSize": pageSize,
  7140. "offset": 0,
  7141. "dataList": tempUsers
  7142. }
  7143. return JsonResponse({'result': 1, 'description': "", 'payload': data})
  7144. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'鉴权失败,请重新登录'))
  7145. @permission_required(ROLE.dealer, ROLE.subaccount)
  7146. def info(request):
  7147. user = request.user
  7148. payload = {
  7149. 'roles':['admin'],
  7150. 'introduction':user.description,
  7151. 'avatar':user.wechatAuthUserInfo.get('avatar'),
  7152. 'name':user.phone
  7153. }
  7154. return JsonResponse({'result': 1, 'description': '', 'payload':payload})
  7155. def getDashboard(request):
  7156. dealerId = str(request.user.id)
  7157. groupIds = Group.get_group_ids_of_dealer(dealerId)
  7158. devList = Device.get_devices_by_group(groupIds).values()
  7159. devCount = len(devList)
  7160. todayTime = datetime.datetime.now()
  7161. yesterdayTime = todayTime - datetime.timedelta(days=1)
  7162. today = todayTime.strftime(Const.DATE_FMT)
  7163. yesterDay = yesterdayTime.strftime(Const.DATE_FMT)
  7164. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':today}, {'daily':1, 'activedDevRatio':1})
  7165. if rcds.count() == 0:
  7166. todayIncome = 0
  7167. todayRechargeIncome = 0
  7168. todayChargeCardIncome = 0
  7169. todayOrder = 0
  7170. else:
  7171. info = rcds[0]
  7172. todayIncome = info.get('daily', {}).get('totalIncome', 0)
  7173. income = info.get('daily', {}).get('income', {})
  7174. todayRechargeIncome = income.get('recharge', 0)
  7175. todayChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('chargeVirtualCard', 0))
  7176. todayOrder = info.get('daily', {}).get('totalIncomeCount', 0)
  7177. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':yesterDay}, {'daily':1, 'activedDevRatio':1})
  7178. if rcds.count() == 0:
  7179. yesterdayIncome = 0
  7180. yesterdayOrder = 0
  7181. yesterdayActiveDevicePercent = 0
  7182. yesterdayActiveDevice = 0
  7183. yesterdayRechargeIncome = 0
  7184. yesterdayChargeCardIncome = 0
  7185. else:
  7186. info = rcds[0]
  7187. yesterdayIncome = info.get('daily', {}).get('totalIncome', 0)
  7188. income = info.get('daily', {}).get('income', {})
  7189. yesterdayRechargeIncome = income.get('recharge', 0)
  7190. yesterdayChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('chargeVirtualCard', 0))
  7191. yesterdayOrder = info.get('daily', {}).get('totalIncomeCount', 0)
  7192. yesterdayActiveDevicePercent = info.get('activedDevRatio', 0)
  7193. yesterdayActiveDevice = int(round(yesterdayActiveDevicePercent / 100.0 * devCount, 2))
  7194. date = MONTH_DATE_KEY.format(year=todayTime.year, month=todayTime.month)
  7195. rcds = DealerMonthlyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':date}, {'monthly':1, 'activedDevRatio':1, 'addedUserCount':1})
  7196. if rcds.count() == 0:
  7197. monthIncome = 0
  7198. monthRechargeIncome = 0
  7199. monthChargeCardIncome = 0
  7200. thisMonthOrder = 0
  7201. userCountAddedThisMonth = 0
  7202. else:
  7203. info = rcds[0]
  7204. monthIncome = info.get('monthly', {}).get('totalIncome', 0)
  7205. income = info.get('monthly', {}).get('income', {})
  7206. monthRechargeIncome = income.get('recharge', 0)
  7207. monthChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('chargeVirtualCard', 0))
  7208. thisMonthOrder = info.get('monthly', {}).get('totalIncomeCount', 0)
  7209. userCountAddedThisMonth = info.get('addedUserCount', 0)
  7210. userCount = request.user.userCount
  7211. return JsonOkResponse(
  7212. payload={
  7213. "todayIncome":todayIncome,
  7214. 'todayRechargeIncome':todayRechargeIncome,
  7215. 'todayChargeCardIncome':todayChargeCardIncome,
  7216. "yesterdayIncome":yesterdayIncome,
  7217. 'yesterdayRechargeIncome':yesterdayRechargeIncome,
  7218. 'yesterdayChargeCardIncome':yesterdayChargeCardIncome,
  7219. "thisMonthIncome": monthIncome,
  7220. 'thisMonthRechargeIncome':monthRechargeIncome,
  7221. 'thisMonthChargeCardIncome':monthChargeCardIncome,
  7222. "todayOrder": todayOrder,
  7223. "yesterdayOrder":yesterdayOrder,
  7224. "thisMonthOrder":thisMonthOrder,
  7225. "deviceTotal":len(devList),
  7226. "yesterdayActiveDevice":yesterdayActiveDevice,
  7227. "yesterdayActiveDevicePercent":yesterdayActiveDevicePercent,
  7228. 'userCount':userCount,
  7229. 'userCountAddedThisMonth':userCountAddedThisMonth
  7230. }
  7231. )
  7232. def deviceOfflineTrend(request):
  7233. dealerId = str(request.user.id)
  7234. todayTime = datetime.datetime.now()
  7235. startTime = todayTime - datetime.timedelta(days=7)
  7236. startDay = startTime.strftime(Const.DATE_FMT)
  7237. endDay = todayTime.strftime(Const.DATE_FMT)
  7238. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':{'$gte':startDay, '$lte':endDay}}, {'other':1, 'date':1})
  7239. dataList = []
  7240. for rcd in rcds:
  7241. other = rcd.get('other', {'totalOfflineTime':0, 'totalOfflineBusyTime':0, 'totalOnlineTime':0})
  7242. totalTime = other['totalOfflineTime'] + other['totalOfflineBusyTime'] + other['totalOnlineTime']
  7243. dataList.append({
  7244. 'dateStr':rcd['date'],
  7245. 'offlineTimePercent':round(100 * other['totalOfflineTime'] / totalTime, 2) if totalTime else 0
  7246. })
  7247. return JsonOkResponse(payload={'dataList': dataList})
  7248. @error_tolerate(nil=DefaultJsonErrorResponse)
  7249. @permission_required(ROLE.dealer)
  7250. def deviceActiveTrend(request):
  7251. dealerId = str(request.user.id)
  7252. todayTime = datetime.datetime.now()
  7253. startTime = todayTime - datetime.timedelta(days=7)
  7254. startDay = startTime.strftime(Const.DATE_FMT)
  7255. endDay = todayTime.strftime(Const.DATE_FMT)
  7256. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':{'$gte':startDay, '$lte':endDay}}, {'activedDevRatio':1, 'date':1})
  7257. dataList = []
  7258. for rcd in rcds:
  7259. ratio = rcd.get('activedDevRatio', 0)
  7260. dataList.append({
  7261. 'dateStr':rcd['date'],
  7262. 'activeDevicePercent':ratio
  7263. })
  7264. return JsonOkResponse(payload={'dataList': dataList})
  7265. @error_tolerate(nil=DefaultJsonErrorResponse)
  7266. @permission_required(ROLE.dealer)
  7267. def getGroupStatistics(request):
  7268. def calc_group_stats(groupId, startDate, endDate):
  7269. groupResult = GroupReport.get_rpt([groupId], startDate, endDate)
  7270. offlineCoin = groupResult[groupId].get('lineCoins', 0)
  7271. rcds = GroupDailyStatsModelProxy.get_data_list(startTime=startDate,
  7272. endTime=endDate,
  7273. groupId=ObjectId(groupId),
  7274. only={
  7275. 'other': 1, 'incomeTotal': 1, 'daily': 1,
  7276. 'activedDevRatio': 1
  7277. })
  7278. orderTotal, payIncome, offlineTime, totalTime, totalActivedRate, peakValue = 0, RMB(0.0), 0, 0, 0, 0
  7279. count = 0
  7280. for rcd in rcds:
  7281. count += 1
  7282. daily = rcd.get('daily') or {}
  7283. other = rcd.get('other') or {}
  7284. orderTotal += daily.get('totalIncomeCount', 0)
  7285. payIncome += daily.get('totalIncome', 0)
  7286. offlineTime += other.get('totalOfflineTime', 0)
  7287. totalTime = totalTime + other.get('totalOfflineTime', 0) + other.get('totalOnlineTime', 0) + other.get(
  7288. 'totalOfflineBusyTime', 0)
  7289. totalActivedRate += rcd.get('activedDevRatio', 0)
  7290. dayPeakValue = rcd.get('peakUsage', 0)
  7291. if peakValue <= dayPeakValue:
  7292. peakValue = dayPeakValue
  7293. return {
  7294. 'orderTotal': orderTotal,
  7295. 'payIncome': payIncome,
  7296. 'offlineCoin': offlineCoin,
  7297. 'deviceOfflineCount': int(round(offlineTime / totalTime * 100.0, 2)) if totalTime > 0 else 0,
  7298. # 前台修改后,用设备离线时间占比offlineTime/totalTime * 100
  7299. 'dailyActivityRate': int(round(totalActivedRate / count, 2)) if count > 0 else 0,
  7300. 'peakValue': peakValue
  7301. }
  7302. ownerId = str(request.user.id)
  7303. startDate = str(request.GET.get('startTime'))
  7304. endDate = str(request.GET.get('endTime'))
  7305. pageIndex = int(request.GET.get('pageIndex'))
  7306. pageSize = int(request.GET.get('pageSize'))
  7307. groupIds = Group.get_group_ids_of_dealer(ownerId)
  7308. total = len(groupIds)
  7309. pageGroupIds = groupIds[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  7310. dataList = []
  7311. count = 0
  7312. for groupId in pageGroupIds:
  7313. count += 1
  7314. group = Group.get_group(groupId)
  7315. devList = Device.get_devices_by_group([groupId]).values()
  7316. devCount = len(devList)
  7317. valueDict = calc_group_stats(groupId, startDate, endDate)
  7318. dataList.append({
  7319. 'id':str(groupId),
  7320. 'groupName':group['groupName'],
  7321. 'address':group['address'],
  7322. 'deviceTotal':devCount,
  7323. 'orderTotal':valueDict.get('orderTotal', 0),
  7324. 'payIncome':valueDict.get('payIncome', RMB(0.0)),
  7325. 'offlineCoin':valueDict.get('offlineCoin', 0),
  7326. 'deviceOfflineCount':valueDict.get('deviceOfflineCount', 0),
  7327. 'dailyActivityRate':valueDict.get('dailyActivityRate', 0),
  7328. 'peakValue':valueDict.get('peakValue', 0)
  7329. })
  7330. return JsonOkResponse(payload={'total':total, 'dataList': dataList})
  7331. @error_tolerate(nil=DefaultJsonErrorResponse)
  7332. @permission_required(ROLE.dealer)
  7333. def getOrderTrendByGroup(request):
  7334. groupId = request.GET.get('id')
  7335. todayTime = datetime.datetime.now()
  7336. startDate = request.GET.get('startTime', '')
  7337. if not startDate:
  7338. startTime = todayTime - datetime.timedelta(days=7)
  7339. startDate = startTime.strftime(Const.DATE_FMT)
  7340. endDate = request.GET.get('endTime', '')
  7341. if not endDate:
  7342. endDate = (todayTime + datetime.timedelta(days=1)).strftime(Const.DATE_FMT)
  7343. group_report_dict = GroupReport.get_rpt([groupId], startDate, endDate)
  7344. rcds = GroupDailyStatsModelProxy.get_data_list(startTime=startDate,
  7345. endTime=endDate,
  7346. groupId=ObjectId(groupId),
  7347. only={
  7348. 'daily': 1, 'date': 1
  7349. })
  7350. dataList = []
  7351. for rcd in rcds: # type: GroupDailyStat
  7352. daily = rcd.daily
  7353. dataList.append({
  7354. 'dateStr': rcd.date,
  7355. 'payIncome': daily.get('totalIncome', 0),
  7356. 'orderTotal': daily.get('totalIncomeCount', 0),
  7357. 'offlineCoin': group_report_dict.get(rcd.date, {'lineCoins': 0, 'count': 0}.get('lineCoins', 0))
  7358. })
  7359. return JsonOkResponse(payload={'dataList': dataList})
  7360. @error_tolerate(nil=DefaultJsonErrorResponse)
  7361. @permission_required(ROLE.dealer)
  7362. def getOfflineTrendByGroup(request):
  7363. groupId = request.GET.get('id')
  7364. startDate = request.GET.get('startTime', '')
  7365. endDate = request.GET.get('endTime', '')
  7366. if not startDate:
  7367. todayTime = datetime.datetime.now()
  7368. startTime = todayTime - datetime.timedelta(days=7)
  7369. startDate = startTime.strftime(Const.DATE_FMT)
  7370. endDate = todayTime.strftime(Const.DATE_FMT)
  7371. rcds = GroupDailyStat.get_collection().find({'groupId':ObjectId(groupId), 'date':{'$gte':startDate, '$lte':endDate}}, {'other':1, 'date':1})
  7372. dataList = []
  7373. for rcd in rcds:
  7374. other = rcd.get('other', {})
  7375. offlineTime = other.get('totalOfflineTime', 0)
  7376. totalTime = other.get('totalOfflineTime', 0) + other.get('totalOnlineTime', 0) + other.get('totalOfflineBusyTime', 0)
  7377. dataList.append({
  7378. 'dateStr':rcd['date'],
  7379. 'offlineCount':int(round(offlineTime / totalTime * 100.0, 2)) if totalTime else 0
  7380. })
  7381. return JsonOkResponse(payload={'dataList':dataList})
  7382. @error_tolerate(nil=DefaultJsonErrorResponse)
  7383. @permission_required(ROLE.dealer)
  7384. def dailyActivityTrendByGroup(request):
  7385. groupId = request.GET.get('id')
  7386. startDate = request.GET.get('startTime', '')
  7387. endDate = request.GET.get('endTime', '')
  7388. if not startDate:
  7389. todayTime = datetime.datetime.now()
  7390. startTime = todayTime - datetime.timedelta(days=7)
  7391. startDate = startTime.strftime(Const.DATE_FMT)
  7392. endDate = todayTime.strftime(Const.DATE_FMT)
  7393. rcds = GroupDailyStat.get_collection().find({'groupId':ObjectId(groupId), 'date':{'$gte':startDate, '$lte':endDate}}, {'activedDevRatio':1, 'devCount':1, 'date':1})
  7394. dataList = []
  7395. for rcd in rcds:
  7396. deviceTotal = rcd.get('devCount', 0)
  7397. dataList.append({
  7398. 'dateStr':rcd['date'],
  7399. 'dailyActivity':int(float(rcd.get('activedDevRatio', 0)) / 100.0 * deviceTotal),
  7400. 'deviceTotal':deviceTotal
  7401. })
  7402. return JsonOkResponse(payload={'dataList':dataList})
  7403. @error_tolerate(nil=DefaultJsonErrorResponse)
  7404. @permission_required(ROLE.dealer)
  7405. def getPeakValueTrendByGroup(request):
  7406. groupId = request.GET.get('id')
  7407. startDate = request.GET.get('startTime', '')
  7408. endDate = request.GET.get('endTime', '')
  7409. if not startDate:
  7410. todayTime = datetime.datetime.now()
  7411. startTime = todayTime - datetime.timedelta(days=7)
  7412. startDate = startTime.strftime(Const.DATE_FMT)
  7413. endDate = todayTime.strftime(Const.DATE_FMT)
  7414. rcds = GroupDailyStat.get_collection().find({'groupId':ObjectId(groupId), 'date':{'$gte':startDate, '$lte':endDate}}, {'other':1, 'date':1})
  7415. dataList = []
  7416. hourlyDict = {}
  7417. for rcd in rcds:
  7418. hourly = rcd.get('other', {}).get('hourly', {})
  7419. for hour, value in hourly.items():
  7420. if not hourlyDict.has_key(hour):
  7421. hourlyDict[hour] = {'usageSum':0, 'usageCount':0}
  7422. else:
  7423. hourlyDict[hour]['usageSum'] += value['usageSum']
  7424. hourlyDict[hour]['usageCount'] += value['usageCount']
  7425. for ii in range(24):
  7426. hour = str(ii)
  7427. if hourlyDict.has_key(hour):
  7428. hourValue = hourlyDict[hour]
  7429. dataList.append(
  7430. {'hour':hour, 'usage':int(round(float(hourValue['usageSum']) / float(hourValue['usageCount']), 2)) if hourValue['usageCount'] > 0 else 0 }
  7431. )
  7432. else:
  7433. dataList.append({'hour':hour, 'usage':0})
  7434. return JsonOkResponse(payload={'dataList':dataList})
  7435. @error_tolerate(nil=DefaultJsonErrorResponse)
  7436. @permission_required(ROLE.dealer)
  7437. def getDeviceStatistics(request):
  7438. ownerId = str(request.user.id)
  7439. logicalCode = request.GET.get('searchKey', '')
  7440. startDate = request.GET.get('startTime', '')
  7441. endDate = request.GET.get('endTime', '')
  7442. pageIndex = int(request.GET.get('pageIndex'))
  7443. pageSize = int(request.GET.get('pageSize'))
  7444. if not startDate:
  7445. todayTime = datetime.datetime.now()
  7446. startTime = todayTime - datetime.timedelta(days=7)
  7447. startDate = startTime.strftime(Const.DATE_FMT)
  7448. endDate = todayTime.strftime(Const.DATE_FMT)
  7449. # 找出相关所有设备
  7450. if logicalCode:
  7451. dev_no = Device.get_devNo_by_logicalCode(logicalCode)
  7452. if dev_no:
  7453. devNoList = [dev_no]
  7454. else:
  7455. devNoList = []
  7456. else:
  7457. groupIds = Group.get_group_ids_of_dealer(ownerId)
  7458. tempList = Device.get_devNos_by_group(groupIds)
  7459. total = len(tempList)
  7460. devNoList = tempList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  7461. if not devNoList:
  7462. return JsonOkResponse(payload={'total': 0, 'dataList': []})
  7463. total = len(devNoList)
  7464. dataList = []
  7465. devList = Device.get_dev_by_nos(devNoList, True)
  7466. for dev in devList.values():
  7467. lc = dev['logicalCode']
  7468. devType = dev.get('devType', {}).get('name', '')
  7469. groupName = dev.get('groupInfo', {}).get('groupName', '')
  7470. remarks = dev.get('remarks', '')
  7471. orderTotal, payIncome, deviceOfflineCount, deviceOfflineTimeTotal, peakValue = 0, RMB(0.0), 0, 0, 0
  7472. rcds = DeviceDailyStatsModelProxy.get_data_list(
  7473. startTime=startDate,
  7474. endTime=endDate,
  7475. logicalCode=lc,
  7476. only={'date': 1, 'other': 1, 'daily': 1, 'peakUsage': 1})
  7477. for rcd in rcds:
  7478. daily = rcd.get('daily') or {}
  7479. orderTotal += daily.get('totalIncomeCount', 0)
  7480. payIncome += RMB(daily.get('totalIncome', 0))
  7481. other = rcd.get('other') or {}
  7482. deviceOfflineCount += other.get('offlineCount', 0)
  7483. deviceOfflineTimeTotal += other.get('totalOfflineTime', 0)
  7484. if peakValue <= rcd.get('peakUsage', 0):
  7485. peakValue = rcd.get('peakUsage', 0)
  7486. faultCount = FeedBack.get_collection().find(
  7487. {'logicalCode': lc, 'createTime': {'$gte': startDate, '$lte': endDate}}).count()
  7488. solveFaultCount = FeedBack.get_collection().find(
  7489. {'logicalCode': lc, 'createTime': {'$gte': startDate, '$lte': endDate}, 'status': 1}).count()
  7490. dataList.append({
  7491. 'devType': devType,
  7492. 'orderTotal': orderTotal,
  7493. 'payIncome': payIncome,
  7494. 'remarks': remarks,
  7495. 'deviceOfflineCount': deviceOfflineCount,
  7496. 'deviceOfflineTimeTotal': deviceOfflineTimeTotal / 60,
  7497. 'faultCount': faultCount,
  7498. 'solveFaultCount': solveFaultCount,
  7499. 'peakValue': peakValue,
  7500. 'groupName': groupName,
  7501. 'logicalCode': lc
  7502. })
  7503. return JsonOkResponse(payload={'total': total, 'dataList': dataList})
  7504. @error_tolerate(nil=DefaultJsonErrorResponse)
  7505. @permission_required(ROLE.dealer)
  7506. def getDeviceList(request):
  7507. ownerId = str(request.user.id)
  7508. pageIndex = int(request.GET.get('pageIndex'))
  7509. pageSize = int(request.GET.get('pageSize'))
  7510. groupIds = Group.get_group_ids_of_dealer(ownerId)
  7511. allDevNoList = Device.get_devNos_by_group(groupIds)
  7512. devNoList = allDevNoList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  7513. total = len(allDevNoList)
  7514. dataList = []
  7515. devList = Device.get_dev_by_nos(devNoList, verbose=True)
  7516. for dev in devList.values(): # type: DeviceDict
  7517. if dev.logicalCode == 'G419646':
  7518. monitorUrl = 'http://vod1.ddhlok.com/zzdd/shanghai4.m3u8'
  7519. elif dev.logicalCode == 'G430439':
  7520. monitorUrl = 'http://vod1.ddhlok.com/zzdd/shanghai5.m3u8'
  7521. elif dev.logicalCode == 'G430498':
  7522. monitorUrl = 'http://vod1.ddhlok.com/zzdd/shanghai1.m3u8'
  7523. else:
  7524. monitorUrl = None
  7525. devType = dev.devType.get('name', '')
  7526. dataList.append({
  7527. 'devType' : devType,
  7528. 'online': dev.online,
  7529. 'signal':dev.signal,
  7530. 'remarks':dev.get('remarks', ''),
  7531. 'registrationTime':dev.get('dateTimeAdded', ''),
  7532. 'simExpireDate':dev.fixedSimExpireDate,
  7533. 'groupName':dev.get('groupInfo', {}).get('groupName', ''),
  7534. 'imei':dev.devNo,
  7535. 'iccid':dev.get('iccid', ''),
  7536. 'logicalCode':dev.logicalCode,
  7537. 'monitorUrl':monitorUrl
  7538. })
  7539. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  7540. @error_tolerate(nil=DefaultJsonErrorResponse)
  7541. @permission_required(ROLE.dealer)
  7542. def getDevMapChart(request):
  7543. ownerId = str(request.user.id)
  7544. # 查找出所有已注册的设备
  7545. devList = list(Device.get_collection().find(
  7546. {'ownerId':str(ownerId)},
  7547. {'devNo': 1, 'districtId': 1, '_id': 0, 'logicalCode': 1, 'cycle': 1}
  7548. ))
  7549. districts = dict(Counter([District.get_district(_['districtId']).split(' ')[0] for _ in devList if
  7550. _.has_key('districtId') and District.get_district(_['districtId']) != '']))
  7551. def get_province(pvc):
  7552. if pvc == u'内蒙古自治区':
  7553. pvc = u'内蒙古'
  7554. elif pvc == u'黑龙江省':
  7555. pvc = u'黑龙江'
  7556. else:
  7557. pvc = pvc[0:2]
  7558. return pvc
  7559. dataList = [{'name': get_province(province), 'value': count} for province, count in districts.items()]
  7560. busy = 0
  7561. online = 0
  7562. offline = 0
  7563. deviceDict = {
  7564. _['devNo']: {'logicalCode': _['logicalCode'], 'cycle': _.get('cycle', Const.DEV_CYCLE_DEFAULT)} for
  7565. _ in devList}
  7566. for item in Device.get_many_device_status_cache(deviceDict).values():
  7567. device = DeviceDict(item) # type: DeviceDict
  7568. if device.status == 1:
  7569. busy += 1
  7570. if device.online == 1:
  7571. online += 1
  7572. elif device.online == 0:
  7573. offline += 1
  7574. return JsonResponse({'result': 1, 'description': u"", 'payload': {
  7575. "busy": busy,
  7576. "online": online,
  7577. "offline": offline,
  7578. "unregistered":0,
  7579. "dataList": dataList
  7580. }})
  7581. @error_tolerate(nil=DefaultJsonErrorResponse)
  7582. @permission_required(ROLE.dealer)
  7583. def getDeviceTrend(request):
  7584. ownerId = str(request.user.id)
  7585. startDate = request.GET.get('startTime', '')
  7586. endDate = request.GET.get('endTime', '')
  7587. if not startDate:
  7588. todayTime = datetime.datetime.now()
  7589. startTime = todayTime - datetime.timedelta(days=7)
  7590. startDate = startTime.strftime(Const.DATE_FMT)
  7591. endDate = todayTime.strftime(Const.DATE_FMT)
  7592. dataList = []
  7593. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7594. endTime=endDate,
  7595. dealerId=ObjectId(ownerId),
  7596. only={'date': 1, 'devCount': 1, 'activedDevRatio': 1})
  7597. for record in records:
  7598. devCount = record.get('devCount', 0)
  7599. activedRatio = record.get('activedDevRatio', 0)
  7600. dataList.append({
  7601. 'dateStr': record['date'],
  7602. 'deviceTotal': devCount,
  7603. 'active': int(round(devCount * activedRatio / 100.0, 2))
  7604. })
  7605. return JsonOkResponse(payload={'dataList': dataList})
  7606. @error_tolerate(nil=DefaultJsonErrorResponse)
  7607. @permission_required(ROLE.dealer)
  7608. def getAllFeedbackStatistics(request):
  7609. feedBacks = list(FeedBack.get_collection().find(
  7610. {'ownerId': request.user.id},
  7611. {'_id': 0, 'feedType': 1, 'status': 1}
  7612. ))
  7613. fault = [_['status'] for _ in feedBacks if _['feedType'] == 'fault']
  7614. faultProcessed = [_ for _ in fault if _ == 1]
  7615. upper = [_['status'] for _ in feedBacks if _['feedType'] == 'upper']
  7616. upperProcessed = [_ for _ in upper if _ == 1]
  7617. refund = [_['status'] for _ in feedBacks if _['feedType'] == 'refund']
  7618. refundProcessed = [_ for _ in refund if _ == 1]
  7619. return JsonResponse({'result': 1, 'description': None, 'payload': {
  7620. "faultCount": len(fault),
  7621. "faultProcessedCount": len(faultProcessed),
  7622. "upperCount": len(upper),
  7623. "upperProcessedCount": len(upperProcessed),
  7624. "refundCount": len(refund),
  7625. "refundProcessedCount": len(refundProcessed)
  7626. }})
  7627. @error_tolerate(nil=DefaultJsonErrorResponse)
  7628. @permission_required(ROLE.dealer)
  7629. def getDeviceNetworkTrend(request):
  7630. ownerId = str(request.user.id)
  7631. startDate = request.GET.get('startTime', '')
  7632. endDate = request.GET.get('endTime', '')
  7633. if not startDate:
  7634. todayTime = datetime.datetime.now()
  7635. startTime = todayTime - datetime.timedelta(days=7)
  7636. startDate = startTime.strftime(Const.DATE_FMT)
  7637. endDate = todayTime.strftime(Const.DATE_FMT)
  7638. dataList = []
  7639. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7640. endTime=endDate,
  7641. dealerId=ObjectId(ownerId),
  7642. only={'date': 1, 'other': 1})
  7643. for rcd in records:
  7644. other = rcd.get('other') or {}
  7645. dataList.append({
  7646. 'dateStr': rcd['date'],
  7647. 'online': other.get('totalOnlineTime', 0) + other.get('totalOfflineBusyTime', 0),
  7648. 'offline': other.get('totalOfflineTime', 0)
  7649. })
  7650. return JsonOkResponse(payload={'dataList': dataList})
  7651. @error_tolerate(nil=DefaultJsonErrorResponse)
  7652. @permission_required(ROLE.dealer)
  7653. def getPackageUsageFrequency(request):
  7654. ownerId = str(request.user.id)
  7655. startDate = request.GET.get('startTime', '')
  7656. endDate = request.GET.get('endTime', '')
  7657. if not startDate:
  7658. todayTime = datetime.datetime.now()
  7659. startTime = todayTime - datetime.timedelta(days=7)
  7660. startDate = startTime.strftime(Const.DATE_FMT)
  7661. endDate = todayTime.strftime(Const.DATE_FMT)
  7662. packageDict = {}
  7663. totalCount = 0
  7664. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7665. endTime=endDate,
  7666. dealerId=ObjectId(ownerId),
  7667. only={'date': 1, 'other': 1})
  7668. for rcd in records:
  7669. package = (rcd.get('other') or {}).get('package', {})
  7670. for coin, count in package.items():
  7671. try:
  7672. totalCount += count
  7673. if not packageDict.has_key(str(coin)):
  7674. packageDict[str(coin)] = count
  7675. else:
  7676. packageDict[str(coin)] += count
  7677. except Exception, e:
  7678. continue
  7679. dataList = []
  7680. for coin, count in packageDict.items():
  7681. dataList.append({
  7682. 'name': u'%s元' % round(float(coin) / 100.0, 2),
  7683. 'percent': round(float(count) / float(totalCount) * 100.0, 1) if totalCount > 0 else 100
  7684. }
  7685. )
  7686. return JsonOkResponse(payload={'dataList': dataList})
  7687. @error_tolerate(nil=DefaultJsonErrorResponse)
  7688. @permission_required(ROLE.dealer)
  7689. def getIncomeTrend(request):
  7690. ownerId = str(request.user.id)
  7691. startDate = request.GET.get('startTime', '')
  7692. endDate = request.GET.get('endTime', '')
  7693. if not startDate:
  7694. todayTime = datetime.datetime.now()
  7695. startTime = todayTime - datetime.timedelta(days=7)
  7696. startDate = startTime.strftime(Const.DATE_FMT)
  7697. endDate = todayTime.strftime(Const.DATE_FMT)
  7698. offlineCoinsDict = {r['date']: r.get('lineCoins', 0) for r in DealerReport.get_rpts(ownerId, startDate, endDate)}
  7699. dataList = []
  7700. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7701. endTime=endDate,
  7702. dealerId=ObjectId(ownerId),
  7703. only={'date': 1, 'daily': 1})
  7704. for rcd in records:
  7705. daily = rcd.get('daily') or {}
  7706. date = rcd['date']
  7707. dataList.append({
  7708. 'dateStr': date,
  7709. 'offlineCoin': offlineCoinsDict.get(date, 0),
  7710. 'payIncome': daily.get('totalIncome', 0)
  7711. })
  7712. return JsonOkResponse(payload={'dataList': dataList})
  7713. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取收益趋势失败"))
  7714. @permission_required(ROLE.dealer)
  7715. def getConsumptionTrend(request):
  7716. ownerId = str(request.user.id)
  7717. startDate = request.GET.get('startTime', '')
  7718. endDate = request.GET.get('endTime', '')
  7719. if not startDate:
  7720. todayTime = datetime.datetime.now()
  7721. startTime = todayTime - datetime.timedelta(days=7)
  7722. startDate = startTime.strftime(Const.DATE_FMT)
  7723. endDate = todayTime.strftime(Const.DATE_FMT)
  7724. dataList = []
  7725. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7726. endTime=endDate,
  7727. dealerId=ObjectId(ownerId),
  7728. only={'date': 1, 'daily': 1})
  7729. for rcd in records:
  7730. consumptionDict = (rcd.get('daily') or {}).get('consumption', {})
  7731. date = rcd['date']
  7732. itemList = []
  7733. for kind, value in consumptionDict.items():
  7734. if kind not in DEALER_CONSUMPTION_AGG_KIND.choices():
  7735. continue
  7736. itemList.append({
  7737. 'name': DEALER_CONSUMPTION_AGG_KIND_TRANSLATION[kind],
  7738. 'value': value,
  7739. 'unit': DEALER_CONSUMPTION_AGG_KIND_UNIT[kind],
  7740. })
  7741. dataList.append({
  7742. 'dateStr': date,
  7743. 'items': itemList,
  7744. })
  7745. return JsonOkResponse(payload={'dataList': dataList})
  7746. @error_tolerate(nil=DefaultJsonErrorResponse)
  7747. @permission_required(ROLE.dealer)
  7748. def getOrderTrend(request):
  7749. ownerId = str(request.user.id)
  7750. startDate = request.GET.get('startTime', '')
  7751. endDate = request.GET.get('endTime', '')
  7752. if not startDate:
  7753. todayTime = datetime.datetime.now()
  7754. startTime = todayTime - datetime.timedelta(days=7)
  7755. startDate = startTime.strftime(Const.DATE_FMT)
  7756. endDate = todayTime.strftime(Const.DATE_FMT)
  7757. hourlyDict = {}
  7758. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7759. endTime=endDate,
  7760. dealerId=ObjectId(ownerId),
  7761. only={'date': 1, 'hourly': 1})
  7762. for rcd in records:
  7763. hourly = rcd.get('hourly') or {}
  7764. for hour, value in hourly.items():
  7765. if not hourlyDict.has_key(hour):
  7766. hourlyDict[hour] = VirtualCoin(value.get('consumption', {}).get('coin', 0))
  7767. else:
  7768. hourlyDict[hour] += VirtualCoin(value.get('consumption', {}).get('coin', 0))
  7769. dataList = []
  7770. for ii in range(24):
  7771. hour = str(ii)
  7772. order = 0
  7773. if hourlyDict.has_key(hour):
  7774. order = hourlyDict.get(hour)
  7775. dataList.append({
  7776. 'dateStr':u'%s时' % hour,
  7777. 'order':str(order)
  7778. })
  7779. return JsonOkResponse(payload={'dataList':dataList})
  7780. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取收益列表失败"))
  7781. @permission_required(ROLE.dealer)
  7782. def getIncomeOrderList(request):
  7783. ownerId = str(request.user.id)
  7784. startTime = request.GET.get("startTime")
  7785. endTime = request.GET.get("endTime")
  7786. pageIndex = int(request.GET.get("pageIndex"))
  7787. pageSize = int(request.GET.get("pageSize"))
  7788. groupId = request.GET.get("groupId")
  7789. logicalCode = request.GET.get("logicalCode")
  7790. phoneNumber = request.GET.get("phoneNumber")
  7791. filters = {
  7792. "ownerId": ownerId,
  7793. "via__nin": [RechargeRecordVia.SendCoin, RechargeRecordVia.Refund]
  7794. }
  7795. if groupId:
  7796. filters.update({"groupId": groupId})
  7797. if logicalCode:
  7798. filters.update({"logicalCode": logicalCode})
  7799. # 如果存在phoneNumber,则是单一查找人
  7800. if phoneNumber:
  7801. phoneOwner = MyUser.objects.filter(phoneNumber=phoneNumber).first()
  7802. if phoneOwner:
  7803. filters.update({"openId": phoneOwner.openId})
  7804. records = ClientRechargeModelProxy.get_data_list(startTime=startTime, endTime=endTime,
  7805. **filters) # type: CustomQuerySet
  7806. total = records.count()
  7807. # 这个地方的数据一定是按照年进行分型的
  7808. dataList = list()
  7809. for rcd in records.paginate(pageIndex, pageSize):
  7810. try:
  7811. user = MyUser.objects.filter(openId=rcd.openId).only("openId", "gateWay", "productAgentId", "sex", "nickname").first()
  7812. if user.sex == 0:
  7813. sex = u"女"
  7814. elif user.sex == 1:
  7815. sex = u"男"
  7816. else:
  7817. sex = ""
  7818. userNickname = "{}-{}".format(user.nickname, user.phone) if user.phone else user.nickname
  7819. data = {
  7820. "id": str(rcd.id),
  7821. "orderAmount": str(rcd.amount),
  7822. "tradeType": RECHARGE_RECORD_VIA_TRANSLATION.get(rcd.via, "-"),
  7823. "gateway": rcd.gateway,
  7824. "status": rcd.result,
  7825. "userNickname": userNickname,
  7826. "userGender": sex,
  7827. "groupName": rcd.groupName,
  7828. "logicalCode": rcd.logicalCode,
  7829. "devTypeName": rcd.dev_type_name,
  7830. "createdTime": rcd.dateTimeAdded,
  7831. "gatewayTradeNo": rcd.wxOrderNo,
  7832. 'outTradeNo': rcd.orderNo
  7833. }
  7834. except Exception as e:
  7835. logger.exception("record no is {}, error is".format(rcd.orderNo, e))
  7836. continue
  7837. else:
  7838. dataList.append(data)
  7839. return JsonOkResponse(payload={"total": total, "dataList": dataList})
  7840. @permission_required(ROLE.dealer, ROLE.subaccount)
  7841. def getConsumptionOrderList(request):
  7842. """
  7843. 经销商PC端 对于 消费订单列表的获取
  7844. :param request:
  7845. :return:
  7846. """
  7847. ownerId = str(request.user.id)
  7848. startDate = request.GET.get('startTime')
  7849. endDate = request.GET.get('endTime')
  7850. pageIndex = int(request.GET.get('pageIndex', 1))
  7851. pageSize = int(request.GET.get('pageSize', 10))
  7852. groupId = str(request.GET.get('groupId'))
  7853. logicalCode = request.GET.get('logicalCode')
  7854. phoneNumber = request.GET.get("phoneNumber")
  7855. _type = request.GET.get("consumeType") # /netPay/cardPay/ 启动方式应该是只有 扫码启动 以及刷卡启动
  7856. dataList = []
  7857. filters = {
  7858. "ownerId": ownerId,
  7859. "isNormal": True
  7860. }
  7861. if _type == "cardPay":
  7862. filters.update({"remarks": u"刷卡消费"})
  7863. elif _type == "netPay":
  7864. filters.update({"remarks__ne": u"刷卡消费"})
  7865. else:
  7866. pass
  7867. if groupId:
  7868. filters.update({"groupId": groupId})
  7869. if logicalCode:
  7870. filters.update({"logicalCode": logicalCode})
  7871. if phoneNumber:
  7872. phoneOwner = MyUser.objects.filter(phoneNumber=phoneNumber).first()
  7873. if phoneOwner:
  7874. filters.update({"openId": phoneOwner.openId})
  7875. records = ClientConsumeModelProxy.get_data_list(startTime=startDate,
  7876. endTime=endDate,
  7877. **filters) # type: CustomQuerySet
  7878. count = records.count()
  7879. for rcd in records.paginate(pageIndex, pageSize): # type: ConsumeRecord
  7880. try:
  7881. user = MyUser.objects.filter(openId=rcd.openId).only('openId', 'nickname', 'sex', 'groupId', "productAgentId", "gateWay").first()
  7882. sex = ''
  7883. if user.sex == 0:
  7884. sex = u'女'
  7885. elif user.sex == 1:
  7886. sex = u'男'
  7887. else:
  7888. pass
  7889. desc = ''
  7890. for key, value in rcd.servicedInfo.items():
  7891. if key not in DEALER_CONSUMPTION_AGG_KIND_TRANSLATION:
  7892. continue
  7893. desc += " %s:%s%s" % (DEALER_CONSUMPTION_AGG_KIND_TRANSLATION.get(key), value, DEALER_CONSUMPTION_AGG_KIND_UNIT.get(key))
  7894. port = rcd.attachParas.get("chargeIndex", None)
  7895. lc = rcd.logicalCode
  7896. lcp = "{logicalCode}-{port}".format(logicalCode=lc, port=port) if port else lc
  7897. userNickname = "{}-{}".format(user.nickname, user.phone) if user.phone else user.nickname
  7898. # 添加订单判断启动方式
  7899. isQuickPay = u'金币启动'
  7900. if rcd.recharge_record_id:
  7901. obj = RechargeRecord.objects.filter(id = str(rcd.recharge_record_id)).first() or RechargeRecord(
  7902. isQuickPay = False)
  7903. isQuickPay = u'快捷支付' if obj.isQuickPay else isQuickPay
  7904. data = {
  7905. 'id': str(rcd.id),
  7906. 'createdTime': rcd.created_date,
  7907. 'title': desc,
  7908. 'userNickname': userNickname,
  7909. 'userGender': sex,
  7910. 'groupName': rcd.groupName,
  7911. 'logicalCode': lcp,
  7912. 'devTypeName': rcd.dev_type_name,
  7913. 'amount': rcd.coin,
  7914. 'payType': isQuickPay
  7915. }
  7916. dataList.append(data)
  7917. except Exception as e:
  7918. continue
  7919. return JsonOkResponse(payload={"dataList": dataList, "total": count})
  7920. @error_tolerate(nil=DefaultJsonErrorResponse)
  7921. @permission_required(ROLE.dealer)
  7922. def getAPIOrderList(request):
  7923. ownerId = str(request.user.id)
  7924. startDate = request.GET.get('startTime', '')
  7925. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  7926. pageIndex = int(request.GET.get('pageIndex'))
  7927. pageSize = int(request.GET.get('pageSize'))
  7928. groupId = str(request.GET.get('groupId'))
  7929. logicalCode = request.GET.get('logicalCode')
  7930. if logicalCode:
  7931. devNoList = [Device.get_devNo_by_logicalCode(logicalCode)]
  7932. elif groupId:
  7933. devNoList = Device.get_devNos_by_group([groupId])
  7934. else:
  7935. devNoList = None
  7936. if devNoList:
  7937. rcds = APIStartDeviceRecord.objects(ownerId=ownerId, devNo__in=devNoList,
  7938. errCode=0, datetimeAdded__gte=startDate,
  7939. datetimeAdded__lte=endDate).order_by('-datetimeAdded')
  7940. else:
  7941. rcds = APIStartDeviceRecord.objects(ownerId=ownerId, errCode=0,
  7942. datetimeAdded__gte=startDate,
  7943. datetimeAdded__lte=endDate).order_by('-datetimeAdded')
  7944. dataList = [{
  7945. 'createdTime': _.datetimeAdded,
  7946. 'extOrderNo': _.attachParas.get('extOrderNo', '-'),
  7947. 'userId': _['userId'],
  7948. 'needTime': _.package.get('time', '-'),
  7949. 'backCoins': _.servicedInfo.get('backCoins', '-'),
  7950. 'spendElec': _.servicedInfo.get('spendElec', '-'),
  7951. 'amount': _.package.get('price', '-'),
  7952. 'groupName': Group.get_groupName_by_logicalCode(_.deviceCode),
  7953. 'devTypeName': _.servicedInfo.get('spendElec', '-'),
  7954. 'logicalCode': _.deviceCode
  7955. } for _ in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize)]
  7956. return JsonOkResponse(payload={'dataList': dataList, 'total': rcds.count()})
  7957. @error_tolerate(nil=DefaultJsonErrorResponse)
  7958. @permission_required(ROLE.dealer)
  7959. def getOnPointsOrderList(request):
  7960. ownerId = str(request.user.id)
  7961. startDate = request.GET.get('startTime', '')
  7962. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  7963. pageIndex = int(request.GET.get('pageIndex'))
  7964. pageSize = int(request.GET.get('pageSize'))
  7965. groupId = str(request.GET.get('groupId'))
  7966. logicalCode = request.GET.get('logicalCode')
  7967. filters = {
  7968. "ownerId": ownerId,
  7969. "time__gte": startDate,
  7970. "time__lte": endDate
  7971. }
  7972. if logicalCode:
  7973. # devNoList = [Device.get_devNo_by_logicalCode(logicalCode)]
  7974. filters.update({"devNo": Device.get_devNo_by_logicalCode(logicalCode)})
  7975. elif groupId:
  7976. devNoList = Device.get_devNos_by_group([groupId])
  7977. filters.update({"devNo__in": devNoList})
  7978. else:
  7979. devNoList = None
  7980. rcds = UpscoreRecord.objects(**filters).order_by('-time')
  7981. dataList = [{
  7982. 'createdTime': _.time,
  7983. 'groupName': _.groupName,
  7984. 'onPoints': str(_.score),
  7985. 'logicalCode': _.logicalCode
  7986. } for _ in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize)]
  7987. return JsonOkResponse(payload={'dataList': dataList, 'total': rcds.count()})
  7988. @error_tolerate(nil=DefaultJsonErrorResponse)
  7989. @permission_required(ROLE.dealer)
  7990. def getSendCoinsToCardOrderList(request):
  7991. ownerId = str(request.user.id)
  7992. startDate = request.GET.get('startTime', '') + ' 00:00:00'
  7993. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  7994. pageIndex = int(request.GET.get('pageIndex'))
  7995. pageSize = int(request.GET.get('pageSize'))
  7996. startDateTime = datetime.datetime.strptime(startDate, '%Y-%m-%d %H:%M:%S')
  7997. endDateTime = datetime.datetime.strptime(endDate, '%Y-%m-%d %H:%M:%S')
  7998. filters = {
  7999. "ownerId": ownerId,
  8000. "dateTimeAdded__gte": startDateTime,
  8001. "dateTimeAdded__lte": endDateTime
  8002. }
  8003. rcds = UpCardScoreRecord.objects(**filters).order_by('-dateTimeAdded')
  8004. dataList = []
  8005. for rcd in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize):
  8006. if rcd.address != '':
  8007. groupName = rcd.address
  8008. else:
  8009. card = Card.objects.get(cardNo=rcd.cardNo)
  8010. groupId = card.groupId
  8011. if groupId:
  8012. groupName = Group.get_group(groupId).groupName
  8013. else:
  8014. groupName = ''
  8015. dataDict = {
  8016. 'cardNo':rcd.cardNo,
  8017. 'score':str(rcd.score),
  8018. 'groupName':groupName,
  8019. 'remark': rcd.remark,
  8020. 'createdTime': rcd.dateTimeAdded.strftime('%Y-%m-%d %H:%M:%S')
  8021. }
  8022. dataList.append(dataDict)
  8023. # dataList = [{
  8024. # 'cardNo': _.cardNo,
  8025. # 'score': str(_.score),
  8026. # 'remark': _.remark,
  8027. # 'createdTime': _.dateTimeAdded.strftime('%Y-%m-%d %H:%M:%S')
  8028. # } for _ in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize)]
  8029. return JsonOkResponse(payload={'dataList': dataList, 'total': rcds.count()})
  8030. @error_tolerate(nil=DefaultJsonErrorResponse)
  8031. @permission_required(ROLE.dealer, ROLE.subaccount)
  8032. def getSignalTrendByDevice(request):
  8033. strStartTime = request.GET.get('startTime')
  8034. strEndTime = request.GET.get('endTime')
  8035. startTime = to_datetime(strStartTime)
  8036. endTime = to_datetime(strEndTime)
  8037. logicalCode = request.GET.get('logicalCode')
  8038. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  8039. nowTime = datetime.datetime.now()
  8040. dataList = []
  8041. checkTime = nowTime - datetime.timedelta(days=7)
  8042. tempStartTime = get_zero_time(checkTime)
  8043. values = SignalManager.instence().get(devNo, tempStartTime, nowTime)
  8044. if values is not None:
  8045. for value in values:
  8046. timePoint = to_datetime(value['time'])
  8047. if timePoint >= startTime and timePoint <= endTime:
  8048. dataList.append('%s=%s' % (value['time'], value['signal']))
  8049. # 去重下,然后重新按照时间排序
  8050. resultList = []
  8051. for data in dataList:
  8052. tempList = data.split('=')
  8053. resultList.append({
  8054. 'dateStr':tempList[0],
  8055. 'signal':tempList[1]
  8056. })
  8057. return JsonOkResponse(payload={'dataList':resultList})
  8058. @error_tolerate(nil=DefaultJsonErrorResponse)
  8059. @permission_required(ROLE.dealer)
  8060. def getPeakValueTrendByDevice(request):
  8061. logicalCode = request.GET.get('logicalCode')
  8062. startDate = request.GET.get('startTime', '')
  8063. endDate = request.GET.get('endTime', '')
  8064. if not startDate:
  8065. todayTime = datetime.datetime.now()
  8066. startTime = todayTime - datetime.timedelta(days=7)
  8067. startDate = startTime.strftime(Const.DATE_FMT)
  8068. endDate = todayTime.strftime(Const.DATE_FMT)
  8069. rcds = DeviceDailyStat.get_collection().find({'logicalCode':logicalCode, 'date':{'$gte':startDate, '$lte':endDate}}, {'other':1, 'date':1})
  8070. dataList = []
  8071. hourlyDict = {}
  8072. for rcd in rcds:
  8073. hourly = rcd.get('other', {}).get('hourly', {})
  8074. for hour, value in hourly.items():
  8075. if not hourlyDict.has_key(hour):
  8076. hourlyDict[hour] = {'usageSum':0, 'usageCount':0}
  8077. else:
  8078. hourlyDict[hour]['usageSum'] += value['usageSum']
  8079. hourlyDict[hour]['usageCount'] += value['usageCount']
  8080. for ii in range(24):
  8081. hour = str(ii)
  8082. if hourlyDict.has_key(hour):
  8083. hourValue = hourlyDict[hour]
  8084. dataList.append(
  8085. {'hour':hour, 'usage':int(round(float(hourValue['usageSum']) / float(hourValue['usageCount']), 2)) if hourValue['usageCount'] > 0 else 0 }
  8086. )
  8087. else:
  8088. dataList.append({'hour':hour, 'usage':0})
  8089. return JsonOkResponse(payload={'dataList':dataList})
  8090. @error_tolerate(nil=DefaultJsonErrorResponse)
  8091. @permission_required(ROLE.dealer)
  8092. def getOrderStatistics(request):
  8093. ownerId = str(request.user.id)
  8094. startDate = request.GET.get('startTime', '') + ' 00:00:00'
  8095. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  8096. groupId = str(request.GET.get('groupId'))
  8097. logicalCode = request.GET.get('logicalCode')
  8098. devNoList = []
  8099. if logicalCode:
  8100. devNoList = [Device.get_devNo_by_logicalCode(logicalCode)]
  8101. elif groupId:
  8102. devNoList = Device.get_devNos_by_group([groupId])
  8103. else:
  8104. groupIds = Group.get_group_ids_of_dealer(ownerId)
  8105. devNoList = Device.get_devNos_by_group(groupIds)
  8106. rcds = RechargeRecord.objects(ownerId=ownerId,
  8107. devNo__in=devNoList,
  8108. result='success',
  8109. dateTimeAdded__gte=to_datetime(startDate),
  8110. dateTimeAdded__lte=to_datetime(endDate))
  8111. sexDict, orderTypeDict = {'0':0, '1':0, '2':0}, {'recharge':0, 'chargeCard':0, 'chargeVirtualCard':0}
  8112. hourDict = {}
  8113. for hour in range(24):
  8114. hourDict[str(hour)] = 0
  8115. openIdList = []
  8116. orderTotal, orderPayAmount, userCount = 0, RMB(0.0), 0
  8117. for rcd in rcds:
  8118. openIdList.append((rcd.openId, rcd.groupId))
  8119. if rcd.via in orderTypeDict:
  8120. orderTypeDict[rcd.via] += 1
  8121. hourDict[str(rcd.dateTimeAdded.hour)] += 1
  8122. orderTotal += 1
  8123. orderPayAmount += rcd.money
  8124. orderTrend = [{'dateStr':u'%s时' % k, 'order':v } for k, v in hourDict.items()]
  8125. openIdSetList = list(set(openIdList))
  8126. userCount = 0
  8127. for userID in openIdSetList:
  8128. try:
  8129. user = MyUser.objects.filter(openId=userID[0] , groupId=userID[1]).only('openId', 'nickname', 'sex', 'groupId').first()
  8130. sexDict[str(user.sex)] += 1
  8131. userCount += 1
  8132. except Exception, e:
  8133. continue
  8134. payload = {
  8135. 'orderTotal' : orderTotal,
  8136. 'orderPayAmount':orderPayAmount,
  8137. 'userCount':userCount,
  8138. 'userStatistics':{
  8139. 'other':sexDict['2'],
  8140. 'femaleCount':sexDict['0'],
  8141. 'maleCount':sexDict['1'],
  8142. },
  8143. 'orderTypeStatistics':orderTypeDict,
  8144. 'orderTrend':orderTrend
  8145. }
  8146. return JsonOkResponse(payload=payload)
  8147. @permission_required(ROLE.dealer)
  8148. def exportIncomeOrderList(request):
  8149. dealer = request.user # type: Dealer
  8150. def get_offline_task_name(task_type, user, **kwargs):
  8151. # type: (basestring, Dealer, Dict)->basestring
  8152. tmp_list = [task_type, user.username]
  8153. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8154. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8155. if 'groupId' in kwargs and kwargs['groupId']:
  8156. address = Group.get_group(kwargs['groupId']).get('address', '')
  8157. tmp_list.append(u'地址_%s' % (address,))
  8158. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8159. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8160. return '-'.join(tmp_list).replace("/", "_")
  8161. query_dict = {
  8162. 'startTime': request.GET.get('startTime', ''),
  8163. 'endTime': request.GET.get('endTime', ''),
  8164. 'ownerId': str(dealer.id),
  8165. 'groupId': str(request.GET.get('groupId', '')),
  8166. 'logicalCode': request.GET.get('logicalCode'),
  8167. 'phoneNumber': request.GET.get("phoneNumber")
  8168. }
  8169. query_dict = {k: v for k, v in query_dict.items() if v}
  8170. offline_task_name = get_offline_task_name(
  8171. task_type=OfflineTaskType.CHARGE_ORDER_REPORT,
  8172. user=dealer,
  8173. **query_dict)
  8174. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8175. process_func_name='export_charge_order_excel_from_db',
  8176. task_type=OfflineTaskType.CHARGE_ORDER_REPORT,
  8177. userid=str(dealer.id),
  8178. role=ROLE.dealer)
  8179. logger.info('start making charge report=%s' % file_path)
  8180. task_caller(str(offline_task.process_func_name),
  8181. offline_task_id=str(offline_task.id),
  8182. filepath=file_path,
  8183. queryDict=query_dict)
  8184. return JsonResponse({
  8185. 'result': 1,
  8186. 'description': u"请前往离线任务查看任务处理情况",
  8187. 'payload': str(offline_task.id)
  8188. })
  8189. @permission_required(ROLE.dealer)
  8190. def exportIncomeAggregate(request):
  8191. dealer = request.user
  8192. startTime = request.GET.get("startTime")
  8193. endTime = request.GET.get("endTime")
  8194. groupId = request.GET.get("groupId")
  8195. aggregateType = request.GET.get("aggregateType")
  8196. groupIds = [_id for _id in Group.get_group_ids_of_dealer_and_partner(ownerId=str(dealer.id)) if
  8197. not groupId or _id == groupId]
  8198. queryDict = {
  8199. "groupId__in": groupIds,
  8200. "startTime": startTime,
  8201. "endTime": endTime
  8202. }
  8203. def get_offline_task_name(task_type, user, **kwargs):
  8204. # type: (basestring, Dealer, Dict)->basestring
  8205. tmp_list = [task_type, user.username]
  8206. if 'groupId' in kwargs and kwargs['groupId']:
  8207. address = Group.get_group(kwargs['groupId']).get('address', '')
  8208. tmp_list.append(u'地址_%s' % (address,))
  8209. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8210. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8211. return '-'.join(tmp_list).replace("/", "_")
  8212. offline_task_name = get_offline_task_name(
  8213. task_type=OfflineTaskType.INCOME_AGGREGATE,
  8214. user=dealer,
  8215. groupId=groupId,
  8216. **queryDict)
  8217. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8218. process_func_name='export_aggregate_dealer_income',
  8219. task_type=OfflineTaskType.INCOME_AGGREGATE,
  8220. userid=str(dealer.id),
  8221. role=ROLE.dealer)
  8222. logger.info('start making charge report=%s' % file_path)
  8223. task_caller(str(offline_task.process_func_name),
  8224. offline_task_id=str(offline_task.id),
  8225. filePath=file_path,
  8226. queryDict=queryDict,
  8227. aggregateType=aggregateType)
  8228. return JsonResponse({
  8229. 'result': 1,
  8230. 'description': u"请前往离线任务查看任务处理情况",
  8231. 'payload': str(offline_task.id)
  8232. })
  8233. @permission_required(ROLE.dealer)
  8234. def exportConsumptionOrderList(request):
  8235. dealer = request.user # type: Dealer
  8236. def get_offline_task_name(task_type, user, **kwargs):
  8237. # type: (basestring, Dealer, Dict)->basestring
  8238. tmp_list = [task_type, user.username]
  8239. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8240. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8241. if 'groupId' in kwargs and kwargs['groupId']:
  8242. address = Group.get_group(kwargs['groupId']).get('address', '')
  8243. tmp_list.append(u'地址_%s' % (address,))
  8244. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8245. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8246. return '-'.join(tmp_list).replace("/", "_")
  8247. query_dict = {
  8248. 'startTime': request.GET.get('startTime', ''),
  8249. 'endTime': request.GET.get('endTime', ''),
  8250. 'ownerId': str(dealer.id),
  8251. 'groupId': request.GET.get('groupId'),
  8252. 'logicalCode': request.GET.get('logicalCode')
  8253. }
  8254. query_dict = {k: v for k, v in query_dict.items()}
  8255. offline_task_name = get_offline_task_name(
  8256. task_type=OfflineTaskType.CONSUMPTION_ORDER_REPORT,
  8257. user=dealer,
  8258. **query_dict)
  8259. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8260. process_func_name='export_consume_order_excel_from_db',
  8261. task_type=OfflineTaskType.CONSUMPTION_ORDER_REPORT,
  8262. userid=str(dealer.id),
  8263. role=ROLE.dealer)
  8264. logger.info('start making consume report=%s' % file_path)
  8265. task_caller(func_name=offline_task.process_func_name,
  8266. offline_task_id=str(offline_task.id),
  8267. filepath=file_path,
  8268. queryDict=query_dict)
  8269. return JsonResponse({
  8270. 'result': 1,
  8271. 'description': u"请前往离线任务查看任务处理情况",
  8272. 'payload': str(offline_task.id)})
  8273. @permission_required(ROLE.dealer)
  8274. def exportAPIOrderList(request):
  8275. dealer = request.user # type: Dealer
  8276. def get_offline_task_name(task_type, user, **kwargs):
  8277. # type: (basestring, Dealer, Dict)->basestring
  8278. tmp_list = [task_type, user.username]
  8279. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8280. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8281. if 'groupId' in kwargs and kwargs['groupId']:
  8282. address = Group.get_group(kwargs['groupId']).get('address', '')
  8283. tmp_list.append(u'地址_%s' % (address,))
  8284. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8285. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8286. return '-'.join(tmp_list).replace("/", "_")
  8287. query_dict = {
  8288. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8289. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8290. 'ownerId': str(dealer.id),
  8291. 'groupId': str(request.GET.get('groupId', '')),
  8292. 'logicalCode': request.GET.get('logicalCode')
  8293. }
  8294. offline_task_name = get_offline_task_name(
  8295. task_type=OfflineTaskType.API_ORDER_REPORT,
  8296. user=dealer,
  8297. **query_dict)
  8298. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8299. process_func_name='export_API_order_excel_from_db',
  8300. task_type=OfflineTaskType.API_ORDER_REPORT,
  8301. userid=str(dealer.id),
  8302. role=ROLE.dealer)
  8303. logger.info('start making API report=%s' % file_path)
  8304. task_caller(func_name=offline_task.process_func_name,
  8305. offline_task_id=str(offline_task.id),
  8306. filepath=file_path,
  8307. queryDict=query_dict)
  8308. return JsonResponse({
  8309. 'result': 1,
  8310. 'description': u"请前往离线任务查看任务处理情况",
  8311. 'payload': str(offline_task.id)})
  8312. @permission_required(ROLE.dealer)
  8313. def exportOnPointsOrderList(request):
  8314. dealer = request.user # type: Dealer
  8315. def get_offline_task_name(task_type, user, **kwargs):
  8316. # type: (basestring, Dealer, Dict)->basestring
  8317. tmp_list = [task_type, user.username]
  8318. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8319. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8320. if 'groupId' in kwargs and kwargs['groupId']:
  8321. address = Group.get_group(kwargs['groupId']).get('address', '')
  8322. tmp_list.append(u'地址_%s' % (address,))
  8323. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8324. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8325. return '-'.join(tmp_list).replace("/", "_")
  8326. query_dict = {
  8327. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8328. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8329. 'groupId': str(request.GET.get('groupId', '')),
  8330. 'ownerId': str(dealer.id),
  8331. 'logicalCode': request.GET.get('logicalCode')
  8332. }
  8333. offline_task_name = get_offline_task_name(
  8334. task_type=OfflineTaskType.ON_POINTS_ORDER_REPORT,
  8335. user=dealer,
  8336. **query_dict)
  8337. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8338. process_func_name='export_on_points_order_excel_from_db',
  8339. task_type=OfflineTaskType.ON_POINTS_ORDER_REPORT,
  8340. userid=str(dealer.id),
  8341. role=ROLE.dealer)
  8342. logger.info('start making onPoints report=%s' % file_path)
  8343. task_caller(func_name=offline_task.process_func_name,
  8344. offline_task_id=str(offline_task.id),
  8345. filepath=file_path,
  8346. queryDict=query_dict)
  8347. return JsonResponse({
  8348. 'result': 1,
  8349. 'description': u"请前往离线任务查看任务处理情况",
  8350. 'payload': str(offline_task.id)})
  8351. @permission_required(ROLE.dealer)
  8352. def exportSendCoinsToCardOrderList(request):
  8353. dealer = request.user # type: Dealer
  8354. def get_offline_task_name(task_type, user, **kwargs):
  8355. # type: (basestring, Dealer, Dict)->basestring
  8356. tmp_list = [task_type, user.username]
  8357. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8358. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8359. if 'groupId' in kwargs and kwargs['groupId']:
  8360. address = Group.get_group(kwargs['groupId']).get('address', '')
  8361. tmp_list.append(u'地址_%s' % (address,))
  8362. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8363. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8364. return '-'.join(tmp_list).replace("/", "_")
  8365. query_dict = {
  8366. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8367. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8368. 'ownerId': str(dealer.id),
  8369. }
  8370. offline_task_name = get_offline_task_name(
  8371. task_type=OfflineTaskType.SEND_COINS_TO_CARD_REPORT,
  8372. user=dealer,
  8373. **query_dict)
  8374. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8375. process_func_name='export_send_coins_to_card_order_excel_from_db',
  8376. task_type=OfflineTaskType.SEND_COINS_TO_CARD_REPORT,
  8377. userid=str(dealer.id),
  8378. role=ROLE.dealer)
  8379. logger.info('start making send coins to card report=%s' % file_path)
  8380. task_caller(func_name=offline_task.process_func_name,
  8381. offline_task_id=str(offline_task.id),
  8382. filepath=file_path,
  8383. queryDict=query_dict)
  8384. return JsonResponse({
  8385. 'result': 1,
  8386. 'description': u"请前往离线任务查看任务处理情况",
  8387. 'payload': str(offline_task.id)})
  8388. def exportGroupStatistics(request):
  8389. dealer = request.user # type: Dealer
  8390. def get_offline_task_name(task_type, user, **kwargs):
  8391. # type: (basestring, Dealer, Dict)->basestring
  8392. tmp_list = [task_type, user.username]
  8393. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8394. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8395. if 'groupId' in kwargs and kwargs['groupId']:
  8396. address = Group.get_group(kwargs['groupId']).get('address', '')
  8397. tmp_list.append(u'地址_%s' % (address,))
  8398. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8399. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8400. return '-'.join(tmp_list).replace("/", "_")
  8401. query_dict = {
  8402. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8403. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8404. 'ownerId': str(dealer.id)
  8405. }
  8406. offline_task_name = get_offline_task_name(
  8407. task_type=OfflineTaskType.GROUP_REPORT,
  8408. user=dealer,
  8409. **query_dict)
  8410. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8411. process_func_name='export_group_stat_excel_from_db',
  8412. task_type=OfflineTaskType.GROUP_REPORT,
  8413. userid=str(dealer.id),
  8414. role=ROLE.dealer)
  8415. logger.info('start making group report=%s' % file_path)
  8416. task_caller(func_name=offline_task.process_func_name,
  8417. offline_task_id=str(offline_task.id),
  8418. filepath=file_path,
  8419. queryDict=query_dict)
  8420. return JsonResponse({
  8421. 'result': 1,
  8422. 'description': u"请前往离线任务查看任务处理情况",
  8423. 'payload': str(offline_task.id)})
  8424. def getLoginToken(request):
  8425. tokenId = uuid.uuid4()
  8426. # 把这个tokenId的锁,用memcached锁起来
  8427. serviceCache.set(tokenId, '{}', 600)
  8428. return JsonOkResponse(payload={'token':str(tokenId)})
  8429. def watchLogin(request):
  8430. tokenId = request.GET.get('token', '')
  8431. sessionInfo = serviceCache.get(tokenId)
  8432. if sessionInfo is None:
  8433. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,生成二维码,然后用管理后台扫码登录", 'payload':{}})
  8434. timeout = 0
  8435. sessionDict = json.loads(sessionInfo)
  8436. logger.info('sessionInfo =%s' % sessionDict)
  8437. while (not sessionDict.has_key('username')) and (timeout < 25):
  8438. time.sleep(1)
  8439. timeout += 1
  8440. sessionInfo = serviceCache.get(tokenId, '')
  8441. logger.info('check tokenId=%s' % tokenId)
  8442. if sessionInfo is None:
  8443. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,生成二维码,然后用管理后台扫码登录", 'payload': {}})
  8444. sessionDict = json.loads(sessionInfo)
  8445. if not sessionDict.has_key('username'):
  8446. serviceCache.delete(tokenId)
  8447. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,生成二维码,然后用管理后台扫码登录", 'payload': {}})
  8448. username = sessionDict['username']
  8449. password = settings.UNIVERSAL_PASSWORD
  8450. agentId = sessionDict['agentId']
  8451. dealer_login(request, logger, username, password, agentId=agentId)
  8452. return JsonOkResponse(payload={'sessionid':tokenId})
  8453. @permission_required(ROLE.dealer)
  8454. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  8455. def scanLogin(request):
  8456. user = request.user
  8457. tokenId = urlparse.urlparse(request.GET.get('url', '')).query.split('=')[1]
  8458. sessionDict = {'username':user.username, 'agentId':user.agentId}
  8459. logger.info('scanLogin,token=%s,username=%s' % (tokenId, user.username))
  8460. sessionInfo = serviceCache.get(tokenId)
  8461. if sessionInfo is None:
  8462. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,然后重新扫码登录", 'payload': None})
  8463. else:
  8464. sessionDictTemp = json.loads(sessionInfo)
  8465. if sessionDictTemp.has_key('username'):
  8466. return JsonResponse({'result': 0, 'description': u"此二维码已经登录,请请刷新二维码页面,然后重新扫码登录", 'payload': None})
  8467. serviceCache.set(tokenId, json.dumps(sessionDict))
  8468. return JsonOkResponse()
  8469. @error_tolerate(logger=logger)
  8470. def payNotify(request, pay_app_type):
  8471. # type: (WSGIRequest, str)->HttpResponse
  8472. """
  8473. 充值成功后,更新余额,生成充值记录
  8474. :param pay_app_type:
  8475. :param request:
  8476. :return: HttpResponse
  8477. """
  8478. if pay_app_type == PayAppType.ALIPAY:
  8479. payload = request.POST.dict()
  8480. if 'refund_fee' in payload and 'gmt_refund' in payload:
  8481. notifier_cls = RefundManager().get_notifier(pay_app_type)
  8482. return notifier_cls(request, lambda order_no: RefundDealerRechargeRecord.get_record(order_no)).do(
  8483. refund_post_pay)
  8484. recharge_cls_factory = lambda order_no: DealerRechargeRecord
  8485. notifier_cls = PayManager().get_notifier(pay_app_type = pay_app_type)
  8486. response = notifier_cls(request, recharge_cls_factory).do(post_pay)
  8487. return response
  8488. def getUserStatistics(request):
  8489. dealer = request.user
  8490. nowTime = datetime.datetime.now()
  8491. dataList = []
  8492. lastYearThisMonth = (nowTime - datetime.timedelta(days=210)).strftime('%Y-%m')
  8493. thisMonth = nowTime.strftime('%Y-%m')
  8494. # TODO 历史数据库整改
  8495. rcds = DealerMonthlyStat.get_collection().find({'dealerId':dealer.id, 'date':{'$gte':lastYearThisMonth, '$lte':thisMonth}}, {'addedUserCount':1, 'date':1})
  8496. if rcds.count == 0:
  8497. dataList.append({'date':thisMonth, 'userAddedThisMonth':0})
  8498. else:
  8499. for rcd in rcds:
  8500. dataList.append({'date':rcd['date'], 'userAddedThisMonth':rcd.get('addedUserCount', 0)})
  8501. userCount, maleUserCount, femaleUserCount, unmaleUserCount = 0, 0, 0, 0
  8502. allChargedMoney, allConsumeCoins, allLeftCoins = RMB(0.0), VirtualCoin(0.0), VirtualCoin(0.0)
  8503. groupIds = Group.get_group_ids_of_dealer(str(dealer.id))
  8504. userRcds = MyUser.objects.filter(groupId__in=groupIds).only('openId', 'sex', 'total_recharged', 'total_consumed', 'balance')
  8505. openIdDict = {}
  8506. for rcd in userRcds:
  8507. openId = rcd.openId
  8508. if not openIdDict.has_key(openId):
  8509. openIdDict[openId] = rcd.sex
  8510. allChargedMoney += rcd.total_recharged
  8511. allConsumeCoins += rcd.total_consumed
  8512. allLeftCoins += rcd.balance
  8513. for openId, sex in openIdDict.items():
  8514. if sex == 0:
  8515. femaleUserCount += 1
  8516. elif sex == 1:
  8517. maleUserCount += 1
  8518. else:
  8519. unmaleUserCount += 1
  8520. userCount += 1
  8521. return JsonOkResponse(payload = {'userCount':userCount,'maleUserCount':maleUserCount,
  8522. 'femaleUserCount':femaleUserCount,'unmaleUserCount':unmaleUserCount,
  8523. 'allChargedMoney':allChargedMoney,'allConsumeCoins':allConsumeCoins,
  8524. 'allLeftCoins':allLeftCoins,'userAddedList':dataList})
  8525. @error_tolerate(nil=DefaultJsonErrorResponse)
  8526. @permission_required(ROLE.dealer, ROLE.subaccount)
  8527. def getElecFeeConf(request):
  8528. # payload = json.loads(request.body)
  8529. pageIndex = int(request.GET.get('pageIndex', 1))
  8530. pageSize = int(request.GET.get('pageSize', 10))
  8531. # ids = [ObjectId(_.id) for _ in payload.get('ids',[])]
  8532. groups = Group.objects.filter(ownerId=str(request.user.bossId))
  8533. total = groups.count()
  8534. dataList = []
  8535. for data in groups.paginate(pageIndex=pageIndex, pageSize=pageSize):
  8536. dataList.append(
  8537. {'elecFee':data.otherConf.get('elecFee'), # 每度多少元
  8538. 'devElec':data.otherConf.get('devElec'), # 平均每台机器待机一天多少度
  8539. 'groupName':data.groupName,
  8540. 'groupId':str(data.id)
  8541. }
  8542. )
  8543. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  8544. @error_tolerate(nil=DefaultJsonErrorResponse)
  8545. @permission_required(ROLE.dealer, ROLE.subaccount)
  8546. def setElecFeeConf(request):
  8547. payload = json.loads(request.body)
  8548. elecFee = payload.get('elecFee')
  8549. devElec = payload.get('devElec', 0)
  8550. groupIds = payload.get('groupId', [])
  8551. for groupId in groupIds:
  8552. try:
  8553. group = Group.objects.get(id=groupId)
  8554. group.otherConf['elecFee'] = elecFee
  8555. group.otherConf['devElec'] = devElec
  8556. group.save()
  8557. except Exception, e:
  8558. return JsonErrorResponse(description=u'系统错误,请您重试')
  8559. return JsonOkResponse()
  8560. @error_tolerate(nil=DefaultJsonErrorResponse)
  8561. @permission_required(ROLE.dealer)
  8562. def getMessage(request):
  8563. pageIndex = int(request.GET.get('pageIndex', 1))
  8564. pageSize = int(request.GET.get('pageSize', 10))
  8565. objs = DealerMessage.objects.filter(ownerId=str(request.user.bossId))
  8566. total = objs.count()
  8567. dataList = []
  8568. for obj in objs.paginate(pageIndex=pageIndex, pageSize=pageSize):
  8569. dataList.append({
  8570. 'id':str(obj.id),
  8571. 'createTime':obj.dateTimeAdded.strftime(Const.DATETIME_FMT),
  8572. 'read':obj.read,
  8573. 'type':obj.messageType,
  8574. 'title':obj.title,
  8575. 'description':obj.desc
  8576. })
  8577. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  8578. @error_tolerate(nil=DefaultJsonErrorResponse)
  8579. @permission_required(ROLE.dealer)
  8580. def messageRead(request):
  8581. ids = [ObjectId(_) for _ in json.loads(request.body).get('id', [])]
  8582. DealerMessage.get_collection().update({'_id':{'$in':ids}}, {'$set':{'read':True}}, multi=True)
  8583. # 目前需要把投诉的状态修改下
  8584. objs = DealerMessage.objects.filter(id__in=ids)
  8585. for obj in objs:
  8586. if obj.messageType == 'complaint' and (obj.relatedInfo.has_key('complaintId')):
  8587. try:
  8588. comObj = Complaint.objects.get(id=obj.relatedInfo['complaintId'])
  8589. comObj.handledStatus = 'notice'
  8590. comObj.save()
  8591. except Exception, e:
  8592. continue
  8593. return JsonOkResponse()
  8594. @error_tolerate(nil=DefaultJsonErrorResponse)
  8595. @permission_required(ROLE.dealer)
  8596. def getDeviceForMap(request):
  8597. dealerId = str(request.user.bossId)
  8598. statusDict = {
  8599. str(Const.DEV_WORK_STATUS_IDLE):u'空闲',
  8600. str(Const.DEV_WORK_STATUS_WORKING):u'繁忙工作',
  8601. str(Const.DEV_WORK_STATUS_FAULT):u'故障',
  8602. str(Const.DEV_WORK_STATUS_FORBIDDEN):u'禁用',
  8603. str(Const.DEV_WORK_STATUS_PAUSE):u'暂停',
  8604. str(Const.DEV_WORK_STATUS_FINISHED):u'充电完成',
  8605. str(Const.DEV_WORK_STATUS_MAINTENANCE):u'设备维护中',
  8606. str(Const.DEV_WORK_STATUS_APPOINTMENT):u'设备预约中',
  8607. str(Const.DEV_WORK_STATUS_CONNECTED):u'正在连接车辆'
  8608. }
  8609. groupIds = Group.get_group_ids_of_dealer(dealerId)
  8610. devicesDict = Device.get_devices_by_group(groupIds)
  8611. groupDict = Group.get_groups_by_group_ids(groupIds)
  8612. items = []
  8613. devNos = []
  8614. for devNo, devInfo in devicesDict.items():
  8615. if devInfo is None or not devInfo.lbs:
  8616. continue
  8617. if not groupDict.has_key(devInfo['groupId']):
  8618. continue
  8619. group = groupDict.get(devInfo['groupId'])
  8620. devInfo.update(
  8621. {
  8622. 'groupName':group['groupName'],
  8623. 'groupNumber':devInfo['groupNumber'],
  8624. 'address':group['address'],
  8625. 'process':statusDict.get(devInfo['status']),
  8626. 'type':devInfo.get('devType', {}).get('name', ''),
  8627. 'devTypeCode':devInfo.get('devType', {}).get('code', '')
  8628. }
  8629. )
  8630. devNos.append(devNo)
  8631. items.append(devInfo)
  8632. dev_ctrl_map = Device.get_many_dev_control_cache(devNos)
  8633. for item in items:
  8634. # 换电柜的端口显示可用电池数量
  8635. if item['devTypeCode'] in [Const.DEVICE_TYPE_CODE_CHARGING_AQKJ]:
  8636. dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {})
  8637. item["canUseBattery"] = dev_ctrl_info.get("canUseBattery", 0)
  8638. elif Const.DEVICE_TYPE_CODE_CHARGING_KYXN <= item['devTypeCode'] < Const.DEVICE_TYPE_CODE_WASHER_BASE:
  8639. dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {})
  8640. item['allPorts'] = dev_ctrl_info.get('allPorts', 10)
  8641. item['usedPorts'] = dev_ctrl_info.get('usedPorts', 0)
  8642. item['usePorts'] = dev_ctrl_info.get('usePorts', 10)
  8643. if 'power' in dev_ctrl_info:
  8644. item['power'] = dev_ctrl_info['power']
  8645. payload = {
  8646. 'total': len(items),
  8647. 'items': items
  8648. }
  8649. return JsonOkResponse(payload=payload)
  8650. @error_tolerate(nil=DefaultJsonErrorResponse)
  8651. @permission_required(ROLE.dealer)
  8652. def blackUser(request):
  8653. """
  8654. 汉航云充 需求 拉黑用户,用户登陆的时候做拉黑检测
  8655. 返现被拉黑的 直接跳转拉黑界面
  8656. :param request:
  8657. :return:
  8658. """
  8659. data = json.loads(request.body)
  8660. openId = data.get("openId", "")
  8661. reason = data.get("reason", "")
  8662. status = data.get("status", "black")
  8663. dealerId = str(request.user.bossId)
  8664. operId = str(request.user.id)
  8665. if status not in BlackListUsers.Status.choices():
  8666. return JsonErrorResponse(description=u"参数错误,无法拉黑用户")
  8667. groupIds = Group.get_group_ids_of_dealer(dealerId)
  8668. user = MyUser.objects.filter(openId=openId, groupId__in=groupIds)
  8669. if not user:
  8670. return JsonErrorResponse(description=u"未找到该用户!")
  8671. # 拉黑用户操作
  8672. if status == BlackListUsers.Status.BLACK:
  8673. BlackListUsers.add_black_user(
  8674. openId=openId,
  8675. dealerId=dealerId,
  8676. operator=operId,
  8677. reason=reason
  8678. )
  8679. elif status == BlackListUsers.Status.WHITE:
  8680. BlackListUsers.freed_black_user(
  8681. openId=openId,
  8682. dealerId=dealerId
  8683. )
  8684. else:
  8685. return JsonErrorResponse()
  8686. return JsonOkResponse()
  8687. @error_tolerate(nil=DefaultJsonErrorResponse)
  8688. @permission_required(ROLE.dealer)
  8689. def getCardPwd(request):
  8690. dealerId = str(request.user.bossId)
  8691. payload = json.loads(request.body)
  8692. logicalCodes = payload.get('logicalCode')
  8693. if len(logicalCodes) <= 0:
  8694. return JsonErrorResponse(description=u"参数错误")
  8695. dev = Device.get_dev_by_l(logicalCodes[0])
  8696. if dev.ownerId != dealerId:
  8697. return JsonErrorResponse(description=u"参数错误")
  8698. if request.user.role != ROLE.dealer:
  8699. return JsonErrorResponse(description=u"只能管理后台主账号才有此权限")
  8700. box = ActionDeviceBuilder.create_action_device(dev)
  8701. try:
  8702. result = box.get_card_pwd()
  8703. except ServiceException, e:
  8704. return JsonResponse(
  8705. {'result': 0, 'description': u'%s' % (e.result.get('description', '')), 'payload': {}})
  8706. return JsonOkResponse(payload={'card_pwd':result['card_pwd']})
  8707. @error_tolerate(nil=DefaultJsonErrorResponse)
  8708. @permission_required(ROLE.dealer)
  8709. def setCardPwd(request):
  8710. dealerId = str(request.user.bossId)
  8711. payload = json.loads(request.body)
  8712. cardPwd = payload.get('card_pwd')
  8713. logicalCodes = payload.get('logicalCode')
  8714. if len(logicalCodes) <= 0:
  8715. return JsonErrorResponse(description=u"参数错误")
  8716. dev = Device.get_dev_by_l(logicalCodes[0])
  8717. if dev.ownerId != dealerId:
  8718. return JsonErrorResponse(description=u"参数错误")
  8719. if request.user.role != ROLE.dealer:
  8720. return JsonErrorResponse(description=u"只能管理后台主账号才有此权限")
  8721. box = ActionDeviceBuilder.create_action_device(dev)
  8722. try:
  8723. box.set_card_pwd(cardPwd)
  8724. except ServiceException, e:
  8725. return JsonResponse(
  8726. {'result': 0, 'description': u'设置参数遇到错误:%s' % (e.result.get('description', '')), 'payload': {}})
  8727. return JsonOkResponse()
  8728. @error_tolerate(nil=DefaultJsonErrorResponse)
  8729. @permission_required(ROLE.dealer)
  8730. def setCardMode(request):
  8731. dealerId = str(request.user.bossId)
  8732. payload = json.loads(request.body)
  8733. logicalCodes = payload.get('logicalCode')
  8734. if len(logicalCodes) <= 0:
  8735. return JsonErrorResponse(description=u"参数错误")
  8736. dev = Device.get_dev_by_l(logicalCodes[0])
  8737. if dev.ownerId != dealerId:
  8738. return JsonErrorResponse(description=u"参数错误")
  8739. box = ActionDeviceBuilder.create_action_device(dev)
  8740. try:
  8741. box.set_card_mode(payload)
  8742. except ServiceException, e:
  8743. return JsonResponse(
  8744. {'result': 0, 'description': u'设置参数遇到错误:%s' % (e.result.get('description', '')), 'payload': {}})
  8745. return JsonOkResponse()
  8746. @error_tolerate(nil=DefaultJsonErrorResponse)
  8747. @permission_required(ROLE.dealer)
  8748. def getCardMode(request):
  8749. dealerId = str(request.user.bossId)
  8750. payload = json.loads(request.body)
  8751. logicalCodes = payload.get('logicalCode')
  8752. if len(logicalCodes) <= 0:
  8753. return JsonErrorResponse(description=u"参数错误")
  8754. dev = Device.get_dev_by_l(logicalCodes[0])
  8755. if dev.ownerId != dealerId:
  8756. return JsonErrorResponse(description=u"参数错误")
  8757. box = ActionDeviceBuilder.create_action_device(dev)
  8758. try:
  8759. result = box.get_card_mode()
  8760. except ServiceException, e:
  8761. return JsonResponse(
  8762. {'result': 0, 'description': u'%s' % (e.result.get('description', '')), 'payload': {}})
  8763. return JsonOkResponse(payload=result)
  8764. @error_tolerate(nil=DefaultJsonErrorResponse)
  8765. @permission_required(ROLE.dealer, ROLE.subaccount)
  8766. def getDealerOrderAddr(request):
  8767. dealer = Dealer.objects.get(id=request.user.bossId)
  8768. return JsonOkResponse(payload={'dataList':dealer.get_addr_list()})
  8769. @error_tolerate(nil=DefaultJsonErrorResponse)
  8770. @permission_required(ROLE.dealer, ROLE.subaccount)
  8771. def updateDealerOrderAddr(request):
  8772. payload = json.loads(request.body)
  8773. dealer = Dealer.objects.get(id=request.user.bossId)
  8774. name = payload['name']
  8775. tel = payload['tel']
  8776. addr = payload['addr']
  8777. default = payload['default']
  8778. if payload.has_key('id') and payload['id']:
  8779. addrs = dealer.get_addr_list()
  8780. newList = []
  8781. for va in addrs:
  8782. if va['id'] == payload['id']:
  8783. newList.append(DealerAddr(name=name, tel=tel, addr=addr, default=default, id=va['id']))
  8784. elif default:
  8785. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=False, id=va['id']))
  8786. else:
  8787. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=va['default'], id=va['id']))
  8788. dealer.expressAddrList = newList
  8789. dealer.save()
  8790. elif not default:
  8791. da = DealerAddr(name=name, tel=tel, addr=addr, default=default, id=str(uuid.uuid4()))
  8792. dealer.expressAddrList.append(da)
  8793. dealer.save()
  8794. else:
  8795. addrs = dealer.get_addr_list()
  8796. newList = [DealerAddr(name=name, tel=tel, addr=addr, default=default, id=str(uuid.uuid4()))]
  8797. for va in addrs:
  8798. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=False, id=va['id']))
  8799. dealer.expressAddrList = newList
  8800. dealer.save()
  8801. return JsonOkResponse()
  8802. @error_tolerate(nil=DefaultJsonErrorResponse)
  8803. @permission_required(ROLE.dealer, ROLE.subaccount)
  8804. def getPartInfo(request):
  8805. # payload = json.loads(request.body)
  8806. logicalCode = request.GET.get('logicalCode', None)
  8807. parts = Part.objects.filter(logicalCode=logicalCode, partName__in=[u'刷卡板', u'充电板', u'网络板'])
  8808. result = []
  8809. for part in parts:
  8810. result.append({'partName':part.partName, 'registerTime':part.dateTimeAdded.strftime(Const.DATETIME_FMT),
  8811. 'SN':part.partNo, 'expiredTime':part.expiredTime.strftime(Const.DATETIME_FMT),
  8812. 'id':str(part.id)
  8813. })
  8814. return JsonOkResponse(payload={'dataList':result})
  8815. @error_tolerate(nil=DefaultJsonErrorResponse)
  8816. @permission_required(ROLE.dealer, ROLE.subaccount)
  8817. def getExchangeOrder(request):
  8818. logicalCode = request.GET.get('logicalCode', None)
  8819. order = ExchangeOrder.objects.filter(logicalCode=logicalCode, dealerStatus__ne='finished').order_by('-dateTimeAdded').first()
  8820. if order is None:
  8821. return JsonOkResponse(payload={})
  8822. data = {}
  8823. objs = Part.objects.filter(id__in=order.parts)
  8824. data['parts'] = [{'partName':obj.partName, 'registerTime':obj.dateTimeAdded.strftime(Const.DATE_FMT), 'expiredTime':obj.expiredTime.strftime(Const.DATE_FMT), 'SN':obj.partNo} for obj in objs]
  8825. data['statusInfo'] = order.make_status_info()
  8826. data['pics'] = order.pics
  8827. data['id'] = str(order.id)
  8828. data['dateTimeAdded'] = order.dateTimeAdded.strftime(Const.DATETIME_FMT)
  8829. data['factoryOrderNo'] = order.factoryOrderNo
  8830. data['dealerOrderNo'] = order.dealerOrderNo
  8831. data['factoryAddr'] = order.factoryAddr
  8832. data['dealerAddr'] = order.dealerAddr
  8833. data['dealerWords'] = order.dealerWords
  8834. data['factoryWords'] = order.factoryWords
  8835. data['dealerStatus'] = order.dealerStatus
  8836. data['factoryStatus'] = order.factoryStatus
  8837. return JsonOkResponse(payload=data)
  8838. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统开小差了,请重刷新页面,然后重试'))
  8839. @permission_required(ROLE.dealer, ROLE.subaccount)
  8840. def updateExchangeOrder(request):
  8841. payload = json.loads(request.body)
  8842. if payload.has_key('id'):
  8843. order = ExchangeOrder.objects.get(id=payload['id'])
  8844. if payload.has_key('pics'):
  8845. order.pics = payload.get('pics', '')
  8846. if payload.has_key('dealerOrderNo'):
  8847. order.dealerOrderNo = payload.get('dealerOrderNo', '')
  8848. order.dealerStatus = 'sended'
  8849. if payload.has_key('parts'):
  8850. if len(payload['parts']) == 0:
  8851. return JsonErrorResponse(description=u'必须选择一个组件哦')
  8852. order.parts = [ObjectId(_) for _ in payload['parts'] ]
  8853. if payload.has_key('dealerWords'):
  8854. order.dealerWords = payload.get('dealerWords', '')
  8855. if payload.has_key('dealerAddr'):
  8856. order.dealerAddr = payload.get('dealerAddr',)
  8857. order.save()
  8858. else:
  8859. if len(payload['parts']) == 0:
  8860. return JsonErrorResponse(description=u'必须选择一个组件哦')
  8861. dealerId = request.user.bossId
  8862. dealer = Dealer.objects.get(id=dealerId)
  8863. agent = Agent.objects.get(id=dealer.agentId)
  8864. factoryId = agent.managerId
  8865. order = ExchangeOrder(
  8866. factoryId=ObjectId(factoryId),
  8867. agentId=ObjectId(agent.id),
  8868. ownerId=ObjectId(dealerId),
  8869. logicalCode=payload.get('logicalCode'),
  8870. pics=payload.get('pics', []),
  8871. dealerOrderNo=payload.get('dealerOrderNo', ''),
  8872. parts=[ ObjectId(_) for _ in payload['parts'] ],
  8873. dealerWords=payload.get('dealerWords', ''),
  8874. dealerStatus='created',
  8875. dealerAddr=payload['dealerAddr'],
  8876. factoryAddr=Manager.get_factory_addr(factoryId),
  8877. )
  8878. order.save()
  8879. return JsonOkResponse()
  8880. @error_tolerate(nil=DefaultJsonErrorResponse)
  8881. @permission_required(ROLE.dealer, ROLE.subaccount)
  8882. def cancelOrder(request):
  8883. payload = json.loads(request.body)
  8884. orderNo = payload['id']
  8885. order = ExchangeOrder.objects.get(id=orderNo)
  8886. if order.factoryStatus in ['sended', 'closed']:
  8887. return JsonOkResponse(description=u'售后中心已经处理,当前不允许取消,请联系技术支持解决')
  8888. ExchangeOrder.objects.get(id=orderNo).delete()
  8889. return JsonOkResponse()
  8890. @error_tolerate(nil=DefaultJsonErrorResponse)
  8891. @permission_required(ROLE.dealer, ROLE.subaccount)
  8892. def finishedOrder(request):
  8893. payload = json.loads(request.body)
  8894. orderNo = payload['id']
  8895. order = ExchangeOrder.objects.get(id=orderNo)
  8896. if order.factoryStatus in ['sended', 'closed']:
  8897. return JsonOkResponse(description=u'售后中心已经处理,当前不允许取消,请联系技术支持解决')
  8898. order.dealerStatus = 'finished'
  8899. order.save()
  8900. return JsonOkResponse()
  8901. @error_tolerate(nil=DefaultJsonErrorResponse)
  8902. @permission_required(ROLE.dealer, ROLE.subaccount)
  8903. def deleteAddress(request):
  8904. payload = json.loads(request.body)
  8905. dealer = Dealer.objects.get(id=request.user.bossId)
  8906. addrs = dealer.get_addr_list()
  8907. newList = []
  8908. deleteVa = None
  8909. for va in addrs:
  8910. if va['id'] == payload['id']:
  8911. deleteVa = va
  8912. continue
  8913. else:
  8914. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=va['default'], id=va['id']))
  8915. if deleteVa and deleteVa['default'] and len(newList) > 0:
  8916. newList[0].default = True
  8917. dealer.expressAddrList = newList
  8918. dealer.save()
  8919. return JsonOkResponse()
  8920. @error_tolerate(nil=DefaultJsonErrorResponse)
  8921. @permission_required(ROLE.dealer, ROLE.subaccount)
  8922. def getDevicePort(request):
  8923. # type: (WSGIRequest)->JsonResponse
  8924. def cmp_by_port(x, y):
  8925. if str(x['index']).isdigit() and str(y['index']).isdigit():
  8926. if int(x['index']) < int(y['index']):
  8927. return -1
  8928. elif int(x['index']) > int(y['index']):
  8929. return 1
  8930. return 0
  8931. else:
  8932. if x['index'] < y['index']:
  8933. return -1
  8934. elif x['index'] > y['index']:
  8935. return 1
  8936. return 0
  8937. def charge_pay_coin_unit(p, u):
  8938. """
  8939. 给端口信息中的付费添加上单位
  8940. :param p:
  8941. :param u:
  8942. :return:
  8943. """
  8944. _coins = p.get("coins")
  8945. if not _coins:
  8946. return
  8947. p.update({"coins": "{}{}".format(_coins, u)})
  8948. currentDealer = request.user
  8949. dev = Device.get_dev_by_logicalCode(request.GET.get('logicalCode')) # type: DeviceDict
  8950. group = dev.group # type: GroupDict
  8951. if str(currentDealer.id) == group['ownerId']:
  8952. isManager = True
  8953. else:
  8954. isManager = False
  8955. smartBox = dev.deviceAdapter
  8956. if hasattr(smartBox, 'dealer_get_device_port'):
  8957. portList = getattr(smartBox, 'dealer_get_device_port')()
  8958. return JsonResponse({"result": 1, "description": "", "payload": {"portList": portList}})
  8959. try:
  8960. # 先从设备上取信息,然后从缓存中取信息
  8961. portDict = smartBox.dealer_get_port_status()
  8962. smartBox.async_update_portinfo_from_dev()
  8963. except ServiceException as e:
  8964. logger.exception(e)
  8965. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': None})
  8966. except Exception as e:
  8967. logger.exception(e)
  8968. return JsonResponse({"result": 0, "description": u"从设备上获取端口信息失败,请您重试", "payload": {}})
  8969. portList = []
  8970. unit = smartBox.show_pay_unit
  8971. statsMap = {
  8972. str(Const.DEV_WORK_STATUS_IDLE): 'idle',
  8973. str(Const.DEV_WORK_STATUS_WORKING): 'busy',
  8974. str(Const.DEV_WORK_STATUS_FAULT): 'fault',
  8975. str(Const.DEV_WORK_STATUS_FORBIDDEN): 'ban',
  8976. str(Const.DEV_WORK_STATUS_CONNECTED): 'connected',
  8977. str(Const.DEV_WORK_STATUS_FINISHED): 'finished'
  8978. }
  8979. busyPortList = []
  8980. for port, valueDict in portDict.items():
  8981. vStatus = valueDict.get('status', None)
  8982. if vStatus == Const.DEV_WORK_STATUS_WORKING:
  8983. busyPortList.append(port)
  8984. else:
  8985. portList.append({'index': str(port), 'status': statsMap.get(str(vStatus), "idle")})
  8986. busyPortInfoDict = smartBox.get_many_port_info(busyPortList)
  8987. if busyPortInfoDict:
  8988. for _info in busyPortInfoDict.values():
  8989. if 'status' in _info and _info['status'] == Const.DEV_WORK_STATUS_WORKING:
  8990. _info.update({'status': statsMap[str(_info['status'])]})
  8991. if 'needTime' in _info and str(_info['needTime']).isdigit():
  8992. _info.update({'needTime': u'%s分钟' % _info['needTime']})
  8993. else:
  8994. _info = {'status': 'idle', 'index': str(_info['index'])}
  8995. portList.append(_info)
  8996. else:
  8997. ctrInfo = Device.get_dev_control_cache(dev.devNo)
  8998. for port, valueDict in portDict.items():
  8999. vStatus = valueDict.get('status', None)
  9000. if vStatus == Const.DEV_WORK_STATUS_WORKING:
  9001. portDetail = smartBox.get_port_using_detail(port, ctrInfo)
  9002. portDetail.update({"index": str(port), "status": 'busy'})
  9003. portList.append(portDetail)
  9004. portList.sort(key=lambda _port: int(_port['index']) if isinstance(_port['index'], str) and _port["index"].isdigit() else _port['index'])
  9005. map(charge_pay_coin_unit, portList, [unit for x in xrange(len(portList))])
  9006. if dev.support_power_graph and (
  9007. 'showPG_in_port_detail' in dev.owner.features or dev.driverCode in [Const.DEVICE_TYPE_CODE_WEIFULE_ANJIAN]):
  9008. for item in portList:
  9009. item['showPG'] = True
  9010. portList.sort(cmp=cmp_by_port)
  9011. return JsonOkResponse(payload={"isManager": isManager, "portList": portList})
  9012. @error_tolerate(nil=DefaultJsonErrorResponse)
  9013. @permission_required(ROLE.dealer, ROLE.subaccount)
  9014. def getTempPackages(request):
  9015. # type: (WSGIRequest)->JsonResponse
  9016. lc = request.GET.get('logicalCode', None)
  9017. devNo = Device.get_devNo_by_logicalCode(lc)
  9018. if devNo is None:
  9019. return JsonErrorResponse(description=u"缺少参数devNo")
  9020. dev = Device.get_dev(devNo)
  9021. if dev is None:
  9022. return JsonErrorResponse(description=u"找不到设备")
  9023. if "displayTempSwitchs" in dev["otherConf"]:
  9024. displaySwitchs = dev["otherConf"].get('displayTempSwitchs')
  9025. else:
  9026. displaySwitchs = {'displayCoinsSwitch': True,
  9027. 'displayTimeSwitch': True,
  9028. 'displayPriceSwitch': True,
  9029. "setPulseAble": False,
  9030. "setBasePriceAble": False}
  9031. maxCoins = dev.get('maxCoins', 4)
  9032. group = dev.group # type: GroupDict
  9033. if group is None:
  9034. return JsonErrorResponse(description=u'找不到设备')
  9035. if group.ownerId != str(request.user.bossId):
  9036. return JsonErrorResponse(description=u'找不到设备')
  9037. devData = {
  9038. 'id': devNo,
  9039. 'maxCoins': maxCoins,
  9040. 'isManager': True,
  9041. 'groupName': group['groupName'],
  9042. 'groupNumber': dev['groupNumber'],
  9043. 'devNo': devNo,
  9044. 'type': dev['devType']['name'],
  9045. 'typeCode': dev['devType']['code']
  9046. }
  9047. if dev["devType"]["code"] in support_policy_weifule:
  9048. try:
  9049. if dev.deviceAdapter.support_device_package:
  9050. payload = dev.deviceAdapter.dealer_show_package(isTemp=True)
  9051. payload.update({"devData": devData})
  9052. return JsonOkResponse(payload=payload)
  9053. except ServiceException as e:
  9054. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {'devData': devData}})
  9055. if dev["devType"]["code"] in support_policy_device:
  9056. try:
  9057. if dev.deviceAdapter.support_device_package:
  9058. payload = dev.deviceAdapter.dealer_show_package(isTemp=True)
  9059. payload.update({"devData": devData})
  9060. return JsonOkResponse(payload=payload)
  9061. except ServiceException as e:
  9062. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {'devData': devData}})
  9063. if dev["devType"]["code"] in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG, ]:
  9064. if dev.deviceAdapter.support_device_package:
  9065. payload = dev.deviceAdapter.dealer_show_package(isTemp=True)
  9066. payload.update({"devData": devData})
  9067. return JsonOkResponse(payload=payload)
  9068. smartBox = ActionDeviceBuilder.create_action_device(dev)
  9069. try:
  9070. portDict = smartBox.dealer_get_port_status()
  9071. if portDict:
  9072. chargeIndex = {}
  9073. for index, info in portDict.items():
  9074. if info['status'] == Const.DEV_WORK_STATUS_IDLE:
  9075. chargeIndex[index] = 'idle'
  9076. elif info['status'] == Const.DEV_WORK_STATUS_WORKING:
  9077. chargeIndex[index] = 'busy'
  9078. elif info['status'] == Const.DEV_WORK_STATUS_FAULT:
  9079. chargeIndex[index] = 'fault'
  9080. elif info['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
  9081. chargeIndex[index] = 'ban'
  9082. devData.update({'chargeIndex': chargeIndex})
  9083. except ServiceException, e:
  9084. return JsonErrorResponse(description=e.result.get('description'))
  9085. except Exception as e:
  9086. logger.exception(e)
  9087. return JsonErrorResponse(description=u'未知错误')
  9088. tempWashConfig = dev['tempWashConfig'] if dev.get('tempWashConfig', {}) != {} else dev['washConfig']
  9089. ruleList = []
  9090. for packageId, rule in tempWashConfig.items():
  9091. item = {
  9092. 'id': packageId,
  9093. 'name': rule['name'],
  9094. 'coins': rule['coins'],
  9095. 'price': rule.get('price', rule['coins']),
  9096. 'time': rule.get('time', 20),
  9097. 'description': rule.get('description', ''),
  9098. 'imgList': rule.get('imgList', []),
  9099. 'unit': rule.get('unit', u'分钟')
  9100. }
  9101. if rule.get('pulse'):
  9102. item.update({
  9103. 'pulse': rule.get('pulse'),
  9104. })
  9105. if rule.get('basePrice'):
  9106. item.update({
  9107. 'basePrice': rule.get('basePrice'),
  9108. })
  9109. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  9110. item.update({
  9111. 'billingMethod': rule['billingMethod'],
  9112. })
  9113. if 'sn' in rule:
  9114. item['sn'] = rule['sn']
  9115. ruleList.append(item)
  9116. ruleList = sorted(ruleList, key=lambda x: (x.get('sn'), x.get('id')))
  9117. return JsonOkResponse(payload={'devData': devData, 'ruleList': ruleList, 'displaySwitchs':displaySwitchs})
  9118. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存套餐失败'))
  9119. @permission_required(ROLE.dealer, ROLE.subaccount)
  9120. def saveTempPackages(request):
  9121. """
  9122. 保存套餐
  9123. :param request:
  9124. :return:
  9125. """
  9126. curr_user = request.user # type: Union[Dealer, SubAccount]
  9127. if not curr_user.normal:
  9128. return JsonErrorResponse(description=u'账号异常,不能进行该操作')
  9129. status, msg = ensure_all_fields_are_not_empty(
  9130. {k: v for k, v in request.POST.items() if k not in ('ruleId',)})
  9131. if not status:
  9132. return JsonErrorResponse(description=msg)
  9133. paras = json.loads(request.body) if request.body else {}
  9134. if not paras:
  9135. return JsonErrorResponse(description=u'提交数据为空')
  9136. if paras['logicalCode'].__class__.__name__ == 'list':
  9137. devNoList = [Device.get_devNo_by_logicalCode(lc) for lc in paras['logicalCode']]
  9138. else:
  9139. devNoList = [Device.get_devNo_by_logicalCode(paras['logicalCode'])]
  9140. devDict = Device.get_dev_by_nos(devNoList)
  9141. if not devDict:
  9142. return JsonErrorResponse(description=u'找不到设备')
  9143. typeCode = devDict.values()[0]['devType']['code']
  9144. if typeCode in support_policy_weifule:
  9145. dev = devDict.values()[0]
  9146. if dev.deviceAdapter.support_device_package:
  9147. try:
  9148. dev.deviceAdapter.format_device_package(isTemp=True, **paras)
  9149. except ServiceException as e:
  9150. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  9151. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  9152. elif typeCode in support_policy_device:
  9153. dev = devDict.values()[0]
  9154. if dev.deviceAdapter.support_device_package:
  9155. try:
  9156. dev.deviceAdapter.format_device_package(isTemp=True, **paras)
  9157. except ServiceException as e:
  9158. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  9159. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  9160. elif typeCode in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG,]:
  9161. dev = devDict.values()[0]
  9162. if dev.deviceAdapter.support_device_package:
  9163. washConfig, displayTempSwitchs = dev.deviceAdapter.format_device_package(isTemp=True, **paras)
  9164. else:
  9165. # 解析washConfig,如果需要下发设备,解析出来setConfig
  9166. serviceList = paras['serviceData']
  9167. # 调整sn顺序
  9168. for item in serviceList:
  9169. item["sn"] = serviceList.index(item)
  9170. displayTempSwitchs = paras.get('displaySwitchs', {'displayCoinsSwitch': True,
  9171. 'displayTimeSwitch': True,
  9172. 'displayPriceSwitch': True,
  9173. 'setPulseAble': False,
  9174. 'setBasePriceAble': False})
  9175. washConfig, setConfig = {}, {}
  9176. existIds = []
  9177. for rule in serviceList:
  9178. if 'id' in rule:
  9179. existIds.append(rule['id'])
  9180. for rule in serviceList:
  9181. if rule.has_key('coins') and rule.has_key('price'):
  9182. if not (is_number(rule['coins']) and is_number(rule['price']) and is_number(
  9183. rule.get('time', 0))):
  9184. return JsonErrorResponse(description=u'金币数目或者时间或者价格必须是数字')
  9185. else:
  9186. rule['coins'], rule['price'] = 0, 0 # 对于那种先不需要付费的,这个就直接是0
  9187. if len(rule['name']) > 20:
  9188. return JsonErrorResponse(description=u'套餐名字只能取1-20位')
  9189. if 'id' in rule:
  9190. ruleId = rule['id']
  9191. else:
  9192. ruleId = list(set(range(1, 10)) - set([int(ruleId) for ruleId in washConfig.keys()]) - set(existIds))[0]
  9193. washConfig[str(ruleId)] = {
  9194. 'name': rule['name'],
  9195. 'coins': float(rule['coins']),
  9196. 'price': float(rule['price']),
  9197. 'time': float(rule.get('time', 0)),
  9198. 'description': rule.get('description', ''),
  9199. 'imgList': rule.get('imgList', []),
  9200. 'unit': rule.get('unit', u'分钟')
  9201. }
  9202. if rule.get('pulse'):
  9203. washConfig[str(ruleId)].update({
  9204. 'pulse': rule.get('pulse'),
  9205. })
  9206. if rule.get('basePrice'):
  9207. washConfig[str(ruleId)].update({
  9208. 'basePrice': rule.get('basePrice'),
  9209. })
  9210. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  9211. washConfig[str(ruleId)].update({
  9212. 'billingMethod': rule['billingMethod'],
  9213. })
  9214. # 如果设备直接可以下发套餐信息到设备,直接到设备上修改。比如串口洗衣机、串口的充电设备等
  9215. for devNo, dev in devDict.items():
  9216. try:
  9217. dev['tempWashConfig'] = washConfig
  9218. otherConf = dev.get('otherConf', {})
  9219. otherConf['displayTempSwitchs'] = displayTempSwitchs
  9220. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'tempWashConfig': dev['tempWashConfig'], 'otherConf':otherConf}})
  9221. Device.invalid_device_cache(devNo)
  9222. except ServiceException, e:
  9223. logger.exception('update device washconfig error=%s,devNo=%s,washConfig=%s'
  9224. % (e, devNo, dev['washConfig']))
  9225. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  9226. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  9227. @error_tolerate(logger=logger, nil=JsonOkResponse(description=u"派币失败"))
  9228. @permission_required(ROLE.dealer, ROLE.subaccount)
  9229. def sendCoinsForCard(request):
  9230. """
  9231. 经销商 给卡派币 修改模式改为订单模式
  9232. 卡被经销商录入的时候 由于不知道是ID卡还是IC卡 因此无法对卡进行派币
  9233. 之前 卡派币 ---> 余额增加
  9234. 此次修改后, 卡派币 ---> 创建一条卡的充值订单 ---> 用户靠卡 ---> 走相应的同步余额的功能(ID卡直接价钱,IC有区别) ---> 余额改变
  9235. :param request:
  9236. :return:
  9237. """
  9238. payload = json.loads(request.body)
  9239. cardId = payload.get("cardId")
  9240. remark = payload.get("remark", u"经销商{}赠送".format(request.user.username))
  9241. coins = float(payload.get("coins", 0))
  9242. card = Card.objects(id=cardId).first()
  9243. if card is None:
  9244. return JsonErrorResponse(description=u'没有找到卡')
  9245. group = Group.get_group(card.groupId) # type: GroupDict
  9246. # 创建卡充值订单表 类型为派币
  9247. # 卡的openId 一定会存在 用户侧绑定会有 经销商录入会有 默认值
  9248. payload = {
  9249. 'orderNo': str(uuid.uuid1()),
  9250. 'openId': card.openId,
  9251. 'money': RMB(0),
  9252. 'coins': VirtualCoin(coins),
  9253. 'description': remark,
  9254. 'groupId': card.groupId,
  9255. 'groupName': group.groupName,
  9256. 'ownerId': group.ownerId,
  9257. 'operator': request.user.nickname,
  9258. 'result': 'success',
  9259. 'via': 'sendcoin',
  9260. 'attachParas': {
  9261. 'cardId': card.id,
  9262. 'cardNo': card.cardNo,
  9263. }
  9264. }
  9265. record = RechargeRecord(**payload).save()
  9266. order = CardRechargeOrder.new_one(
  9267. openId=card.openId,
  9268. cardId=cardId,
  9269. cardNo=card.cardNo,
  9270. money=RMB(0),
  9271. coins=VirtualCoin(coins),
  9272. group=group,
  9273. rechargeId=record.id,
  9274. rechargeType=u"sendCoin"
  9275. )
  9276. # ID 卡直接充值掉
  9277. if card.cardType == "ID":
  9278. balance = card.balance + order.coins
  9279. preBalance = card.balance
  9280. order.update_after_recharge_id_card(None, balance, preBalance)
  9281. CardRechargeRecord.add_record(
  9282. card=card,
  9283. group=Group.get_group(order.groupId),
  9284. order=order,
  9285. )
  9286. # 刷新卡里面的余额
  9287. card.balance = balance
  9288. card.lastMaxBalance = balance
  9289. card.showBalance = balance # 微付乐一体板要用
  9290. card.save()
  9291. # 创建上分表
  9292. newRcd = UpCardScoreRecord(
  9293. cardNo=card.cardNo,
  9294. cardId=cardId,
  9295. ownerId=str(request.user.bossId),
  9296. score=coins,
  9297. address=group.groupName,
  9298. remark=remark
  9299. )
  9300. newRcd.save()
  9301. return JsonResponse({"result": 1, "description": u"派币成功", 'payload': {}})
  9302. @error_tolerate(nil=DefaultJsonErrorResponse)
  9303. @permission_required(ROLE.dealer, ROLE.subaccount)
  9304. def querySendCoinsRcd(request):
  9305. cardId = request.GET.get('cardId', None)
  9306. if cardId:
  9307. objs = UpCardScoreRecord.objects.filter(cardId=cardId).order_by('-dateTimeAdded')
  9308. else:
  9309. objs = UpCardScoreRecord.objects.filter(ownerId=str(request.user.bossId)).order_by('-dateTimeAdded')
  9310. pageIndex = int(request.GET.get('pageIndex', 1))
  9311. pageSize = int(request.GET.get('pageSize', 10))
  9312. total = objs.count()
  9313. dataList = []
  9314. for obj in objs.paginate(pageIndex=pageIndex, pageSize=pageSize):
  9315. dataList.append({
  9316. 'dateTimeAdded':obj.dateTimeAdded.strftime(Const.DATETIME_FMT),
  9317. 'score':obj.score,
  9318. 'cardNo':obj.cardNo,
  9319. 'cardId':obj.cardId,
  9320. 'remark':obj.remark,
  9321. })
  9322. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  9323. def setSelfRechargeCardPrice(request):
  9324. payload = json.loads(request.body)
  9325. rechargeCardPrice = payload['rechargeCardPrice']
  9326. dev = Device.get_dev_by_logicalCode(payload['logicalCode'])
  9327. group = Group.get_group(dev['groupId'])
  9328. smartbox = ActionDeviceBuilder.create_action_device(dev)
  9329. smartbox.remote_charge_card(int(rechargeCardPrice))
  9330. # 蓝光卡记录, 卡不用添加在后台, 所以没有卡id
  9331. CardRechargeRecord.add_self_card_record('languang_card_id', group, RMB(rechargeCardPrice), dev)
  9332. return JsonOkResponse()
  9333. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取自动提现信息失败"))
  9334. @permission_required(ROLE.dealer)
  9335. def getAutoWithdrawConfig(request):
  9336. dealer = request.user # type: Dealer
  9337. payload = {
  9338. "phone": dealer.username,
  9339. "autoWithdrawSwitch": dealer.auto_withdraw_switch,
  9340. "autoWithdrawBankFee": dealer.auto_withdraw_bank_fee,
  9341. "withdrawFeeRatio": dealer.withdrawFeeRatio,
  9342. "autoWithdrawType": dealer.auto_withdraw_type,
  9343. "weekDay": dealer.auto_withdraw_strategy.get('value'),
  9344. "autoWithdrawMin": dealer.auto_withdraw_min
  9345. }
  9346. if dealer.monitorPhone:
  9347. payload['phone'] = dealer.monitorPhone
  9348. cards = []
  9349. for bankCard in WithdrawBankCard.objects(ownerId = str(dealer.id), role = dealer.role):
  9350. cards.append({
  9351. 'accountCode': bankCard.accountCode,
  9352. 'accountName': bankCard.accountName,
  9353. 'bankName': bankCard.bankName
  9354. })
  9355. payload.update({
  9356. 'cards': cards
  9357. })
  9358. return JsonOkResponse(payload = payload)
  9359. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"保存自动提现信息失败"))
  9360. @permission_required(ROLE.dealer)
  9361. def saveAutoWithdrawConfig(request):
  9362. dealer = request.user
  9363. payload = json.loads(request.body)
  9364. autoWithdrawSwitch = payload.get("autoWithdrawSwitch")
  9365. autoWithdrawMin = RMB(payload.get("autoWithdrawMin"))
  9366. if autoWithdrawMin < RMB(settings.WITHDRAW_MINIMUM):
  9367. return JsonErrorResponse(description=u"最小提现金额不能少于提现接口设置最小转账金额({}元)".format(settings.WITHDRAW_MINIMUM))
  9368. autoWithdrawType = payload.get("autoWithdrawType")
  9369. weekDay = int(payload.get("weekDay"))
  9370. smsCode = payload.get("code", "")
  9371. status, msg = dealerWithdrawSMSProvider.verify(dealer.username, smsCode)
  9372. if not status:
  9373. return JsonErrorResponse(msg)
  9374. # 如果自动提现到微信 需要检测提现微信是否绑定
  9375. if autoWithdrawType == WITHDRAW_PAY_TYPE.WECHAT:
  9376. auth_bridge = get_wechat_auth_bridge(source=dealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9377. key = auth_bridge.bound_openid_key
  9378. if not dealer.isAutoWithdrawOpenIdBound(key):
  9379. return JsonResponse({"result": ErrorCode.AUTO_WITHDRAW_WECHAT_NOT_BIND, "description": ""})
  9380. # 银行卡的信息不保存 每次提现的时候直接去取 防止银行卡解绑造成信息不同步
  9381. dealer.withdrawOptions.update({
  9382. 'autoWithdrawSwitch': autoWithdrawSwitch,
  9383. 'autoWithdrawType': autoWithdrawType,
  9384. 'autoWithdrawStrategy': {'type': 'asWeek', 'value': weekDay},
  9385. 'autoWithdrawMin': autoWithdrawMin.mongo_amount,
  9386. })
  9387. if 'bankAccount' in payload:
  9388. dealer.withdrawOptions.update({
  9389. 'bankAccount': payload['bankAccount']
  9390. })
  9391. dealer.save()
  9392. return JsonOkResponse(description=u'自动提现配置成功')
  9393. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取绑定信息失败"))
  9394. @permission_required(ROLE.dealer)
  9395. def getBoundWalletWeiXinId(request):
  9396. """
  9397. 获取经销商绑定后台 提现的 ID
  9398. :param request:
  9399. :return:
  9400. """
  9401. dealer = request.user
  9402. auth_bridge = get_wechat_auth_bridge(source=dealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9403. key = auth_bridge.bound_openid_key
  9404. payOpenIdInfo = dealer.get_bound_pay_info(key)
  9405. return JsonResponse(
  9406. {
  9407. "result": 1,
  9408. "description": "",
  9409. 'payload': {
  9410. "bound": True if payOpenIdInfo.get("openId") else False,
  9411. "avatar": payOpenIdInfo.get("avatar"),
  9412. "sex": payOpenIdInfo.get("sex"),
  9413. "nickname": payOpenIdInfo.get("nickname")
  9414. }
  9415. })
  9416. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取验证码失败"))
  9417. @permission_required(ROLE.dealer)
  9418. def getBindWalletWechatSMSCode(request):
  9419. try:
  9420. phoneNumber = request.user.username
  9421. agent = Agent.get_agent(request.user.agentId)
  9422. productName = agent['productName']
  9423. if not phoneNumber:
  9424. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  9425. status, msg = dealerBindWalletWechatSMSProvider.get(phoneNumber=phoneNumber,
  9426. productName=productName,
  9427. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  9428. if not status:
  9429. return JsonResponse({'result': 0, 'description': msg})
  9430. else:
  9431. return JsonResponse({'result': 1, 'description': ''})
  9432. except Exception, e:
  9433. logger.exception('unable to get %s' % e)
  9434. return JsonResponse({'result': 0, 'description': ''})
  9435. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"自动绑定失败"))
  9436. @permission_required(ROLE.dealer)
  9437. def verifyNewWalletWechatBinding(request):
  9438. currentDealer = request.user # type: cast(Dealer)
  9439. code = request.POST.get('code')
  9440. if not code:
  9441. return JsonErrorResponse(description=u'请输入6位验证码')
  9442. status, msg = dealerBindWalletWechatSMSProvider.verify(phoneNumber=request.user.username, smsCode=code)
  9443. if not status:
  9444. return JsonErrorResponse(description=msg)
  9445. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9446. return JsonResponse(
  9447. {
  9448. 'result': 1,
  9449. 'description': None,
  9450. 'payload': {
  9451. 'redirect_uri': auth_bridge.generate_auth_url_user_scope(
  9452. redirect_uri=DEALER_BIND_WALLET_WECHAT_URL)
  9453. }
  9454. })
  9455. @permission_required(ROLE.dealer)
  9456. def verifyNewWalletWechatBindingCallback(request):
  9457. auth_code = request.GET.get('code')
  9458. if not auth_code:
  9459. return JsonErrorResponse(description=u'未收到code,请刷新重试')
  9460. currentDealer = request.user
  9461. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9462. user_info = auth_bridge.get_user_info(auth_code=auth_code)
  9463. user_info_payload = {
  9464. 'avatar': user_info['avatar'],
  9465. 'sex': user_info['sex'],
  9466. 'nickname': user_info['nickname'],
  9467. 'openId': user_info['openId']
  9468. }
  9469. logger.debug('dealer(id=%s) is binding wechat for messaging, bridge=%s' % (str(request.user.bossId), auth_bridge))
  9470. key = auth_bridge.bound_openid_key
  9471. currentDealer.set_bound_pay_info(key, **user_info_payload)
  9472. currentDealer.save()
  9473. return DealerBindIdResponseRedirect(result='ok')
  9474. @permission_required(ROLE.dealer)
  9475. def selfRechargeCardRecords(request):
  9476. # type: (WSGIRequest)->JsonResponse
  9477. """
  9478. 蓝光国际手动充卡记录查询
  9479. :param request:
  9480. :return:
  9481. """
  9482. ownerId = str(request.user.bossId)
  9483. logicalCode = request.GET['logicalCode']
  9484. pageIndex = int(request.GET.get('pageIndex', 1))
  9485. pageSize = int(request.GET.get('pageSize', 10))
  9486. objs = CardRechargeRecord.objects.filter(ownerId=ownerId, logicalCode=logicalCode, cardId='languang_card_id').order_by('-dateTimeAdded')
  9487. rcdList = []
  9488. total = 0
  9489. for obj in objs:
  9490. total += 1
  9491. rcdList.append({
  9492. 'price': int(float(str(obj.money))),
  9493. 'dateTimeAdded': obj.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  9494. })
  9495. return JsonResponse({
  9496. 'result': 1,
  9497. 'description': None,
  9498. 'payload': {
  9499. 'total': total,
  9500. 'dataList': rcdList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  9501. }
  9502. })
  9503. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"同步设备电池信息失败"))
  9504. @permission_required(ROLE.dealer, ROLE.subaccount)
  9505. def asyncBatterySnByDevice(request):
  9506. """
  9507. 从设备侧同步电池编号
  9508. :param request:
  9509. :return:
  9510. """
  9511. payload = json.loads(request.body)
  9512. logicalCode = payload.get("logicalCode")
  9513. dealerId = str(request.user.bossId)
  9514. dev = Device.get_dev_by_logicalCode(logicalCode=logicalCode)
  9515. if not dev:
  9516. return JsonErrorResponse(description=u"未找到设备,请您确认设备逻辑码正确")
  9517. if dev.ownerId != dealerId:
  9518. return JsonErrorResponse(description=u"未找到设备,请您确认设备逻辑码正确")
  9519. box = ActionDeviceBuilder.create_action_device(dev)
  9520. if not hasattr(box, "_query_all_battery_imei"):
  9521. return JsonErrorResponse(description=u"该设备不支持导入电池编号,请确认设备逻辑码正确")
  9522. try:
  9523. batteryInfo = box._query_all_battery_imei()
  9524. except ServiceException:
  9525. return JsonErrorResponse(description=u"读取电池信息失败,请重新试试")
  9526. addBatteryLis = list()
  9527. for port, batterySn in batteryInfo.items():
  9528. try:
  9529. battery = Battery.add_from_device(
  9530. batterySn=batterySn,
  9531. devNo=dev.devNo,
  9532. port=port,
  9533. dealerId=dealerId
  9534. )
  9535. except Exception as e:
  9536. logger.exception(e)
  9537. continue
  9538. if not battery:
  9539. continue
  9540. addBatteryLis.append(batterySn)
  9541. message = u"操作成功,此次录入的电池编号为: \n{}".format("\n".join(addBatteryLis))
  9542. return JsonOkResponse(description=message)
  9543. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"录入电池信息失败"))
  9544. @permission_required(ROLE.dealer, ROLE.subaccount)
  9545. def asyncBatterySnByEnter(request):
  9546. """
  9547. 经销商手动录入电池编号
  9548. :param request:
  9549. :return:
  9550. """
  9551. payload = json.loads(request.body)
  9552. batterySn = payload.get("batterySn")
  9553. dealerId = str(request.user.bossId)
  9554. if not Battery.is_battery_sn_format(batterySn):
  9555. return JsonErrorResponse(u"请输入正确的电池编号(15位数字)")
  9556. battery = Battery.add_from_enter(batterySn=batterySn, dealerId=dealerId)
  9557. if not battery:
  9558. return JsonErrorResponse(description=u"请勿重复录入电池编号")
  9559. return JsonOkResponse(description=u"录入成功\n{}".format(batterySn))
  9560. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取电池列表信息失败"))
  9561. @permission_required(ROLE.dealer, ROLE.subaccount)
  9562. def batteryList(request):
  9563. """
  9564. 获取电池列表
  9565. :param request:
  9566. :return:
  9567. """
  9568. dealerId = str(request.user.bossId)
  9569. pageSize = int(request.GET.get("pageSize", 10))
  9570. pageIndex = int(request.GET.get("pageIndex", 1))
  9571. searchKey = request.GET.get("searchKey", "")
  9572. logicalCode = request.GET.get("logicalCode")
  9573. data = list()
  9574. filters = {
  9575. "dealerId": dealerId
  9576. }
  9577. if logicalCode:
  9578. dev = Device.get_dev_by_l(logicalCode)
  9579. if not dev or dev.ownerId != dealerId:
  9580. return JsonOkResponse(payload={"total": 0, "data": data})
  9581. filters.update({"devNo": dev.devNo})
  9582. query = Battery.objects.filter(**filters).search(searchKey)
  9583. total = query.count()
  9584. batteries = query.skip((pageIndex - 1) * pageSize).limit(pageSize)
  9585. for battery in batteries:
  9586. data.append(battery.to_dict())
  9587. return JsonOkResponse(
  9588. payload={
  9589. "total": total,
  9590. "dataList": data
  9591. }
  9592. )
  9593. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"删除电池失败"))
  9594. @permission_required(ROLE.dealer, ROLE.subaccount)
  9595. def deleteBattery(request):
  9596. """
  9597. 删除电池
  9598. :param request:
  9599. :return:
  9600. """
  9601. dealerId = str(request.user.bossId)
  9602. payload = json.loads(request.body)
  9603. batterySn = payload.get("ids")
  9604. if len(batterySn) > 1:
  9605. return JsonErrorResponse(description=u"电池数量超限")
  9606. result = Battery.delete_one(dealerId, batterySn[0])
  9607. if not result:
  9608. return JsonErrorResponse(description=u"删除电池信息失败")
  9609. return JsonErrorResponse(description=u"电池编号<{}>删除成功".format(batterySn[0]))
  9610. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取电池定位失败"))
  9611. @permission_required(ROLE.dealer, ROLE.subaccount)
  9612. def batteryPosition(request):
  9613. """
  9614. 经销商处查看电池的定位
  9615. :param request:
  9616. :return:
  9617. """
  9618. dealerId = str(request.user.bossId)
  9619. batterySn = request.GET.get("batterySn", "")
  9620. battery = Battery.get_one(dealerId=dealerId, batterySn=batterySn)
  9621. if not battery:
  9622. return JsonErrorResponse(description=u"未找到电池,请重新试试")
  9623. # result = BatteryInfo().getBatteryInfo(batterySn).get(batterySn)
  9624. result = BatteryInfo().getBatteryInfo(batterySn).get(batterySn)
  9625. if not result:
  9626. return JsonErrorResponse(description=u"电池定位第三方数据请求失败")
  9627. # TODO zjl 需要对经纬度进行转换
  9628. # TODO 前台做成了分页的形式 暂时就这样吧 后续再修改
  9629. data = {
  9630. "lat": result.get("lat"),
  9631. "lng": result.get("lng"),
  9632. "voltage": result.get("voltage")
  9633. }
  9634. payload = {
  9635. "total": 1,
  9636. "items": [data]
  9637. }
  9638. return JsonOkResponse(payload=payload)
  9639. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置电池失败"))
  9640. @permission_required(ROLE.dealer, ROLE.subaccount)
  9641. def disableBattery(request):
  9642. """
  9643. 经销商标记电池 被标记的电池当再次被放入的时候
  9644. :param request:
  9645. :return:
  9646. """
  9647. dealerId = str(request.user.bossId)
  9648. payload = json.loads(request.body)
  9649. disable = payload.get("disable")
  9650. batterySn = payload.get("batterySn")
  9651. print batterySn, type(batterySn)
  9652. print disable, type(disable)
  9653. for sn in batterySn:
  9654. battery = Battery.get_one(dealerId, sn)
  9655. if not battery:
  9656. return JsonErrorResponse(description=u"未查找到电池数据,请刷新页面重试")
  9657. battery.disable = disable
  9658. return JsonOkResponse()
  9659. @permission_required(ROLE.dealer)
  9660. def createEmptyCardTicket(request):
  9661. json_str = request.body
  9662. json_data = json.loads(json_str)
  9663. number = json_data.get('number')
  9664. card_id = json_data.get('cardId')
  9665. if not str(number).isdigit():
  9666. return JsonErrorResponse(description=u'请输入数字!')
  9667. if int(number) > 50:
  9668. return JsonErrorResponse(description=u'单次发卡数量不能超过50张')
  9669. try:
  9670. card_model = VirtualCard.objects.get(id=card_id)
  9671. except Exception:
  9672. return JsonErrorResponse(description=u'读取虚拟卡失败,请重试')
  9673. attachParas = {}
  9674. attachParas['number'] = int(number)
  9675. attachParas['card_id'] = card_id
  9676. virtual_cards = VirtualCardBuilder.create_virtual_card(request.user, card_model, attachParas)
  9677. return JsonResponse({'result': 0, 'description': '当前生成卡号:%s' % (','.join(virtual_cards))})
  9678. @permission_required(ROLE.dealer, ROLE.subaccount)
  9679. def bindVirtualCardToRechargeIDCard(request):
  9680. payload = json.loads(request.body)
  9681. virtualCardId = payload.get('virtualCardId')
  9682. rechargeIDCardId = payload.get('rechargeIDCardId')
  9683. if virtualCardId is None:
  9684. return JsonErrorResponse(description=u'未找到虚拟卡ID')
  9685. if rechargeIDCardId is None:
  9686. return JsonErrorResponse(description=u'未找到ID实体卡')
  9687. card = Card.objects(id=rechargeIDCardId).first()
  9688. if card is None:
  9689. return JsonErrorResponse(description=u'未找到ID实体卡')
  9690. if card.boundVirtualCardId:
  9691. return JsonErrorResponse(description=u'该卡片已绑定一张虚拟卡')
  9692. if card.cardType != RECHARGE_CARD_TYPE.ID:
  9693. return JsonErrorResponse(description=u'该卡不是ID卡')
  9694. virtualCard = UserVirtualCard.objects(id=virtualCardId).first()
  9695. if virtualCard is None:
  9696. return JsonErrorResponse(description=u'未找到虚拟卡')
  9697. updated = card.bind_virtual_card(virtualCard)
  9698. res = VirtualCardBuilder.active_virtual_card(virtualCardId)
  9699. if updated and res:
  9700. return JsonOkResponse()
  9701. else:
  9702. return JsonErrorResponse(description=u'绑定失败')
  9703. @permission_required(ROLE.dealer)
  9704. def unbindVirtualCardToRechargeIDCard(request):
  9705. json_str = request.body
  9706. json_data = json.loads(json_str)
  9707. card_id = str(json_data.get('cardId'))
  9708. try:
  9709. card = Card.objects.get(id=card_id)
  9710. except Exception:
  9711. return JsonErrorResponse(description=u'数据走丢了,请稍后再试')
  9712. if not card.bound_virtual_card:
  9713. return JsonErrorResponse(description=u'该卡片未绑定优惠卡券')
  9714. res = VirtualCardBuilder.unbind_virtual_card(card)
  9715. if res:
  9716. return JsonOkResponse()
  9717. else:
  9718. return JsonErrorResponse(description=u'解绑失败,请稍后再试')
  9719. @error_tolerate(nil=DefaultJsonErrorResponse)
  9720. @permission_required(ROLE.dealer)
  9721. def getDeviceStockForGoods(request):
  9722. logicalCode = request.GET.get('logicalCode', '')
  9723. pageSize = int(request.GET.get("pageSize", 10))
  9724. pageIndex = int(request.GET.get("pageIndex", 1))
  9725. if not logicalCode:
  9726. return JsonErrorResponse(description=u'参数接口错误')
  9727. devObj = Device.objects.get(logicalCode=logicalCode)
  9728. dataList = []
  9729. for itemTypeId, count in devObj.stockDetailDict.items():
  9730. try:
  9731. itemType = ItemType.objects.get(id=itemTypeId)
  9732. except Exception, e:
  9733. continue
  9734. dataList.append({
  9735. 'quantity':count,
  9736. 'itemId':itemTypeId,
  9737. 'itemName':itemType.title,
  9738. 'itemPrice':itemType.price,
  9739. 'itemPicUrl':itemType.picUrl
  9740. })
  9741. return JsonOkResponse(payload={'total':len(dataList), 'dataList':dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]})
  9742. def addGoodsForStock(request):
  9743. payload = json.loads(request.body)
  9744. logicalCode = payload.get('logicalCode')
  9745. quantity = payload.get('quantity')
  9746. itemId = payload.get('itemId')
  9747. dev = Device.get_dev_by_l(logicalCode)
  9748. devObj = Device.objects.get(logicalCode=logicalCode)
  9749. oldQuantity = devObj.stockDetailDict.get(itemId, 0)
  9750. devObj.stockDetailDict[itemId] = quantity
  9751. try:
  9752. devObj.save()
  9753. except Exception, e:
  9754. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9755. if quantity > oldQuantity:
  9756. stockType = 'add'
  9757. stockNum = quantity - oldQuantity
  9758. elif quantity < oldQuantity:
  9759. stockType = 'remove'
  9760. stockNum = oldQuantity - quantity
  9761. else:
  9762. stockType = ''
  9763. itemObj = ItemType.objects.get(id=itemId)
  9764. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  9765. StockRecord.get_collection().insert(
  9766. {'logicCode': logicalCode, 'imei': dev['devNo'], 'stockType': stockType, 'stockTime': stockTime, 'number': stockNum, 'more':itemObj.title})
  9767. # 刷新总的数目
  9768. allCount = 0
  9769. for count in devObj.stockDetailDict.values():
  9770. allCount += count
  9771. result = Device.update_field(dev_no=devObj.devNo, update=True, quantity=allCount)
  9772. if not result:
  9773. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9774. return JsonOkResponse()
  9775. @error_tolerate(nil=DefaultJsonErrorResponse)
  9776. @permission_required(ROLE.dealer)
  9777. def deleteItemStock(request):
  9778. payload = json.loads(request.body)
  9779. logicalCode = payload.get('logicalCode')
  9780. itemIds = payload.get('itemIds')
  9781. dev = Device.get_dev_by_l(logicalCode)
  9782. devObj = Device.objects.get(logicalCode=logicalCode)
  9783. for itemId in itemIds:
  9784. itemObj = ItemType.objects.get(id=itemId)
  9785. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  9786. StockRecord.get_collection().insert(
  9787. {'logicCode': logicalCode, 'imei': dev['devNo'], 'stockType': 'remove', 'stockTime': stockTime, 'number': devObj.stockDetailDict.get(itemId, 0), 'more':itemObj.title})
  9788. try:
  9789. devObj.stockDetailDict.pop(itemId)
  9790. except Exception, e:
  9791. continue
  9792. try:
  9793. devObj.save()
  9794. except Exception, e:
  9795. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9796. allCount = 0
  9797. for count in devObj.stockDetailDict.values():
  9798. allCount += count
  9799. result = Device.update_field(dev_no=devObj.devNo, update=True, quantity=allCount)
  9800. if not result:
  9801. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9802. return JsonOkResponse()
  9803. @error_tolerate(nil=DefaultJsonErrorResponse)
  9804. @permission_required(ROLE.dealer)
  9805. def updateStockQuantityForGoods(request):
  9806. payload = json.loads(request.body)
  9807. logicalCode = payload.get('logicalCode')
  9808. quantity = payload.get('quantity')
  9809. itemIds = payload.get('itemIds')
  9810. dev = Device.get_dev_by_l(logicalCode)
  9811. oldQuantity = dev['quantity']
  9812. devObj = Device.objects.get(logicalCode=logicalCode)
  9813. for itemId in itemIds:
  9814. devObj.stockDetailDict[itemId] = quantity
  9815. if quantity > oldQuantity:
  9816. stockType = 'add'
  9817. stockNum = quantity - oldQuantity
  9818. elif quantity < oldQuantity:
  9819. stockType = 'remove'
  9820. stockNum = oldQuantity - quantity
  9821. else:
  9822. stockType = ''
  9823. try:
  9824. itemObj = ItemType.objects.get(id=itemId)
  9825. except Exception, e:
  9826. continue
  9827. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  9828. StockRecord.get_collection().insert(
  9829. {'logicCode': logicalCode, 'imei': dev['devNo'], 'stockType': stockType, 'stockTime': stockTime, 'number': stockNum, 'more':itemObj.title})
  9830. try:
  9831. devObj.save()
  9832. except Exception, e:
  9833. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9834. allCount = 0
  9835. for count in devObj.stockDetailDict.values():
  9836. allCount += count
  9837. result = Device.update_field(dev_no=devObj.devNo, update=True, quantity=allCount)
  9838. if not result:
  9839. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9840. return JsonOkResponse()
  9841. @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"没有余额卡"))
  9842. @permission_required(ROLE.dealer)
  9843. def getCardListForDevice(request):
  9844. """
  9845. 给中山绿智做的经销商充值
  9846. """
  9847. logicalCode = request.GET.get("logicalCode")
  9848. dealer = Dealer.objects(id=str(request.user.id)).first()
  9849. if dealer is None:
  9850. return JsonErrorResponse(description=u"设备的经销商不存在")
  9851. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  9852. dev = Device.get_dev(devNo)
  9853. if dev is None:
  9854. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  9855. if dev['ownerId'] != str(request.user.bossId):
  9856. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  9857. box = ActionDeviceBuilder.create_action_device(dev)
  9858. try:
  9859. res = box.get_no_balance_list(devNo)
  9860. except ServiceException, e:
  9861. logger.info('error happened, error=%s' % (e,))
  9862. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  9863. except Exception, e:
  9864. logger.exception('error happened, error=%s' % (e,))
  9865. return JsonResponse({'result': 0, 'description': u'系统异常,请检查输入参数,或者稍后重试', 'payload': {}})
  9866. return JsonResponse({'result': 1, 'description': None, 'payload': {"total":1, "dataList":res}})
  9867. @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"没有余额卡"))
  9868. @permission_required(ROLE.dealer)
  9869. def chargeInsufficientBalanceCard(request):
  9870. """
  9871. 给中山绿智做的经销商充值
  9872. """
  9873. payload = json.loads(request.body)
  9874. logicalCode = payload.get("logicalCode")
  9875. amount = payload.get("amount")
  9876. cardIds = payload.get("cardIds")
  9877. if not logicalCode or not amount or not cardIds:
  9878. return JsonErrorResponse(description=u"请完整的传入参数")
  9879. dealer = Dealer.objects(id=str(request.user.id)).first()
  9880. if dealer is None:
  9881. return JsonErrorResponse(description=u"设备的经销商不存在")
  9882. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  9883. dev = Device.get_dev(devNo)
  9884. if dev is None:
  9885. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  9886. if dev['ownerId'] != str(request.user.bossId):
  9887. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  9888. box = ActionDeviceBuilder.create_action_device(dev)
  9889. try:
  9890. res = box.remote_charge_ic_card_by_dealer(cardIds, amount)
  9891. except ServiceException, e:
  9892. logger.info('error happened, error=%s' % (e,))
  9893. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  9894. except Exception, e:
  9895. logger.exception('error happened, error=%s' % (e,))
  9896. return JsonResponse({'result': 0, 'description': u'系统异常,请检查输入参数,或者稍后重试', 'payload': {}})
  9897. return JsonResponse({'result': 1, 'description': None})
  9898. @permission_required(ROLE.dealer)
  9899. def getDeviceLocker(request):
  9900. """
  9901. 储物柜的大小格子配置
  9902. """
  9903. logicalCode = request.GET.get("logicalCode[]")
  9904. if isinstance(logicalCode, (str, unicode)):
  9905. dev = Device.objects.filter(logicalCode=logicalCode).first()
  9906. sizeInfo = dev.otherConf.get("sizeInfo", [])
  9907. if not sizeInfo:
  9908. for i in xrange(1, 25):
  9909. item = {"port":str(i), "size":"small"}
  9910. sizeInfo.append(item)
  9911. dev.otherConf["sizeInfo"] = sizeInfo
  9912. dev.save()
  9913. dev.invalid_device_cache(dev.devNo)
  9914. return JsonResponse({
  9915. "result": 1,
  9916. "description": "",
  9917. "payload": {
  9918. "dataList": sizeInfo
  9919. }
  9920. })
  9921. else: # 批量获取
  9922. pass
  9923. @permission_required(ROLE.dealer)
  9924. def saveDeviceLocker(request):
  9925. """
  9926. 储物柜的大小格子配置
  9927. """
  9928. payload = json.loads(request.body)
  9929. logicalCodes = payload.get("logicalCode")
  9930. portList = payload.get("portList")
  9931. for item in portList:
  9932. item["port"] = str(item["port"])
  9933. if not logicalCodes:
  9934. return JsonResponse({"result": 2,
  9935. "description": "设备号错误,请重试......", })
  9936. if not portList:
  9937. return JsonResponse({"result": 2,
  9938. "description": "当前没有设置任何设备参数", })
  9939. for item in logicalCodes:
  9940. dev = Device.objects.filter(logicalCode=item).first()
  9941. dev.otherConf["sizeInfo"] = portList
  9942. dev.otherConf["actualPortNum"] = len(portList)
  9943. dev.save()
  9944. Device.invalid_device_cache(dev.devNo)
  9945. return JsonResponse({"result": 1,
  9946. "description": "", })
  9947. # 经销商获取提现短信验证码
  9948. @error_tolerate(nil=DefaultJsonErrorResponse)
  9949. @permission_required(ROLE.dealer)
  9950. def getEditMonitorCode(request):
  9951. # type: (WSGIRequest)->JsonResponse
  9952. currentDealer = request.user # type: Dealer
  9953. if currentDealer.abnormal:
  9954. return JsonErrorResponse(description=u'该帐号资金异常,请合法经营。具体请联系客服')
  9955. toNumber = request.GET.get('phone')
  9956. if not toNumber:
  9957. toNumber = request.user.monitorPhone
  9958. if not toNumber:
  9959. return JsonErrorResponse(description=u'没有找到提现审批人的手机号')
  9960. agentId = request.user.agentId
  9961. agent = Agent.get_agent(agentId)
  9962. productName = agent['productName']
  9963. status, msg = dealerEditMonitorSMSProvider.get(phoneNumber=toNumber,
  9964. productName=productName,
  9965. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  9966. if not status:
  9967. return JsonErrorResponse(description=msg)
  9968. else:
  9969. return JsonOkResponse()
  9970. @error_tolerate(nil=DefaultJsonErrorResponse)
  9971. @permission_required(ROLE.dealer)
  9972. def getDealerMonitor(request):
  9973. return JsonOkResponse(payload={'phone':request.user.monitorPhone if request.user.monitorPhone else None})
  9974. @error_tolerate(nil=DefaultJsonErrorResponse)
  9975. @permission_required(ROLE.dealer)
  9976. def editMonitor(request):
  9977. dealer = request.user
  9978. if request.GET.get('oper') == 'delete':
  9979. code = request.GET.get('code')
  9980. phone = dealer.monitorPhone
  9981. if not phone:
  9982. return JsonErrorResponse(description=u'没有找到提现审批人的手机号,无法清除')
  9983. status, msg = dealerEditMonitorSMSProvider.verify(phone, code)
  9984. if not status:
  9985. return JsonErrorResponse(msg)
  9986. dealer.monitorPhone = ''
  9987. dealer.save()
  9988. return JsonOkResponse()
  9989. if not request.GET.get('phone'):
  9990. return JsonErrorResponse(description=u'没有找到提现审批人的手机号')
  9991. phone = request.GET.get('phone')
  9992. code = request.GET.get('code')
  9993. status, msg = dealerEditMonitorSMSProvider.verify(phone, code)
  9994. if not status:
  9995. return JsonErrorResponse(msg)
  9996. dealer.monitorPhone = phone
  9997. dealer.save()
  9998. return JsonOkResponse()
  9999. @error_tolerate(nil=DefaultJsonErrorResponse)
  10000. @permission_required(ROLE.dealer)
  10001. def bindParentNode(request):
  10002. payload = json.loads(request.body)
  10003. parentNode = payload.get("parentLogicalCode")
  10004. node = payload.get("childLogicalCode")
  10005. category = payload.get("category")
  10006. try:
  10007. if category == "CM":
  10008. # 诚马的插座 采用主绑定从的方式 进行绑定
  10009. master, sub = Device.get_dev_by_l(parentNode), Device.get_dev_by_l(node)
  10010. if not all([master, sub]):
  10011. return JsonErrorResponse(description=u"绑定设备错误(10001)")
  10012. master.deviceAdapter.add_node(sub)
  10013. elif category == "BL":
  10014. # 这里有3种情况,1、插座和网关一体板,自己绑自己;2、其他插座绑定纯网关的逻辑编码;3、其他插座绑一体板的二维码
  10015. gatewayDev = Device.get_dev_by_l(parentNode) # type: DeviceDict
  10016. if gatewayDev is None:
  10017. Device.get_collection().update({'logicalCode':node}, {'$set':{'gateImei':parentNode}})
  10018. gatewayPlugDev = Device.get_dev_by_l(node)
  10019. box = gatewayPlugDev.deviceAdapter
  10020. box.add_node(gatewayPlugDev['devNo'])
  10021. else:
  10022. box = gatewayDev.deviceAdapter # type: ChargingGatewayBox
  10023. box.add_node(Device.get_dev_by_l(node)['devNo'])
  10024. else:
  10025. return JsonErrorResponse(description=u"错误的节点绑定类型")
  10026. except ServiceException as se:
  10027. return JsonErrorResponse(description=se.result["description"])
  10028. return JsonOkResponse()
  10029. @error_tolerate(nil=DefaultJsonErrorResponse)
  10030. @permission_required(ROLE.dealer)
  10031. def unbindParentNode(request):
  10032. payload = json.loads(request.body)
  10033. node = payload.get("logicalCode")
  10034. nodeDev = Device.get_dev_by_l(node) # type: DeviceDict
  10035. box = nodeDev.deviceAdapter # type: ChargingBox
  10036. box.remove_from_gateway()
  10037. return JsonOkResponse()
  10038. @error_tolerate(nil=DefaultJsonErrorResponse)
  10039. @permission_required(ROLE.dealer)
  10040. def getGateway(request):
  10041. payload = json.loads(request.body)
  10042. lc = payload.get("logicalCode")
  10043. devObj = Device.objects.get(logicalCode=lc)
  10044. if devObj.gatewayNode == '':
  10045. return JsonResponse({"result": 1, "description": "", "payload": {}})
  10046. gatewayDev = Device.get_dev(devObj.gatewayNode) # type: DeviceDict
  10047. box = gatewayDev.deviceAdapter # type: ChargingGatewayBox
  10048. devInfo = box.get_signal()
  10049. data = {
  10050. 'logicalCode':gatewayDev['logicalCode'],
  10051. 'gatewaySignal':devInfo['signal'],
  10052. 'groupName':gatewayDev['groupName']
  10053. }
  10054. return JsonResponse({"result": 1, "description": "", "payload": data})
  10055. @error_tolerate(nil=DefaultJsonErrorResponse)
  10056. @permission_required(ROLE.dealer)
  10057. def getNodeList(request):
  10058. """
  10059. 获取主机的节点列表
  10060. """
  10061. lc = request.GET.get("logicalCode")
  10062. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  10063. box = dev.deviceAdapter # type: ChargingGatewayBox
  10064. nodeList = box.get_node_list()
  10065. dataList = []
  10066. devDict = {}
  10067. for node in nodeList:
  10068. nodeDev = Device.get_dev(node['devNo']) # type: DeviceDict
  10069. if nodeDev is None:
  10070. continue
  10071. if not nodeDev.is_registered:
  10072. _temp = {
  10073. 'id': node.devNo,
  10074. 'groupId': "",
  10075. 'logicalCode': nodeDev.logicalCode,
  10076. 'devType': nodeDev.devTypeName,
  10077. "online": nodeDev.online,
  10078. "registered": nodeDev.is_registered,
  10079. "signal": nodeDev.signal
  10080. }
  10081. else:
  10082. _temp = {
  10083. 'id': node.devNo,
  10084. 'groupId': nodeDev.group.groupId,
  10085. 'logicalCode': nodeDev.logicalCode,
  10086. 'devType': nodeDev.devTypeName,
  10087. "online": nodeDev.online,
  10088. "registered": nodeDev.is_registered,
  10089. "signal": nodeDev.signal
  10090. }
  10091. if nodeDev['groupId'] in devDict:
  10092. devDict[nodeDev['groupId']].append(node)
  10093. else:
  10094. devDict[nodeDev['groupId']] = [node]
  10095. dataList.append(node)
  10096. natural_sort(array=dataList, key='logicalCode', reverse=False)
  10097. return JsonResponse({
  10098. "result": 1,
  10099. "description": None,
  10100. 'payload': {
  10101. "total": len(dataList),
  10102. "groupCount": len(devDict.keys()),
  10103. "dataList": dataList
  10104. }
  10105. })
  10106. @error_tolerate(nil=DefaultJsonErrorResponse)
  10107. @permission_required(ROLE.dealer)
  10108. def getPortParam(request):
  10109. payload = json.loads(request.body)
  10110. lc = payload.get("logicalCode")[0]
  10111. portIndex = payload.get("port")
  10112. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  10113. box = dev.deviceAdapter # type: ChargingBox
  10114. config = box.get_port_config(portIndex)
  10115. return JsonResponse({"result": 1, "description": "", "payload": config})
  10116. @error_tolerate(nil=DefaultJsonErrorResponse)
  10117. @permission_required(ROLE.dealer)
  10118. def setPortParam(request):
  10119. payload = json.loads(request.body)
  10120. lc = payload.get("logicalCode")[0]
  10121. portIndex = payload.get("port")
  10122. maxCurrent = payload.get('max_current', 10)
  10123. maxPower = payload.get('max_power', 1000)
  10124. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  10125. box = dev.deviceAdapter # type: ChargingBox
  10126. box.set_port_config(portIndex, {'max_power':int(maxPower), 'max_current':int(maxCurrent)})
  10127. return JsonOkResponse()
  10128. @permission_required(ROLE.dealer, ROLE.subaccount)
  10129. def beAuthLogin(request):
  10130. oper_id = request.GET.get('dealerId')
  10131. # 校验经销商是否存在
  10132. dealer = Dealer.objects.filter(id=oper_id).first()
  10133. if not dealer:
  10134. return ErrorResponseRedirect(error=cn('当前经销不存在'))
  10135. # 校验当前用户是否已经是授权登入的
  10136. session = DealerSessionBuilder(request)
  10137. if session.is_dealer_trustee():
  10138. return ErrorResponseRedirect(error=cn('授权人页面不允许切换'))
  10139. role = PermissionRole.objects.filter(dealerId=str(dealer.id), operId=str(request.user.id)).first()
  10140. if role:
  10141. if role.isActive:
  10142. session.check_out_to_dealer_trustee(oper_id)
  10143. else:
  10144. if role.authorizeType == 'dealer_to_dealer':
  10145. return ErrorResponseRedirect(error=cn(u'请联系您的授权经销商给您配置权限'))
  10146. elif role.authorizeType == 'dealer_to_subAccount':
  10147. return ErrorResponseRedirect(error=cn(u'请联系您的主经销商同意此授权关系'))
  10148. else:
  10149. # 没有权限
  10150. return ErrorResponseRedirect(error=cn(u'当前授权已失效'))
  10151. return FrontEndResponseRedirect(add_query('/app/index.html', {}))
  10152. @permission_required(ROLE.dealer)
  10153. def loginMyPrimaryAccount(request):
  10154. session = DealerSessionBuilder(request)
  10155. if session.is_dealer_trustee():
  10156. result = session.check_out_to_dealer_master()
  10157. if not result:
  10158. return ErrorResponseRedirect(error=cn(u'验证失败,请重新登入'))
  10159. else:
  10160. pass
  10161. # return ErrorResponseRedirect(error=cn(u'当前已经是主账户'))
  10162. # 无需切换已经是主账户
  10163. return FrontEndResponseRedirect(add_query('/app/index.html', {}))
  10164. @permission_required(ROLE.dealer)
  10165. def addOrEditOperatorPermission(request):
  10166. session = DealerSessionBuilder(request)
  10167. if session.is_dealer_trustee():
  10168. # 操作员无权限修改改权限
  10169. return ErrorResponseRedirect(error=cn(u'您当前无权修改授权权限'))
  10170. else:
  10171. permissionId = request.POST.get('permissionId')
  10172. permissionDict = request.POST.get('permissions')
  10173. PermissionRule.objects.get(id=permissionId, dealerId=str(request.user.id)).update(permissionDict=permissionDict)
  10174. @permission_required(ROLE.dealer)
  10175. def getAccountPermissionByAuthId(request):
  10176. id = request.GET.get('id')
  10177. role = PermissionRole.objects.filter(operId=id, dealerId=str(request.user.id)).first()
  10178. if not role:
  10179. return JsonResponse({'result': 0, 'description': '您的当前授权已失效'})
  10180. rule = PermissionRule.objects.filter(id=role.permissionRuleId).first()
  10181. return JsonResponse({'result': 1, 'description': '', 'payload': rule.get_permissionDict()})
  10182. @permission_required(ROLE.dealer)
  10183. def saveAccountPermissionByAuthId(request):
  10184. payload = json.loads(request.body)
  10185. id = payload.pop('id', None)
  10186. role = PermissionRole.objects.filter(operId=id, dealerId=str(request.user.id)).first()
  10187. if role:
  10188. if role.authorizeType == 'dealer_to_dealer': # 经销商对经销商 直接激活此次授权
  10189. role.update(isActive=True)
  10190. elif role.authorizeType == 'dealer_to_subAccount': # 经销商对子账号 需要子账号的主账号同意
  10191. pass
  10192. rule = PermissionRule.objects.filter(id=role.permissionRuleId).update(permissionDict=payload)
  10193. return JsonResponse({'result': 1, 'description': '', 'payload':{}})
  10194. else:
  10195. return JsonResponse({'result': 0, 'description': '权限配置失败', 'payload': {}})
  10196. @permission_required(ROLE.dealer)
  10197. def getAuthList(request):
  10198. dealer_id = PermissionRole.get_auth_to_dealer(dealerId=str(request.user.id))
  10199. dealers = Dealer.objects(id__in=dealer_id)
  10200. total = dealers.count()
  10201. pageSize = int(request.GET.get('pageSize', 10))
  10202. pageIndex = int(request.GET.get('pageIndex', 1))
  10203. dataList = []
  10204. for dealer in dealers:
  10205. item = {
  10206. 'id': str(dealer.id),
  10207. 'nickname': dealer.nickname,
  10208. 'username': dealer.username,
  10209. 'avatarUrl': dealer.my_avatar if dealer.my_avatar else settings.DEFAULT_AVATAR_URL,
  10210. }
  10211. dataList.append(item)
  10212. subAccount_id = PermissionRole.get_auth_to_sub(dealerId=str(request.user.id))
  10213. subAccounts = SubAccount.objects(id__in=subAccount_id)
  10214. total += subAccounts.count()
  10215. for subAccount in subAccounts:
  10216. item = {
  10217. 'id': str(subAccount.id),
  10218. 'nickname': subAccount.nickname,
  10219. 'username': subAccount.username,
  10220. 'avatarUrl': subAccount.my_avatar if subAccount.my_avatar else settings.DEFAULT_AVATAR_URL,
  10221. }
  10222. dataList.append(item)
  10223. payload = {
  10224. 'total': total,
  10225. 'dealerId': str(request.user.id),
  10226. 'agentId': request.user.agentId,
  10227. 'dataList': dataList[pageIndex * pageSize - pageSize: pageIndex * pageSize ]
  10228. }
  10229. return JsonResponse({'result': 1, 'description': '', 'username':request.user.username, 'payload': payload})
  10230. @permission_required(ROLE.dealer, ROLE.subaccount)
  10231. def getBeAuthList(request):
  10232. if request.user.role == 'dealer':
  10233. dealer_id = PermissionRole.get_is_auth_list(operId=str(request.user.id), authorizeType='dealer_to_dealer')
  10234. elif request.user.role == 'subaccount':
  10235. dealer_id = PermissionRole.get_is_auth_list(operId=str(request.user.id), authorizeType='dealer_to_subAccount')
  10236. else:
  10237. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10238. dealers = Dealer.objects(id__in=dealer_id)
  10239. total = dealers.count()
  10240. payload = {
  10241. 'total': total,
  10242. 'dealerId': str(request.user.id),
  10243. 'agentId': request.user.agentId
  10244. }
  10245. pageSize = int(request.GET.get('pageSize', 10))
  10246. pageIndex = int(request.GET.get('pageIndex', 1))
  10247. dataList = []
  10248. for dealer in dealers.paginate(pageIndex=pageIndex, pageSize=pageSize):
  10249. item = {
  10250. 'dealerId': str(dealer.id),
  10251. 'nickname': dealer.nickname,
  10252. 'username': dealer.username,
  10253. 'avatarUrl': dealer.my_avatar if dealer.my_avatar else settings.DEFAULT_AVATAR_URL,
  10254. }
  10255. dataList.append(item)
  10256. payload['dataList'] = dataList
  10257. return JsonResponse({'result': 1, 'description': '', 'username': request.user.username, 'payload': payload})
  10258. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10259. @permission_required(ROLE.dealer)
  10260. def getMonthlyPackageTemp(request):
  10261. """
  10262. 获取包月套餐
  10263. :param request:
  10264. :return:
  10265. """
  10266. dealerId = str(request.user.bossId)
  10267. dealer = Dealer.objects.get(id=dealerId)
  10268. monthlyPackages = dealer.monthlyPackage
  10269. dataList = [_package.to_dict() for _package in monthlyPackages]
  10270. return JsonOkResponse(payload={"dataList": dataList})
  10271. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10272. @permission_required(ROLE.dealer)
  10273. def getMonthlyPackageTempDetail(request):
  10274. monthlyPackageId = request.GET.get("id", "")
  10275. monthlyPackage = MonthlyPackageTemp.get_package_by_id(monthlyPackageId)
  10276. if not monthlyPackage or monthlyPackage.ownerId != str(request.user.bossId):
  10277. return JsonErrorResponse(description=u"未找到相应模板套餐,请刷新重试")
  10278. return JsonOkResponse(payload=monthlyPackage.to_dict())
  10279. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10280. @permission_required(ROLE.dealer)
  10281. def saveMonthlyPackageTemp(request):
  10282. """
  10283. 保存包月套餐模板
  10284. :param request:
  10285. :return:
  10286. """
  10287. payload = json.loads(request.body)
  10288. packageId = payload.pop("id", "")
  10289. monthlyPackage = MonthlyPackageTemp.get_package_by_id(packageId)
  10290. if not monthlyPackage or monthlyPackage.ownerId != str(request.user.bossId):
  10291. return JsonErrorResponse(description=u"未找到相应模板套餐,请刷新重试")
  10292. # 修改包月的模板套餐
  10293. monthlyPackage.update_by_fields(**payload)
  10294. return JsonOkResponse()
  10295. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10296. @permission_required(ROLE.dealer)
  10297. def delMonthlyPackageTemp(request):
  10298. """
  10299. 经销商删除包月套餐模板
  10300. :param request:
  10301. :return:
  10302. """
  10303. payload = json.loads(request.body)
  10304. packageId = payload.get("id", "")
  10305. monthlyPackage = MonthlyPackageTemp.get_package_by_id(packageId)
  10306. if not monthlyPackage:
  10307. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10308. if monthlyPackage.ownerId != str(request.user.bossId):
  10309. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10310. # 默认模板无法删除
  10311. if monthlyPackage.isDefault:
  10312. return JsonErrorResponse(description=u"默认包月模板无法删除")
  10313. # 需要将关联此模板的地址组的包月信息全部清空 置为默认的
  10314. groupIds = Group.get_group_ids_of_dealer(str(request.user.bossId))
  10315. Group.objects.filter(id__in=groupIds, monthlyPackage=monthlyPackage).update(monthlyPackage=None)
  10316. # 最后将改套餐置为 idDelete
  10317. monthlyPackage.update(isDelete=1)
  10318. return JsonOkResponse()
  10319. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10320. @permission_required(ROLE.dealer)
  10321. def setDefaultMonthlyPackageTemp(request):
  10322. """
  10323. 经销商 将包月套餐设置成默认的套餐
  10324. :param request:
  10325. :return:
  10326. """
  10327. payload = json.loads(request.body)
  10328. packageId = payload.get("id", "")
  10329. monthlyPackage = MonthlyPackageTemp.get_package_by_id(packageId)
  10330. if not monthlyPackage:
  10331. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10332. if monthlyPackage.ownerId != str(request.user.bossId):
  10333. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10334. monthlyPackage.set_default()
  10335. return JsonOkResponse()
  10336. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10337. @permission_required(ROLE.dealer)
  10338. def addGroupToMonthlyPackageTemp(request):
  10339. """
  10340. 添加设备 到 包月套餐
  10341. :param request:
  10342. :return:
  10343. """
  10344. payload = json.loads(request.body)
  10345. packageId = payload.get("packageId", "")
  10346. groupIds = payload.get("groupId", "")
  10347. groups = list()
  10348. for _groupId in groupIds:
  10349. group = Group.get_dealer_group(str(request.user.bossId), id=_groupId.get("groupId", ""))
  10350. if not group:
  10351. return JsonErrorResponse(description=u"未找到相应的设备组,请刷新重试")
  10352. groups.append(group)
  10353. monthlyPackage = MonthlyPackageTemp.get_dealer_package(ownerId=str(request.user.bossId), id=packageId)
  10354. if not monthlyPackage:
  10355. return JsonErrorResponse(description=u"未找到相应套餐,请刷新重试")
  10356. for _group in groups:
  10357. _group.monthlyRule = monthlyPackage
  10358. return JsonOkResponse()
  10359. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10360. @permission_required(ROLE.dealer)
  10361. def addMonthlyPackageTemp(request):
  10362. ownerId = str(request.user.bossId)
  10363. payload = json.loads(request.body)
  10364. monthlyPackage = MonthlyPackageTemp.create_by_fields(ownerId=ownerId, **payload)
  10365. return JsonOkResponse(payload={"packageId": str(monthlyPackage.id)})
  10366. @permission_required(ROLE.dealer)
  10367. def deleteAuth(request):
  10368. session = DealerSessionBuilder(request)
  10369. if session.is_dealer_trustee():
  10370. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10371. if request.method != 'POST':
  10372. return ErrorResponseRedirect(error=cn(u'异常访问'))
  10373. payload = json.loads(request.body)
  10374. operIds = payload.get('ids')
  10375. try:
  10376. PermissionRole.delete_role_permission(operIds=operIds, dealerId=str(request.user.id))
  10377. except Exception:
  10378. return JsonResponse({'result': 0, 'description': '扫码识别失败,请重试', 'payloay':{}})
  10379. return JsonResponse({'result': 1, 'description': '成功', 'payload':{}})
  10380. @permission_required(ROLE.dealer, ROLE.subaccount)
  10381. def toAuthToken(request):
  10382. session = DealerSessionBuilder(request)
  10383. if session.is_dealer_trustee():
  10384. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10385. else:
  10386. if request.user.role == 'dealer':
  10387. dealerId = str(request.user.id)
  10388. payload = {'oper_id':dealerId, 'role':'dealer'}
  10389. elif request.user.role == 'subaccount':
  10390. subaccount = str(request.user.id)
  10391. payload = {'oper_id': subaccount, 'role': 'subaccount'}
  10392. else:
  10393. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10394. token = MyToken.encode(payload)
  10395. logger.info(token)
  10396. return JsonResponse({ 'result': 1, 'description': None, 'payload': {'dealerId': 'xxx', 'token': token}})
  10397. @permission_required(ROLE.dealer)
  10398. def getOtherDealerAuth(request):
  10399. # 经销商扫经销商授权
  10400. scannedURL = request.GET.get('url', None)
  10401. if not scannedURL:
  10402. return JsonResponse({'result': 100, 'description': u'错误的二维码或二维码已损坏'})
  10403. from urlparse import unquote
  10404. scannedURL = unquote(scannedURL)
  10405. logger.debug('scan url is {}'.format(scannedURL))
  10406. return FrontEndResponseRedirect(add_query(scannedURL, {}))
  10407. @permission_required(ROLE.dealer)
  10408. def toAuth(request):
  10409. master_id = str(request.user.id)
  10410. token = request.GET.get('token', None)
  10411. if not token:
  10412. return JsonResponse({'result': 0, 'description': '扫码识别失败,请重试', 'payload': {}})
  10413. try:
  10414. payload = MyToken.decode(token)
  10415. except Exception as e:
  10416. logger.info('toAuth token is invalid..')
  10417. payload = {}
  10418. if not payload:
  10419. return JsonResponse({'result': 0, 'description': '二维码已失效,请重新添加二维码!!', 'payload': {}})
  10420. role = payload.get('role')
  10421. oper_id = payload.get('oper_id')
  10422. if role == 'dealer':
  10423. if PermissionRole.objects.filter(dealerId=master_id, operId=oper_id).first():
  10424. PermissionRole.objects.filter(dealerId=master_id, operId=oper_id).update(isActive=True)
  10425. return JsonResponse({'result': 0, 'description': '已添加授权人!!', 'payload': {}})
  10426. else:
  10427. PermissionRole.add_dealer_role(oper_id, master_id)
  10428. return JsonResponse({'result': 0, 'description': '授权人添加成功', 'payload':{}})
  10429. elif role == 'subaccount':
  10430. if PermissionRole.objects.filter(dealerId=master_id, operId=oper_id).first():
  10431. return JsonResponse({'result': 1, 'description': '已添加授权人!!', 'payload': {}})
  10432. else:
  10433. PermissionRole.add_subAccount_role(oper_id, master_id)
  10434. return JsonResponse({'result': 1, 'description': '授权人添加成功,等待子账号主经销商同意', 'payload': {}})
  10435. @permission_required(ROLE.dealer)
  10436. def getSubAccountBeAuthList(request):
  10437. subAccountId = request.GET.get('id')
  10438. master_id = str(request.user.id)
  10439. subAccount = SubAccount.objects.filter(id=subAccountId).first()
  10440. if not subAccount:
  10441. return JsonResponse({'result': 0, 'description': '扫码识别失败,请重试', 'payloay':{}})
  10442. pageSize = int(request.GET.get('pageSize', 10))
  10443. pageIndex = int(request.GET.get('pageIndex', 1))
  10444. roles = PermissionRole.objects.filter(operId=subAccountId, authorizeType='dealer_to_subAccount')
  10445. count = roles.count()
  10446. dataList = []
  10447. for role in roles.paginate(pageIndex=pageIndex, pageSize=pageSize):
  10448. dealer = Dealer.objects.filter(id=role.dealerId).first()
  10449. if dealer:
  10450. item = {
  10451. 'id': str(dealer.id),
  10452. 'nickname': dealer.nickname,
  10453. 'username': dealer.username,
  10454. 'avatarUrl': dealer.my_avatar if dealer.my_avatar else settings.DEFAULT_AVATAR_URL,
  10455. 'status': 'agreed' if role.isActive else '',
  10456. }
  10457. dataList.append(item)
  10458. return JsonResponse({'result':1, 'username':subAccount.username, 'payload':{'dealerId':subAccount.bossId, 'agentId':subAccount.agentId, 'dataList':dataList}})
  10459. @permission_required(ROLE.dealer)
  10460. def agreeSubAccountBeAuth(request):
  10461. session = DealerSessionBuilder(request)
  10462. if session.is_dealer_trustee():
  10463. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10464. if request.method != 'POST':
  10465. return ErrorResponseRedirect(error=cn(u'异常访问'))
  10466. payload = json.loads(request.body)
  10467. subAccountId = payload.get('subAccountId')
  10468. authDealerId = payload.get('authDealerId')
  10469. if not subAccountId or not authDealerId:
  10470. return JsonResponse({'result': 1, 'description': '授权失败,请稍后再试', 'payload': {}})
  10471. PermissionRole.objects.filter(operId=subAccountId, dealerId=authDealerId).update(isActive=True)
  10472. return JsonResponse({'result': 1, 'description': '成功', 'payload':{}})
  10473. @permission_required(ROLE.dealer)
  10474. def disagreeSubAccountBeAuth(request):
  10475. session = DealerSessionBuilder(request)
  10476. if session.is_dealer_trustee():
  10477. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10478. if request.method != 'POST':
  10479. return ErrorResponseRedirect(error=cn(u'异常访问'))
  10480. payload = json.loads(request.body)
  10481. subAccountId = payload.get('subAccountId')
  10482. authDealerId = payload.get('authDealerId')
  10483. if not subAccountId or not authDealerId:
  10484. return JsonResponse({'result': 1, 'description': '授权失败,请稍后再试', 'payload': {}})
  10485. PermissionRole.objects.filter(operId=subAccountId, dealerId=authDealerId).update(isActive=False)
  10486. return JsonResponse({'result': 1, 'description': '成功', 'payload': {}})
  10487. @permission_required(ROLE.dealer)
  10488. def toOtherDealerAuth(request):
  10489. # 子账号授权
  10490. scannedURL = request.GET.get('url', None)
  10491. if not scannedURL:
  10492. return JsonResponse({'result': 100, 'description': u'错误的二维码或二维码已损坏'})
  10493. from urlparse import unquote
  10494. scannedURL = unquote(scannedURL)
  10495. logger.debug('scan url is {}'.format(scannedURL))
  10496. return FrontEndResponseRedirect(add_query(scannedURL, {}))
  10497. @permission_required(ROLE.dealer, ROLE.subaccount)
  10498. def getLastVirtualCard(request):
  10499. """
  10500. 获取 经销商自己配置的虚拟卡的模板
  10501. :param request:
  10502. :return:
  10503. """
  10504. obj = VirtualCard.get_last(str(request.user.bossId))
  10505. if obj:
  10506. data = obj.to_dict()
  10507. return JsonOkResponse(payload=data)
  10508. else:
  10509. data = {
  10510. 'cardName': u"时长套餐",
  10511. 'price': 30,
  10512. 'periodDays': 30,
  10513. 'expiredTime': (datetime.datetime.now() + datetime.timedelta(days=30)).strftime("%Y-%m-%d"),
  10514. 'dealerDesc': "",
  10515. 'userDesc': "",
  10516. 'dayQuota': [],
  10517. 'quota': [],
  10518. 'sharedMembersCount': 3,
  10519. 'userLimit': 3,
  10520. }
  10521. return JsonOkResponse(payload=data)
  10522. @permission_required(ROLE.dealer, ROLE.subaccount)
  10523. def getDeviceWarning(request):
  10524. """
  10525. 获取设备端的告警信息
  10526. :param request:
  10527. :return:
  10528. """
  10529. logicalCode = request.GET.get("logicalCode")
  10530. dev = Device.get_dev_by_l(logicalCode)
  10531. if not dev:
  10532. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10533. if dev.ownerId != str(request.user.bossId):
  10534. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10535. warningInfo = Device.get_dev_warning_cache(dev.devNo)
  10536. portWarning = list()
  10537. deviceWarning = dict()
  10538. for _part, _warning in warningInfo.items():
  10539. if not _warning:
  10540. continue
  10541. _newWarning = {
  10542. "warningPart": _part,
  10543. "warningStatus": _warning["warningStatus"],
  10544. "warningDesc": _warning["warningDesc"],
  10545. "warningTime": _warning["warningTime"]
  10546. }
  10547. if _part.isdigit():
  10548. portWarning.append(_newWarning)
  10549. else:
  10550. deviceWarning = _newWarning
  10551. return JsonOkResponse(payload={"device": deviceWarning, "ports": portWarning})
  10552. @permission_required(ROLE.dealer, ROLE.subaccount)
  10553. def cancelDeviceWarning(request):
  10554. """
  10555. 取消设备的告警信息
  10556. :param request:
  10557. :return:
  10558. """
  10559. logicalCode = request.POST.get("logicalCode")
  10560. part = request.POST.get("part")
  10561. dev = Device.get_dev_by_l(logicalCode)
  10562. if not dev:
  10563. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10564. if dev.ownerId != str(request.user.bossId):
  10565. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10566. if part is None:
  10567. Device.clear_dev_warning_cache(dev.devNo)
  10568. else:
  10569. Device.clear_part_warning_cache(dev.devNo, part)
  10570. return JsonOkResponse()
  10571. @permission_required(ROLE.dealer, ROLE.subaccount)
  10572. def clearDeviceCache(request):
  10573. data = json.loads(request.body)
  10574. dev = Device.get_dev_by_logicalCode(data['logicalCode'])
  10575. Device.invalid_all_cache(dev)
  10576. return JsonOkResponse()
  10577. @permission_required(ROLE.dealer, ROLE.subaccount)
  10578. def getCurrencyGroups(request):
  10579. """
  10580. 获取经销商通用组以及通用模式
  10581. :param request:
  10582. :return:
  10583. """
  10584. current_user = request.user # type: Dealer
  10585. pageIndex = int(request.GET.get('pageIndex', 1))
  10586. pageSize = int(request.GET.get('pageSize', 10))
  10587. groups = []
  10588. for group in Group.get_collection().find({'ownerId': str(request.user.bossId)},
  10589. {'_id': 1, 'name': 1, 'currencyGroup': 1, 'groupName': 1}):
  10590. if 'currencyGroup' in group:
  10591. groups.append({
  10592. 'groupId': str(group['_id']),
  10593. 'groupName': group['groupName'],
  10594. 'currencyGroup': group['currencyGroup']
  10595. })
  10596. groups.sort(key=itemgetter('currencyGroup'))
  10597. dataList = []
  10598. for currencyGroup, groups in groupby(groups, itemgetter('currencyGroup')):
  10599. dataList.append({
  10600. 'name': currencyGroup,
  10601. 'members': [{'id': group['groupId'], 'name': group['groupName']} for group in groups]
  10602. })
  10603. return JsonOkResponse(payload={
  10604. 'currencyMode': current_user.currency_mode,
  10605. 'total': len(dataList),
  10606. 'dataList': dataList[pageIndex * pageSize - pageSize: pageIndex * pageSize]
  10607. })
  10608. @permission_required(ROLE.dealer, ROLE.subaccount)
  10609. def updatCurrencyGroups(request):
  10610. """
  10611. 更新经销商通用组以及通用模式
  10612. :param request:
  10613. :return:
  10614. """
  10615. boss = request.user.myBoss # type: Dealer
  10616. payload = json.loads(request.body)
  10617. # 校验分组名字是否为'',否则会导致设置地址组通用(删除操作的时候)无法生效.
  10618. name_list = map(lambda x: x.get('name'), payload.get('groupList', None))
  10619. if name_list:
  10620. check_name = None
  10621. for name in name_list:
  10622. if name == check_name:
  10623. return JsonErrorResponse(description='分组名称不能相同')
  10624. else:
  10625. check_name = name
  10626. else:
  10627. pass
  10628. # 初始化之前的组
  10629. beforeDataList = payload.get('beforeDataList', [])
  10630. for groupInfo in beforeDataList:
  10631. group_ids = [ObjectId(group['id']) for group in groupInfo['members']]
  10632. Group.objects(id__in=group_ids,
  10633. ownerId=str(request.user.bossId)).update(currencyGroup='')
  10634. currencyMode = payload['currencyMode']
  10635. if boss.currencyMode != currencyMode:
  10636. boss.update(currencyMode=currencyMode)
  10637. Dealer.invalid_cache(str(boss.id))
  10638. share_group_list = payload['groupList']
  10639. for share_group in share_group_list:
  10640. share_name = share_group['name']
  10641. group_ids = [ObjectId(group['id']) for group in share_group['members']]
  10642. Group.objects(id__in=group_ids,
  10643. ownerId=str(request.user.bossId)).update(currencyGroup=share_name)
  10644. Group.invalid_group_cache(group_ids)
  10645. return JsonOkResponse()
  10646. @permission_required(ROLE.dealer)
  10647. def setSimChargeAuto(request):
  10648. dealerId = request.user.id
  10649. Device.get_collection().update({'ownerId':str(dealerId)}, {'$set':{'simChargeAuto':True}})
  10650. return JsonOkResponse()
  10651. @permission_required(ROLE .dealer)
  10652. def activeRentDevice(request):
  10653. """
  10654. 经销商主动激活出租设备
  10655. """
  10656. payload = json.loads(request.body)
  10657. logicalCode = payload.get("logicalCode")
  10658. if not logicalCode:
  10659. return JsonErrorResponse(u"激活失败")
  10660. device = Device.objects.get(logicalCode=logicalCode)
  10661. if not device:
  10662. return JsonErrorResponse(u"激活失败")
  10663. try:
  10664. device.active_rent()
  10665. except RentDeviceError as e:
  10666. return JsonErrorResponse(e.message)
  10667. return JsonOkResponse()
  10668. @permission_required(ROLE.dealer)
  10669. def getRentOrder(request):
  10670. """
  10671. 获取经销商所有的日租订单 从前往后
  10672. """
  10673. logicalCode = request.GET.get("logicalCode")
  10674. pageSize = request.GET.get("pageSize")
  10675. pageIndex = request.GET.get("pageIndex")
  10676. if not logicalCode:
  10677. return JsonErrorResponse(u"获取记录失败")
  10678. device = Device.objects.get(logicalCode=logicalCode)
  10679. if not device:
  10680. return JsonErrorResponse(u"获取记录失败")
  10681. orders = DeviceRentOrder.get_by_device(device)
  10682. dataList = [_.to_dict() for _ in orders]
  10683. return JsonOkResponse(payload={"total": orders.count(), "dataList": dataList})
  10684. @permission_required(ROLE.dealer)
  10685. def sendVirtualCard(request):
  10686. payload = json.loads(request.body)
  10687. openId = payload.get("openId")
  10688. groupId = payload.get("groupId")
  10689. cardId = payload.get("cardId")
  10690. vCard = VirtualCard.objects.filter(id=cardId).first()
  10691. if not vCard:
  10692. return JsonErrorResponse(description=u"未找到虚拟卡,请确认虚拟卡信息后重试")
  10693. user = MyUser.objects.filter(openId=openId, groupId=groupId).first()
  10694. if not user:
  10695. return JsonErrorResponse(description=u"未找到用户,请确认派卡地址是否正确")
  10696. userCard = UserVirtualCard(
  10697. cardNo=UserVirtualCard.make_no(),
  10698. cardTypeId=str(cardId),
  10699. openIds=[openId],
  10700. cardName=vCard.cardName,
  10701. ownerOpenId=openId,
  10702. nickname=user.nickname,
  10703. dealerId=vCard.ownerId,
  10704. groupIds=vCard.groupIds,
  10705. devTypeList=vCard.devTypeList,
  10706. price=vCard.price,
  10707. periodDays=vCard.periodDays,
  10708. expiredTime=datetime.datetime.now() + datetime.timedelta(seconds=vCard.periodDays * 24 * 3600),
  10709. dayQuota=vCard.dayQuota,
  10710. userLimit=vCard.userLimit,
  10711. quota=vCard.quota,
  10712. userDesc=vCard.userDesc,
  10713. managerialAppId=user.managerialOpenId,
  10714. managerialOpenId=user.managerialOpenId,
  10715. logicalCode="",
  10716. groupId=groupId
  10717. ).save()
  10718. return JsonOkResponse(description=u"发卡成功")
  10719. @permission_required(ROLE.dealer)
  10720. def stopUserOrder(request):
  10721. orderId = request.GET.get('orderId')
  10722. order = ClientConsumeModelProxy.get_one(id=orderId) # type: ConsumeRecord
  10723. if not order:
  10724. return JsonErrorResponse(description='未找到该笔订单')
  10725. if order.devTypeCode:
  10726. try:
  10727. from apps.web.core.models import DriverAdapter
  10728. adapter = DriverAdapter.get_driver_adapter(order.devTypeCode, None)
  10729. adapter.force_stop_order(order)
  10730. except:
  10731. order.update(isNormal=False, errorDesc='强制订单失败后, 直接更新订单')
  10732. return JsonOkResponse(description=u"停止成功")
  10733. else:
  10734. return JsonErrorResponse(description='强制停止失败')
  10735. @permission_required(ROLE.dealer, ROLE.subaccount)
  10736. def getConsumeTemplate(request):
  10737. """
  10738. 获取用户的消费信息 模板的配置
  10739. :param request:
  10740. :return:
  10741. """
  10742. owner = request.user.myBoss # type: Dealer
  10743. showList = owner.supportedConsumptionShow
  10744. if not showList:
  10745. from apps.web.common.utils import UserConsumeFilter
  10746. showList = UserConsumeFilter.default_filter()
  10747. return JsonOkResponse(payload = {"showList": showList})
  10748. @permission_required(ROLE.dealer, ROLE.subaccount)
  10749. def setConsumeTemplate(request):
  10750. """
  10751. 设置用户的参数
  10752. :param request:
  10753. :return:
  10754. """
  10755. dealerId = request.user.bossId
  10756. payload = json.loads(request.body)
  10757. try:
  10758. Dealer.objects.get(id=dealerId).update(supportedConsumptionShow=payload["showList"])
  10759. Dealer.invalid_cache(dealerId)
  10760. except DoesNotExist:
  10761. return JsonErrorResponse(u"参数错误, 请刷新重试")
  10762. except Exception as e:
  10763. logger.exception("update dealer <{}> supportedConsumptionShow error = {}".format(dealerId, e))
  10764. return JsonErrorResponse(u"参数错误, 请刷新重试")
  10765. return JsonOkResponse()
  10766. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"退款操作中出现异常,请联系客服处理"))
  10767. @permission_required(ROLE.dealer)
  10768. def refundOrder(request):
  10769. payload = json.loads(request.body)
  10770. logger.debug('dealer refund order. dealer: {}, payload: {}'.format(request.user, payload))
  10771. orderNo = payload.get("orderNo", None)
  10772. if not orderNo:
  10773. return JsonErrorResponse(description=u"参数错误,请刷新页面重试")
  10774. refundMoney = RMB(payload.get("refundMoney"))
  10775. deductCoins = VirtualCoin(payload.get("deductCoins"))
  10776. rechargeOrder = ClientRechargeModelProxy.get_one(orderNo=orderNo) # type: RechargeRecord
  10777. if not rechargeOrder:
  10778. return JsonErrorResponse(description=u"未查询到订单,请刷新页面重试")
  10779. if not rechargeOrder.is_refund_available(request.user):
  10780. return JsonErrorResponse(description=u"该类型订单不支持退款")
  10781. if rechargeOrder.coins < deductCoins:
  10782. return JsonErrorResponse(description=u"扣除金币数大于用户实际购买数目")
  10783. currency = rechargeOrder.myuser.calc_currency_balance(rechargeOrder.owner, rechargeOrder.group)
  10784. if currency < deductCoins:
  10785. return JsonErrorResponse(description = u"扣除金币数大于用户目前余额")
  10786. if not rechargeOrder.is_success():
  10787. return JsonErrorResponse(description = u"退款失败,订单状态非成功,请联系平台客服")
  10788. if not rechargeOrder.is_ledgered:
  10789. # 检验订单是否有收益
  10790. return JsonErrorResponse(description=u"退款失败,订单未产生收益,请联系平台客服")
  10791. try:
  10792. refundedOrder = refund_cash(rechargeOrder, refundMoney, deductCoins)
  10793. return JsonOkResponse(description=u"退款成功", payload={"refundedOrderNo": refundedOrder.orderNo})
  10794. except ServiceException as e:
  10795. logger.error(e.result)
  10796. return JsonResponse(e.result)
  10797. except UserServerException as e:
  10798. logger.error(e.message)
  10799. return JsonErrorResponse(description=e.message)
  10800. except Exception as e:
  10801. return JsonErrorResponse(description=u"退款失败,请刷新后重试")
  10802. @permission_required(ROLE.dealer, ROLE.subaccount)
  10803. def getDealerTodoMessage(request):
  10804. """
  10805. 获取经代销商的代办事项
  10806. """
  10807. messages = TodoMessage.get_todo_message(request.user)
  10808. # 进行一次任务检查 查看任务是否完成以及是否需要强制执行
  10809. return JsonOkResponse(payload={"count": len(messages), "dataList": messages})
  10810. @permission_required(ROLE.dealer)
  10811. def saveUserBlackConfig(request):
  10812. dealerId = str(request.user.id)
  10813. payload = json.loads(request.body)
  10814. breakRuleTimes = payload.get('breakRuleTimes', 0)
  10815. orderRemindType = payload.get('orderRemindType', 2)
  10816. openId = payload.get('openId', '')
  10817. dealer = Dealer.objects(id=dealerId).first()
  10818. users = MyUser.objects(openId=openId, agentId=dealer.agentId)
  10819. if users.count() == 0:
  10820. return JsonErrorResponse(description=u"不存在的用户")
  10821. for _ in users:
  10822. _.blacklistConfig['breakRuleTimes'] = breakRuleTimes
  10823. _.blacklistConfig['orderRemindType'] = orderRemindType
  10824. try:
  10825. _.save()
  10826. except Exception as e:
  10827. return JsonErrorResponse(description=u"系统错误")
  10828. return JsonOkResponse(description=u"设置成功")
  10829. @permission_required(ROLE.dealer, ROLE.subaccount)
  10830. @ViewValidator(UserListValidator)
  10831. def userList(request, data):
  10832. groupId = data.get("groupId")
  10833. source = data.get("source")
  10834. reverse = data.get("reverse")
  10835. searchKey = data.get("searchKey")
  10836. pageSize = data.get("pageSize")
  10837. pageIndex = data.get("pageIndex")
  10838. userQuery = MyUser.objects.filter(groupId=groupId)
  10839. if source:
  10840. userQuery = userQuery.filter(gateway=source)
  10841. userQuery = userQuery.order_by("last_login") if reverse else userQuery.order_by("-last_login")
  10842. if re.match(r'1[3-9][0-9]{9}$', searchKey):
  10843. agent = Agent.objects.filter(id = str(request.user.myBoss.agentId)).first() # type: Agent
  10844. if agent.supports('user_identify'):
  10845. user = MyUser.objects(phoneNumber = searchKey).first()
  10846. if not user:
  10847. return JsonErrorResponse(description = u"未找到用户")
  10848. userQuery = userQuery.filter(openId = user.openId)
  10849. users = list(userQuery.paginate(pageIndex, pageSize))
  10850. else:
  10851. unique_user = UniqueUser.objects.filter(phone = searchKey).first() # type: UniqueUser
  10852. if not unique_user:
  10853. return JsonErrorResponse(description = u"未找到用户")
  10854. userQuery = userQuery.filter(openId = unique_user.openId)
  10855. users = list(userQuery.paginate(pageIndex, pageSize))
  10856. elif re.match(r'^[0-9]{5,10}$', searchKey):
  10857. unique_user = UniqueUser.objects.filter(userId = searchKey).first() # type: UniqueUser
  10858. if not unique_user:
  10859. return JsonErrorResponse(description = u"未找到用户")
  10860. userQuery = userQuery.filter(openId = unique_user.openId)
  10861. users = list(userQuery.paginate(pageIndex, pageSize))
  10862. else:
  10863. userQuery = userQuery.search(searchKey)
  10864. users = list(userQuery.paginate(pageIndex, pageSize))
  10865. # 获取用户默认头像
  10866. openIds = [str(_user.openId) for _user in users]
  10867. openId_2_uniId = {_.openId: _.userId for _ in UniqueUser.objects.filter(openId__in=openIds)}
  10868. dataList = list()
  10869. for _user in users: # type: MyUser
  10870. _userInfo = _user.to_dict()
  10871. _userInfo.update(
  10872. {
  10873. "dealerId": str(request.user.bossId),
  10874. "userId": openId_2_uniId.get(_user.openId, ""),
  10875. "id": str(_user.id)
  10876. }
  10877. )
  10878. dataList.append(_userInfo)
  10879. # 总量永远比数据量大于1 这样前端下拉只需要判断 当前的数量和pageSize的对比就行
  10880. total = pageIndex * pageSize + 1 if len(dataList) == pageSize else pageIndex * pageSize
  10881. return JsonResponse({
  10882. "result": 1,
  10883. "description": None,
  10884. "payload": {"total": total, "dataList": dataList}
  10885. })
  10886. @permission_required(ROLE.dealer, ROLE.subaccount)
  10887. def userDetail(request, openId):
  10888. # 获取所有用户的用户组
  10889. groupIds = Group.get_group_ids_of_dealer(str(request.user.bossId))
  10890. users = MyUser.objects.filter(openId=openId, groupId__in=groupIds).order_by("-last_login")
  10891. user = users.first()
  10892. try:
  10893. userId = UniqueUser.objects.get(openId=user.openId).userId
  10894. except DoesNotExist:
  10895. userId = ""
  10896. # 对于users 做累加和处理以及分列处理
  10897. payload = {
  10898. "userId": userId,
  10899. "avatar": user.avatar or Agent.get_agent(user.agentId).get("productLogo"),
  10900. "openId": openId,
  10901. "nickname": user.nickname,
  10902. "status": "black" if check_black_user(dealerId=str(request.user.bossId), openId=openId) else "white",
  10903. "phone": user.phone,
  10904. "total_recharge": RMB(0),
  10905. "total_balance": VirtualCoin(0),
  10906. "total_consume": VirtualCoin(0),
  10907. }
  10908. dataList = list()
  10909. for _user in users: # type: MyUser
  10910. _groupUserInfo = {
  10911. "groupId": _user.groupId,
  10912. "groupName": Group.get_group(_user.groupId).groupName,
  10913. "recharge": RMB(_user.total_recharged),
  10914. "consume": VirtualCoin(_user.total_consumed),
  10915. "balance": VirtualCoin(_user.balance)
  10916. }
  10917. dataList.append(_groupUserInfo)
  10918. payload["total_recharge"] += _groupUserInfo["recharge"]
  10919. payload["total_consume"] += _groupUserInfo["consume"]
  10920. payload["total_balance"] += _groupUserInfo["balance"]
  10921. payload["dataList"] = dataList
  10922. return JsonOkResponse(payload=payload)
  10923. @permission_required(ROLE.dealer, ROLE.subaccount)
  10924. def getPortsInfo(request):
  10925. logicalCode = request.GET.get('logicalCode')
  10926. dev = Device.get_dev_by_l(logicalCode)
  10927. smartBox = dev.deviceAdapter
  10928. portList = smartBox.get_ports_info()
  10929. portList = sorted(portList, key=lambda _: int(_['index']))
  10930. if dev.support_power_graph and 'showPG_in_port_detail' in dev.owner.features:
  10931. for item in portList:
  10932. item['showPG'] = True
  10933. return JsonOkResponse(payload={'portList': portList})
  10934. @permission_required(ROLE.dealer, ROLE.subaccount)
  10935. def getDevicePortDetail(request):
  10936. logicalCode = request.GET.get('logicalCode')
  10937. portIndex = request.GET.get('portIndex')
  10938. dev = Device.get_dev_by_l(logicalCode)
  10939. smartBox = dev.deviceAdapter
  10940. ctrInfo = Device.get_dev_control_cache(dev.devNo)
  10941. payload = smartBox.get_port_using_detail(portIndex, ctrInfo)
  10942. if dev.support_power_graph and 'showPG_in_port_detail' in dev.owner.features:
  10943. payload['showPG'] = True
  10944. payload['index'] = portIndex
  10945. return JsonOkResponse(payload=payload)
  10946. @permission_required(ROLE.dealer, ROLE.subaccount)
  10947. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取失败"))
  10948. def getDealerSwitch(request, category):
  10949. """
  10950. 两级联动开关 经销商的开关获取
  10951. """
  10952. bossId = str(request.user.bossId)
  10953. try:
  10954. dealer = Dealer.objects.get(id=bossId)
  10955. except DoesNotExist:
  10956. return JsonErrorResponse(u"获取配置失败")
  10957. payload = dealer.get_linkage_switch()
  10958. return JsonOkResponse(payload=payload)
  10959. @permission_required(ROLE.dealer, ROLE.subaccount)
  10960. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取失败"))
  10961. def getGroupSwitch(request, category):
  10962. """
  10963. 两级联动开关 地质组的开关获取
  10964. """
  10965. bossId = str(request.user.bossId)
  10966. pageIndex = int(request.GET.get("pageIndex"))
  10967. pageSize = int(request.GET.get("pageSize"))
  10968. try:
  10969. groups = Group.objects.filter(ownerId=bossId)
  10970. except DoesNotExist:
  10971. return JsonErrorResponse(u"获取配置失败")
  10972. offset = (pageIndex - 1) * pageSize
  10973. total = groups.count()
  10974. dataList = list()
  10975. for _group in groups[offset: offset + pageSize]: # type: Group
  10976. _switches = _group.get_linkage_switch()
  10977. _switches.update({"name": _group.groupName, "groupId": str(_group.id)})
  10978. dataList.append(_switches)
  10979. payload = {
  10980. "total": total,
  10981. "dataList": dataList
  10982. }
  10983. return JsonOkResponse(payload=payload)
  10984. @permission_required(ROLE.dealer, ROLE.subaccount)
  10985. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  10986. def setDealerSwitch(request, category):
  10987. """
  10988. 两级联动开关 设置经销商开关
  10989. """
  10990. bossId = str(request.user.bossId)
  10991. try:
  10992. dealer = Dealer.objects.get(id=bossId)
  10993. except DoesNotExist:
  10994. return JsonErrorResponse(u"设置失败")
  10995. payload = json.loads(request.body)
  10996. switch = payload["switch"]
  10997. if switch:
  10998. result = dealer.turn_on(category)
  10999. else:
  11000. result = dealer.turn_off(category)
  11001. return JsonOkResponse() if result else JsonErrorResponse(description=u"设置开关失败,请联系平台客服")
  11002. @permission_required(ROLE.dealer, ROLE.subaccount)
  11003. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11004. def setGroupSwitch(request, category):
  11005. """
  11006. 两级联动开关 设置地质组开关 单个
  11007. """
  11008. bossId = str(request.user.bossId)
  11009. payload = json.loads(request.body)
  11010. groupId = payload["groupId"]
  11011. switch = payload["switch"]
  11012. try:
  11013. group = Group.objects.get(id=groupId, ownerId=bossId)
  11014. except DoesNotExist:
  11015. return JsonErrorResponse(u"设置失败")
  11016. logger.error(group.id)
  11017. if switch:
  11018. group.turn_on(category)
  11019. else:
  11020. group.turn_off(category)
  11021. return JsonOkResponse()
  11022. @permission_required(ROLE.dealer)
  11023. def getServiceChargeModelPara(request):
  11024. """
  11025. 获取服务费模式参数
  11026. :param request:
  11027. :return:
  11028. """
  11029. payload = json.loads(request.body)
  11030. logicalCode = payload.get("logicalCode")
  11031. if isinstance(logicalCode, list) and len(logicalCode):
  11032. logicalCode = logicalCode[0]
  11033. else:
  11034. raise JsonErrorResponse(description=u"无效的设备编号")
  11035. device = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  11036. if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING]:
  11037. serviceChargeModelPara = device.bill_as_service_feature
  11038. if 'half_hour_price_list' or 'top_price_rate' or 'peak_price_rate' or 'normal_price_rate' or 'valley_price_rate' \
  11039. not in device.bill_as_service_feature['elecCharge']:
  11040. return JsonResponse({"result": 1, "description": "", "payload": device.bill_as_service_feature})
  11041. half_hour_price_list = serviceChargeModelPara['elecCharge']['half_hour_price_list']
  11042. nowTime = datetime.datetime.now().strftime('%H:%M')
  11043. timeNowList = nowTime.split(':')
  11044. index = int(timeNowList[0]) * 2 + 2 if int(timeNowList[1]) > 30 else 1 - 1
  11045. currentElecChargeRate = half_hour_price_list['half_hour_price_list'][index]
  11046. if currentElecChargeRate == 'top_price_rate':
  11047. elecCharge = serviceChargeModelPara['elecCharge']['top_price_rate']
  11048. elif currentElecChargeRate == 'peak_price_rate':
  11049. elecCharge = serviceChargeModelPara['elecCharge']['peak_price_rate']
  11050. elif currentElecChargeRate == 'normal_price_rate':
  11051. elecCharge = serviceChargeModelPara['elecCharge']['normal_price_rate']
  11052. elif currentElecChargeRate == 'valley_price_rate':
  11053. elecCharge = serviceChargeModelPara['elecCharge']['valley_price_rate']
  11054. bill_as_service_feature = {
  11055. 'on':device.bill_as_service_feature['on'],
  11056. 'elecCharge':elecCharge,
  11057. 'serviceCharge':device.bill_as_service_feature['service_charge']
  11058. }
  11059. return JsonResponse({"result": 1, "description": "", "payload": bill_as_service_feature})
  11060. return JsonResponse({"result": 1, "description": "", "payload": device.bill_as_service_feature})
  11061. @permission_required(ROLE.dealer, ROLE.subaccount)
  11062. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11063. def setServiceChargeModelPara(request):
  11064. payload = json.loads(request.body)
  11065. logicalCode = payload.get("logicalCode")
  11066. if isinstance(logicalCode, list) and len(logicalCode):
  11067. logicalCode = logicalCode[0]
  11068. else:
  11069. return JsonErrorResponse(description=u"错误的二维码编号")
  11070. elecCharge = payload.get("elecCharge")
  11071. serviceCharge = payload.get("serviceCharge")
  11072. device = Device.get_dev_by_l(logicalCode)
  11073. devNo = device['devNo']
  11074. # if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING]:
  11075. # from apps.web.core.adapter.dianchuan_CarCharging import DianchuanCarCharging
  11076. # device = DianchuanCarCharging(device)
  11077. # device.set_elec_charge_by_dealer(elecCharge)
  11078. # elecChargeDict = {
  11079. # 'top_price_rate' : elecCharge,
  11080. # 'peak_price_rate' : elecCharge,
  11081. # 'normal_price_rate' : elecCharge,
  11082. # 'valley_price_rate' : elecCharge,
  11083. # 'half_hour_price_list' : ['top_price_rate'] * 48,
  11084. # }
  11085. # Device.get_collection().update_one({'devNo': devNo}, {
  11086. # '$set': {
  11087. # 'devType.features.billAsService.elecCharge': elecChargeDict,
  11088. # 'devType.features.billAsService.serviceCharge': serviceCharge
  11089. # }
  11090. # })
  11091. # Device.invalid_device_cache(devNo)
  11092. # return JsonOkResponse()
  11093. Device.get_collection().update_one({'devNo': devNo}, {
  11094. '$set': {
  11095. 'devType.features.billAsService.elecCharge': elecCharge,
  11096. 'devType.features.billAsService.serviceCharge': serviceCharge
  11097. }
  11098. })
  11099. Device.invalid_device_cache(devNo)
  11100. return JsonOkResponse()
  11101. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11102. @permission_required(ROLE.dealer, ROLE.subaccount)
  11103. def getApiInfo(request):
  11104. """
  11105. 获取首页的配额相关数据
  11106. """
  11107. dealer = request.user.myBoss # type: Dealer
  11108. payload = dealer.api_quota_info
  11109. return JsonOkResponse(payload=payload)
  11110. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11111. @permission_required(ROLE.dealer, ROLE.subaccount)
  11112. def getApiAppInfo(request):
  11113. """
  11114. 获取经销上API注册信息
  11115. """
  11116. dealer = request.user.myBoss # type: Dealer
  11117. apiAppInfo = dealer.api_app # type: ApiAppInfo
  11118. return JsonOkResponse(payload={
  11119. 'people': apiAppInfo.people,
  11120. 'tel': apiAppInfo.tel,
  11121. 'callbackUrl': apiAppInfo.callbackUrl,
  11122. 'apiDeviceMax': apiAppInfo.apiDeviceMax
  11123. })
  11124. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11125. @permission_required(ROLE.dealer, ROLE.subaccount)
  11126. def saveApiAppInfo(request):
  11127. """
  11128. 编辑经销上API注册信息
  11129. """
  11130. def check_url(url):
  11131. return re.match(r'^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+', url)
  11132. dealer = request.user.myBoss # type: Dealer
  11133. payload = json.loads(request.body)
  11134. people = payload.get('people')
  11135. tel = payload.get('tel')
  11136. callbackUrl = payload.get('callbackUrl')
  11137. if callbackUrl and not check_url(callbackUrl):
  11138. return JsonErrorResponse(description='回调地址Url填写错误')
  11139. dealer.update_api_app(**{
  11140. 'people': people,
  11141. 'tel': tel,
  11142. 'callbackUrl': callbackUrl
  11143. })
  11144. return JsonOkResponse()
  11145. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11146. @permission_required(ROLE.dealer, ROLE.subaccount)
  11147. def getApiDevice(request):
  11148. """
  11149. 获取经销商的设备列表
  11150. """
  11151. dealerId = request.user.bossId # type: Dealer
  11152. groups = Group.get_group_ids_of_dealer(dealerId)
  11153. groupList = []
  11154. for groupId in groups:
  11155. group = Group.get_group(groupId) # type : GroupDict
  11156. devDict = Device.get_devices_by_group([groupId]) # type:Mapping[DeviceDict]
  11157. if devDict:
  11158. devs = devDict.values()
  11159. groupList.append({
  11160. 'groupName': group['groupName'],
  11161. 'devList': map(lambda _: {'title': '{}_{}'.format(_.devTypeName, _.logicalCode), 'isApi': _.isApi,
  11162. 'logicalCode': _.logicalCode}, devs)
  11163. })
  11164. return JsonOkResponse(payload={'groupList': groupList})
  11165. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11166. @permission_required(ROLE.dealer, ROLE.subaccount)
  11167. def editApiDevice(request):
  11168. """
  11169. 经销商选择api设备
  11170. """
  11171. dealer = request.user.myBoss # type: Dealer
  11172. payload = json.loads(request.body)
  11173. groupList = payload.get('groupList')
  11174. logicalCodes = []
  11175. for item in groupList:
  11176. logicalCodes += item['devList']
  11177. # 找出经销商的全部设备
  11178. groups = Group.get_group_ids_of_dealer(str(dealer.id))
  11179. devDict = Device.get_devices_by_group(groups)
  11180. allList = map(lambda _: _.logicalCode, devDict.values())
  11181. # 找出经销商操作的设备
  11182. trunOnList = map(lambda _: _['logicalCode'], filter(lambda _: _['isApi'] == True, logicalCodes))
  11183. trunOnCount = len(trunOnList)
  11184. if set(trunOnList) - set(allList):
  11185. return JsonErrorResponse(description='非法操作!!! 无法操作其他人的设备')
  11186. apiInfo = dealer.api_app # type: ApiAppInfo
  11187. apiDeviceMax = apiInfo.apiDeviceMax
  11188. if trunOnCount > apiDeviceMax:
  11189. return JsonResponse({'result': 1001, 'description': '经销商API设备配额不足,请购买API设备配额',
  11190. 'payload': {'needQuota': trunOnCount - apiDeviceMax}})
  11191. # 此编辑操作为 关闭此经销商的全部设备 然后开启经销商选中的
  11192. Device.switch_api_mode(allList, isApi=False)
  11193. Device.switch_api_mode(trunOnList, isApi=True)
  11194. return JsonOkResponse()
  11195. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11196. @permission_required(ROLE.dealer, ROLE.subaccount)
  11197. def createQuotaOrder(request):
  11198. dealer = request.user.myBoss # type: Dealer
  11199. payload = json.loads(request.body)
  11200. needQuota = payload.get('needQuota')
  11201. groupList = payload.get('groupList')
  11202. buyType = payload.get('buyType')
  11203. package = payload.get('package', {})
  11204. logicalCodes = []
  11205. if buyType == 'temporary': # 配置设备的时候临时购买
  11206. for item in groupList:
  11207. logicalCodes += item['devList']
  11208. # 找出经销商的全部设备
  11209. groups = Group.get_group_ids_of_dealer(str(dealer.id))
  11210. devDict = Device.get_devices_by_group(groups)
  11211. # 找出经销商操作的设备
  11212. trunOnList = map(lambda _: _['logicalCode'], filter(lambda _: _['isApi'] == True, logicalCodes))
  11213. trunOnCount = len(trunOnList)
  11214. if set(trunOnList) - set(map(lambda _: _.logicalCode, devDict.values())):
  11215. return JsonErrorResponse(description='非法操作!!! 无法操作其他人的设备')
  11216. apiInfo = dealer.api_app # type: ApiAppInfo
  11217. apiDeviceMax = apiInfo.apiDeviceMax
  11218. if trunOnCount - apiDeviceMax <= 0:
  11219. return JsonErrorResponse(description='参数传入有误, 请稍后重试!')
  11220. if trunOnCount - apiDeviceMax != int(needQuota):
  11221. return JsonErrorResponse(description='参数传入有误, 请稍后重试..')
  11222. payload = {
  11223. 'needQuota': needQuota,
  11224. 'trunOnList': trunOnList,
  11225. 'buyType': buyType
  11226. }
  11227. elif buyType == 'package': # 套餐购买页面过来
  11228. payload = {
  11229. 'needQuota': package.get('quota', 1),
  11230. 'trunOnList': [],
  11231. 'buyType': buyType,
  11232. 'package': package
  11233. }
  11234. else:
  11235. return JsonErrorResponse(description='参数传入错误, 请稍后从试')
  11236. # 创建订单
  11237. record = create_dealer_charge_order_for_api(dealer, **payload)
  11238. if record:
  11239. return JsonResponse({'result': 1, 'description': u'创建订单成功', 'payload':{'orderNo':record.orderNo}})
  11240. else:
  11241. return JsonErrorResponse(u'创建订单异常失败')
  11242. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11243. @permission_required(ROLE.dealer, ROLE.subaccount)
  11244. def getQuotaDiscountPackage(request):
  11245. dealer = request.user.myBoss # type: Dealer
  11246. apiInfo = dealer.api_app # type: ApiAppInfo
  11247. unitPrice = apiInfo.apiDevicePerCost
  11248. payload = {
  11249. "unitPrice": unitPrice,
  11250. "discountList": [
  11251. {
  11252. "id": 1,
  11253. "price": unitPrice * 10,
  11254. "quota": 10
  11255. },
  11256. {
  11257. "id": 2,
  11258. "price": unitPrice * 20,
  11259. "quota": 20
  11260. },
  11261. {
  11262. "id": 3,
  11263. "price": unitPrice * 40,
  11264. "quota": 40
  11265. },
  11266. {
  11267. "id": 4,
  11268. "price": unitPrice * 100,
  11269. "quota": 100
  11270. }
  11271. ]
  11272. }
  11273. return JsonOkResponse(payload=payload)
  11274. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11275. @permission_required(ROLE.dealer, ROLE.subaccount)
  11276. def getDisableAdInfo(request):
  11277. """
  11278. 获取首页的配额相关数据
  11279. """
  11280. dealer = request.user.myBoss # type: Dealer
  11281. payload = dealer.disable_ad_quota_info()
  11282. return JsonOkResponse(payload=payload)
  11283. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11284. @permission_required(ROLE.dealer, ROLE.subaccount)
  11285. def getDisableAdDevice(request):
  11286. dealerId = request.user.bossId # type: Dealer
  11287. groups = Group.get_group_ids_of_dealer(dealerId)
  11288. groupList = []
  11289. now = datetime.datetime.now()
  11290. def _filter(dev):
  11291. formart_dict = {
  11292. 'title': '{}_{}'.format(dev.devTypeName, dev.logicalCode),
  11293. 'logicalCode': dev.logicalCode,
  11294. 'expiredTime':None
  11295. }
  11296. if dev.disableADExpireDate and dev.disableADExpireDate > now:
  11297. formart_dict.update({
  11298. 'expiredTime': dev.disableADExpireDate.strftime("%Y-%m-%d %H:%M:%S")
  11299. })
  11300. return formart_dict
  11301. for groupId in groups:
  11302. group = Group.get_group(groupId) # type : GroupDict
  11303. devDict = Device.get_devices_by_group([groupId]) # type:Mapping[DeviceDict]
  11304. if devDict:
  11305. devs = devDict.values()
  11306. groupList.append({
  11307. 'groupName': group['groupName'],
  11308. 'devList': map(_filter, devs)
  11309. })
  11310. return JsonOkResponse(payload={'groupList': groupList})
  11311. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11312. @permission_required(ROLE.dealer, ROLE.subaccount)
  11313. def DisableAdDeviceRecharge(request):
  11314. payload = json.loads(request.body)
  11315. groupList = payload.get('groupList', [])
  11316. devList = []
  11317. for item in groupList:
  11318. devList += item.get('devList', [])
  11319. configuredList = filter(lambda _: _['configured'] == True, devList)
  11320. payInfo = []
  11321. total = 0
  11322. totalMoney = RMB(0)
  11323. for item in configuredList:
  11324. dev = Device.get_dev_by_l(item.get('logicalCode'))
  11325. if not dev:
  11326. continue
  11327. payInfo.append({
  11328. 'title': item.get('title'),
  11329. 'logicalCode':dev.logicalCode,
  11330. 'expireDate': dev.disableADExpireDate,
  11331. 'money': dev.owner.disable_ad_plan.disableAdCost.mongo_amount,
  11332. 'cycle': dev.owner.disable_ad_plan.cycle
  11333. })
  11334. total += 1
  11335. totalMoney += dev.owner.disable_ad_plan.disableAdCost
  11336. return JsonOkResponse(payload={'devList': payInfo, 'total':total, 'totalMoney':totalMoney.mongo_amount})
  11337. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11338. @permission_required(ROLE.dealer, ROLE.subaccount)
  11339. def createDisableAdOrder(request):
  11340. dealer = request.user.myBoss # type: Dealer
  11341. payload = json.loads(request.body)
  11342. buyType = payload.get('buyType')
  11343. devList = payload.get('devList', {})
  11344. logicalCodes = []
  11345. if buyType != 'temporary': # 配置设备的时候临时购买
  11346. return JsonErrorResponse(description='参数传入错误, 请稍后从试')
  11347. for item in devList:
  11348. logicalCodes.append(item['logicalCode'])
  11349. # 找出经销商的全部设备
  11350. devs = Device.get_devs_by_ownerId(str(dealer.id))
  11351. # 找出经销商将要操作的设备
  11352. if set(logicalCodes) - set(map(lambda _: _.logicalCode, devs)):
  11353. return JsonErrorResponse(description='非法操作!!! 无法操作其他人的设备')
  11354. # 创建订单
  11355. record = create_dealer_charge_order_for_disable_ad(dealer, devList)
  11356. if record:
  11357. return JsonResponse({'result': 1, 'description': u'创建订单成功', 'payload':{'orderNo':record.orderNo}})
  11358. else:
  11359. return JsonErrorResponse(u'创建订单异常失败')
  11360. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11361. @permission_required(ROLE.dealer, ROLE.subaccount)
  11362. def getServerFunction(request):
  11363. payload = json.loads(request.body)
  11364. lc = payload.get("logicalCode")
  11365. if isinstance(lc, list) and len(lc):
  11366. lc = lc[0]
  11367. else:
  11368. raise JsonErrorResponse(description=u"无效的设备编号")
  11369. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  11370. if not dev:
  11371. return JsonResponse({'result': 0, 'description': u'未找到该设备', 'payload': {}})
  11372. setConf = dev.deviceAdapter.get_server_setting()
  11373. if setConf is None:
  11374. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  11375. else:
  11376. return JsonResponse({'result': 1, 'description': u'', 'payload': setConf})
  11377. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11378. @permission_required(ROLE.dealer, ROLE.subaccount)
  11379. def setServerFunction(request):
  11380. payload = json.loads(request.body)
  11381. # 去掉多余的参数
  11382. payload.pop('groupId', None)
  11383. logicalCodes = payload.pop('logicalCode')
  11384. if len(logicalCodes) > 1:
  11385. dev = Device.get_dev_by_l(logicalCodes[0]) # type: DeviceDict
  11386. payload = {
  11387. 'operator': {
  11388. 'id': str(request.user.id),
  11389. 'role': request.user.role,
  11390. 'username': request.user.username
  11391. },
  11392. 'logicalCodes': logicalCodes,
  11393. 'payload': payload,
  11394. 'ownerId': dev.ownerId,
  11395. 'devTypeCode': dev.devTypeCode,
  11396. 'operationId': 'server_setting_{}_{}'.format(str(request.user.id), int(time.time()))
  11397. }
  11398. from taskmanager.mediator import task_caller
  11399. task_caller('batch_set_server_settings', **payload)
  11400. return JsonResponse({'result': 1, 'description': None, 'payload': {'operationId': payload['operationId']}})
  11401. else:
  11402. device = Device.get_dev_by_l(logicalCodes[0]) # type: DeviceDict
  11403. if not device:
  11404. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  11405. if device.ownerId != str(request.user.bossId):
  11406. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  11407. try:
  11408. before = device.deviceAdapter.get_server_setting()
  11409. device.deviceAdapter.set_server_setting(payload)
  11410. OperatorLog.log_dev_operation(
  11411. operator=request.user,
  11412. device=device,
  11413. operator_name='setServerSetting',
  11414. content={
  11415. 'before': before, 'after': payload
  11416. })
  11417. except InvalidParameter as e:
  11418. return JsonErrorResponse(description=e.message)
  11419. return JsonOkResponse()
  11420. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11421. @permission_required(ROLE.dealer, ROLE.subaccount)
  11422. def getDealerPreferentialRechargeTemplate(request):
  11423. ownerId = str(request.user.bossId)
  11424. pageIndex = int(request.GET.get('pageIndex', 1))
  11425. pageSize = int(request.GET.get('pageSize', 10))
  11426. templateType = str(request.GET.get('type'))
  11427. dealer = Dealer.objects(id=ownerId).first()
  11428. if dealer is None:
  11429. return JsonErrorResponse(description=u'未知错误')
  11430. if templateType == 'preferentialRechargeTemplate':
  11431. dataList = dealer.templateSet.rechargeDiscount
  11432. elif templateType == 'cardPreferentialRechargeTemplate':
  11433. dataList = dealer.templateSet.cardRechargeDiscount
  11434. else:
  11435. return JsonErrorResponse(description=u"未知错误")
  11436. payload = {
  11437. "total": len(dataList),
  11438. "dataList": dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  11439. }
  11440. return JsonOkResponse(payload=payload)
  11441. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11442. @permission_required(ROLE.dealer, ROLE.subaccount)
  11443. def getDealerPreferentialRechargeTemplateById(request):
  11444. ownerId = str(request.user.bossId)
  11445. templateId = request.GET.get('id', None)
  11446. templateType = str(request.GET.get('type'))
  11447. if templateId is None:
  11448. return JsonErrorResponse(description=u'未知错误')
  11449. dealer = Dealer.objects(id=ownerId).first()
  11450. if dealer is None:
  11451. return JsonErrorResponse(description=u'未知错误')
  11452. if templateType == 'preferentialRechargeTemplate':
  11453. dataList = dealer.templateSet.rechargeDiscount
  11454. elif templateType == 'cardPreferentialRechargeTemplate':
  11455. dataList = dealer.templateSet.cardRechargeDiscount
  11456. else:
  11457. return JsonErrorResponse(description=u"未知错误")
  11458. payload = [_ for _ in dataList if int(templateId) == int(_['id'])][0]
  11459. return JsonOkResponse(payload=payload)
  11460. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11461. @permission_required(ROLE.dealer, ROLE.subaccount)
  11462. def editDealerPreferentialRechargeTemplate(request):
  11463. ownerId = str(request.user.bossId)
  11464. tempData = json.loads(request.body)
  11465. templateType = tempData['type']
  11466. del tempData['type']
  11467. dealer = Dealer.objects(id=ownerId).first()
  11468. if dealer is None:
  11469. return JsonErrorResponse(description=u'未知错误')
  11470. if templateType == 'preferentialRechargeTemplate':
  11471. tempDataList = dealer.templateSet.rechargeDiscount
  11472. elif templateType == 'cardPreferentialRechargeTemplate':
  11473. tempDataList = dealer.templateSet.cardRechargeDiscount
  11474. else:
  11475. return JsonErrorResponse(description=u"未知错误")
  11476. for _ in tempDataList:
  11477. if int(_['id']) == int(tempData['id']):
  11478. tempDataList.remove(_)
  11479. tempDataList.append(tempData)
  11480. if templateType == 'preferentialRechargeTemplate':
  11481. dealer.templateSet.rechargeDiscount = tempDataList
  11482. else:
  11483. dealer.templateSet.cardRechargeDiscount = tempDataList
  11484. dealer.save()
  11485. return JsonOkResponse()
  11486. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11487. @permission_required(ROLE.dealer, ROLE.subaccount)
  11488. def addDealerPreferentialRechargeTemplate(request):
  11489. ownerId = str(request.user.bossId)
  11490. payload = json.loads(request.body)
  11491. templateType = payload['type']
  11492. dealer = Dealer.objects(id=ownerId).first()
  11493. if dealer is None:
  11494. return JsonErrorResponse(description=u'未知错误')
  11495. if templateType == 'preferentialRechargeTemplate':
  11496. tempDataList = dealer.templateSet.rechargeDiscount
  11497. elif templateType == 'cardPreferentialRechargeTemplate':
  11498. tempDataList = dealer.templateSet.cardRechargeDiscount
  11499. else:
  11500. return JsonErrorResponse(description=u"未知错误")
  11501. if len(tempDataList) == 0:
  11502. tempId = 1
  11503. else:
  11504. tempId = max(int(_['id']) for _ in tempDataList) + 1
  11505. temp = {}
  11506. templateInfo = payload.get('templateInfo', [])
  11507. templateName = payload.get('templateName', '')
  11508. if not templateInfo or templateName == '':
  11509. return JsonErrorResponse(description=u'套餐错误')
  11510. for _ in templateInfo:
  11511. _['coins'] = float(_['coins'])
  11512. _['ruleId'] = _['payAmount']
  11513. temp.update({'templateName': templateName, 'templateInfo': templateInfo, 'id': tempId})
  11514. if templateType == 'preferentialRechargeTemplate':
  11515. dealer.templateSet.rechargeDiscount.append(temp)
  11516. else:
  11517. dealer.templateSet.cardRechargeDiscount.append(temp)
  11518. dealer.save()
  11519. return JsonOkResponse()
  11520. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11521. @permission_required(ROLE.dealer, ROLE.subaccount)
  11522. def deleteDealerPreferentialRechargeTemplate(request):
  11523. ownerId = str(request.user.bossId)
  11524. payload = json.loads(request.body)
  11525. tempId = payload['id']
  11526. templateType = payload['type']
  11527. dealer = Dealer.objects(id=ownerId).first()
  11528. if dealer is None:
  11529. return JsonErrorResponse(description=u'未知错误')
  11530. if templateType == 'preferentialRechargeTemplate':
  11531. tempDataList = dealer.templateSet.rechargeDiscount
  11532. elif templateType == 'cardPreferentialRechargeTemplate':
  11533. tempDataList = dealer.templateSet.cardRechargeDiscount
  11534. else:
  11535. return JsonErrorResponse(description=u"未知错误")
  11536. for _ in tempDataList:
  11537. if int(_['id']) == int(tempId):
  11538. tempDataList.remove(_)
  11539. if templateType == 'preferentialRechargeTemplate':
  11540. dealer.templateSet.rechargeDiscount = tempDataList
  11541. else:
  11542. dealer.templateSet.cardRechargeDiscount = tempDataList
  11543. dealer.save()
  11544. return JsonOkResponse()
  11545. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11546. @permission_required(ROLE.dealer, ROLE.subaccount)
  11547. def editGroupsToPreferentialRechargeTemplate(request):
  11548. ownerId = str(request.user.bossId)
  11549. payload = json.loads(request.body)
  11550. tempId = payload['id']
  11551. templateType = payload['type']
  11552. groupIds = [_['groupId'] for _ in payload['groupId']]
  11553. dealer = Dealer.objects(id=ownerId).first()
  11554. if dealer is None:
  11555. return JsonErrorResponse(description=u'未知错误')
  11556. tempData = dict()
  11557. if templateType == 'preferentialRechargeTemplate':
  11558. tempDataList = dealer.templateSet.rechargeDiscount
  11559. elif templateType == 'cardPreferentialRechargeTemplate':
  11560. tempDataList = dealer.templateSet.cardRechargeDiscount
  11561. else:
  11562. return JsonErrorResponse(description=u"未知错误")
  11563. for _ in tempDataList:
  11564. if int(_['id']) == int(tempId):
  11565. tempData = _
  11566. break
  11567. tempRule = dict()
  11568. for _ in tempData['templateInfo']:
  11569. tempRule.update({_['payAmount']: _['coins']})
  11570. if templateType == 'preferentialRechargeTemplate':
  11571. for _ in Group.objects(id__in=groupIds):
  11572. _.ruleDict = format_dot_key(tempRule)
  11573. _.save()
  11574. else:
  11575. for _ in Group.objects(id__in=groupIds):
  11576. _.cardRuleDict = format_dot_key(tempRule)
  11577. _.save()
  11578. GroupCacheMgr.invalid_group_cache(groupIds)
  11579. return JsonOkResponse()
  11580. @permission_required(ROLE.dealer, ROLE.subaccount)
  11581. def getServiceFeePackage(request):
  11582. logicalCode = request.GET.get('logicalCode')
  11583. if not logicalCode:
  11584. raise JsonErrorResponse(description=u'无效的设备编号')
  11585. dev = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  11586. payload = dev.deviceAdapter.get_service_fee_info()
  11587. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  11588. @permission_required(ROLE.dealer, ROLE.subaccount)
  11589. def setServiceFeePackage(request):
  11590. """
  11591. 设置服务费计费参数, 暂时不支持批量
  11592. :param request:
  11593. :return:
  11594. """
  11595. payload = json.loads(request.body)
  11596. if 'billAsService' not in payload:
  11597. return JsonErrorResponse(description=u'传入参数错误')
  11598. logicalCode = payload.get("logicalCode")
  11599. try:
  11600. device = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  11601. device.deviceAdapter.set_service_fee_info(payload)
  11602. except InvalidParameter as e:
  11603. return JsonErrorResponse(description=e.message)
  11604. return JsonOkResponse()
  11605. @permission_required(ROLE.dealer)
  11606. def interconnectionConfig(request):
  11607. ownerId = str(request.user.bossId)
  11608. pageIndex = int(request.GET.get('pageIndex', 1))
  11609. pageSize = int(request.GET.get('pageSize', 10))
  11610. searchKey = str(request.GET.get('searchKey', ''))
  11611. swapFlagSearch = None
  11612. if 'swapFlag' in request.GET:
  11613. if request.GET.get('swapFlag') == 'false':
  11614. swapFlagSearch = False
  11615. else:
  11616. swapFlagSearch = True
  11617. dataList = []
  11618. groupIds = Group.get_group_ids_of_dealer(ownerId)
  11619. groupList = Group.get_groups_by_group_ids(groupIds).values()
  11620. groupList = natural_sort(groupList, 'groupName', False)
  11621. for grp in groupList:
  11622. if searchKey not in grp['groupName']:
  11623. continue
  11624. if swapFlagSearch is not None and swapFlagSearch != grp.get('swapFlag', False):
  11625. continue
  11626. if 'swapFlag' not in grp:
  11627. grp['swapFlag'] = False
  11628. elif grp['swapFlag']:
  11629. swapInfo = SwapGroup.objects(groupId=grp['groupId']).first()
  11630. if swapInfo is not None:
  11631. grp['joinedTime'] = swapInfo.joinedTime.strftime('%Y-%m-%d %H:%M:%S')
  11632. dataList.append(grp)
  11633. return JsonResponse({
  11634. "result": 1,
  11635. "description": None,
  11636. 'payload': {
  11637. "total": len(dataList),
  11638. "dataList": dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  11639. }
  11640. })
  11641. @permission_required(ROLE.dealer)
  11642. def interconnectionDetail(request):
  11643. ownerId = str(request.user.bossId)
  11644. groupId = request.GET.get('groupId', None)
  11645. if groupId is None:
  11646. return JsonErrorResponse(description=u"缺少参数")
  11647. swapInfo = SwapGroup.objects(groupId=groupId).first()
  11648. if swapInfo is None:
  11649. return JsonOkResponse(payload={})
  11650. if ownerId != swapInfo.ownerId:
  11651. return JsonErrorResponse(description=u"参数不一致")
  11652. payload = {
  11653. 'StationLng':swapInfo.lng,
  11654. 'StationLat':swapInfo.lat,
  11655. 'BusineHours':swapInfo.BusineHours,
  11656. 'SiteGuide':swapInfo.SiteGuide,
  11657. 'Construction':swapInfo.Construction,
  11658. 'SupportOrder':swapInfo.SupportOrder,
  11659. 'Pictures':[{'PicID':pic.PicID, 'IsCover':pic.IsCover, 'Url':pic.Url, 'title':pic.Title, 'Title':pic.TitleForShow} for pic in swapInfo.Pictures],
  11660. 'MatchCars':swapInfo.MatchCars,
  11661. 'ParkInfo':swapInfo.ParkInfo,
  11662. 'StationStatus':swapInfo.StationStatus,
  11663. 'ParkNums':swapInfo.ParkNums,
  11664. 'originalAlternateFeeRemark':swapInfo.originalAlternateFeeRemark,
  11665. 'alternateFeeRemark':swapInfo.alternateFeeRemark,
  11666. 'originalDirectFeeRemark':swapInfo.originalDirectFeeRemark,
  11667. 'directFeeRemark':swapInfo.directFeeRemark,
  11668. 'PriceChargingInfo':[{'FeeTime':info.FeeTime, 'ElectricityFee':info.ElectricityFee, 'ServiceFee':info.ServiceFee} for info in swapInfo.PriceChargingInfo],
  11669. 'DiscountPriceChargingInfo':[{'FeeTime':info.DiscountTime, 'ElectricityFee':info.DiscountElectricityFee, 'ServiceFee':info.DiscountServiceFee} for info in swapInfo.DiscountPriceChargingInfo],
  11670. 'ElectricityFee':swapInfo.ElectricityFee,
  11671. 'ServiceFee':swapInfo.ServiceFee,
  11672. 'ParkFee':swapInfo.ParkFee,
  11673. 'chargeTagList':[{'tagId':tag.tagId, 'tagType':tag.tagType, 'tagDesc':tag.tagDesc, 'tagOrder':tag.tagOrder, 'tagName':tag.tagName, 'color':tag.color} for tag in swapInfo.ChargeTagList],
  11674. 'StationTel':swapInfo.StationTel,
  11675. 'ServiceTel':swapInfo.ServiceTel,
  11676. 'Payment':swapInfo.Payment,
  11677. 'Remark':swapInfo.Remark,
  11678. 'RightTag':swapInfo.RightTag,
  11679. 'StationType':swapInfo.StationType
  11680. }
  11681. if swapInfo.swapFlag:
  11682. payload.update({'joinedTime':swapInfo.joinedTime.strftime('%Y-%m-%d %H:%M:%S')})
  11683. return JsonOkResponse(payload=payload)
  11684. @permission_required(ROLE.dealer)
  11685. def uploadSwapPicture(request):
  11686. files = request.FILES.getlist('file')
  11687. groupId = request.POST.get('groupId', None)
  11688. tail = request.POST.get('tail', None)
  11689. if groupId is None:
  11690. return JsonErrorResponse(description=u"缺少参数")
  11691. if not len(files):
  11692. return JsonResponse({'result': 0, 'description': u'未找到上传的商品图片,请重新试试', 'payload': {}})
  11693. uploader = SwapGroupPicFileUploader(inputFile=request.FILES.getlist('file')[0], uploadType='swap', groupId=groupId, tail=tail)
  11694. logger.info('[uploadItemPic] %s is being used' % (repr(uploader),))
  11695. try:
  11696. outputUrl = uploader.upload()
  11697. return JsonResponse({'result': 1, 'description': '', 'payload': {'Url':outputUrl}})
  11698. except InvalidFileSize, e:
  11699. logger.info(
  11700. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  11701. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  11702. except InvalidFileName, e:
  11703. logger.info(
  11704. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  11705. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  11706. @permission_required(ROLE.dealer)
  11707. def getFeeMode(request):
  11708. payload = request.POST
  11709. logicalCode = payload.get("logicalCode")
  11710. devObj = Device.objects.get(logicalCode=logicalCode)
  11711. if devObj.ownerId != str(request.user.id):
  11712. return JsonErrorResponse(description=u"参数错误")
  11713. feeMode = devObj.otherConf.get('feeMode', {})
  11714. timeRateList = []
  11715. shiduan = feeMode.get('shiduan', '000000000000000000000000000000000000000000000000')
  11716. for ii in range(48):
  11717. startHour = 0 + ii / 2
  11718. startMin = '00' if ii % 2 == 0 else '30'
  11719. endHour = startHour if ii % 2 == 0 else startHour + 1
  11720. endMin = '30' if ii % 2 == 0 else '00'
  11721. startTime = '%02d:%s' % (startHour, startMin)
  11722. endTime = '%02d:%s' % (endHour, endMin)
  11723. timeRateList.append({'startTime':startTime, 'endTime':endTime, 'rate':shiduan[ii]})
  11724. result = {'top_price_rate':feeMode.get('jianFee', 0),
  11725. 'top_price_service_rate':feeMode.get('jianServe', 0),
  11726. 'peak_price_rate':feeMode.get('fengFee', 0),
  11727. 'peak_price_service_rate':feeMode.get('fengServe', 0),
  11728. 'normal_price_rate':feeMode.get('pingFee', 0),
  11729. 'normal_price_service_rate':feeMode.get('pingServe', 0),
  11730. 'valley_price_rate':feeMode.get('guFee', 0),
  11731. 'valley_price_service_rate':feeMode.get('guServe', 0),
  11732. 'jishunScale':feeMode.get('jishunScale', 0),
  11733. 'timeRateList':timeRateList}
  11734. return result
  11735. @permission_required(ROLE.dealer)
  11736. def setFeeMode(request):
  11737. payload = request.POST
  11738. logicalCode = payload.get("logicalCode")
  11739. devObj = Device.objects.get(logicalCode=logicalCode)
  11740. if devObj.ownerId != str(request.user.id):
  11741. return JsonErrorResponse(description=u"参数错误")
  11742. feeMode = devObj.otherConf.get('feeMode', {})
  11743. feeMode['jianFee'] = float(request.POST.get('top_price_rate'))
  11744. feeMode['jianServe'] = float(request.POST.get('top_price_service_rate'))
  11745. feeMode['fengFee'] = float(request.POST.get('peak_price_rate'))
  11746. feeMode['fengServe'] = float(request.POST.get('peak_price_service_rate'))
  11747. feeMode['pingFee'] = float(request.POST.get('normal_price_rate'))
  11748. feeMode['pingServe'] = float(request.POST.get('normal_price_service_rate'))
  11749. feeMode['guFee'] = float(request.POST.get('valley_price_rate'))
  11750. feeMode['guServe'] = float(request.POST.get('valley_price_service_rate'))
  11751. feeMode['jishunScale'] = float(request.POST.get('jishunScale', 0))
  11752. shiduan = ''
  11753. for ii in range(48):
  11754. startHour = 0 + ii / 2
  11755. startMin = '00' if ii % 2 == 0 else '30'
  11756. endHour = startHour if ii % 2 == 0 else startHour + 1
  11757. endMin = '30' if ii % 2 == 0 else '00'
  11758. startTime = '%02d:%s' % (startHour, startMin)
  11759. endTime = '%02d:%s' % (endHour, endMin)
  11760. print startTime, endTime
  11761. harfHourValue = '0'
  11762. for conf in request.POST.get('timeRateList'):
  11763. if startTime >= conf['startTime'] and endTime <= conf['endTime']:
  11764. harfHourValue = conf['rate']
  11765. break
  11766. else:
  11767. continue
  11768. shiduan += harfHourValue
  11769. feeMode['shiduan'] = shiduan
  11770. try:
  11771. devObj.save()
  11772. except Exception, e:
  11773. return JsonResponse({"result": 2, "description": "配置失败,请重试"})
  11774. return JsonOkResponse()
  11775. @permission_required(ROLE.dealer)
  11776. def setGroupSwapFlag(request):
  11777. ownerId = str(request.user.bossId)
  11778. groupId = request.POST.get('groupId', None)
  11779. if groupId is None:
  11780. return JsonErrorResponse(description=u"缺少参数")
  11781. swapFalg = request.POST.get('swapFlag', False)
  11782. success, description, groupId = Group.update_group(groupId, swapFalg=swapFalg)
  11783. SwapGroup.get_collection().update({'groupId':groupId}, {'$set':{'swapFlag':swapFalg}})
  11784. return JsonOkResponse() if success else JsonErrorResponse(description=description,
  11785. payload={'groupId': groupId})
  11786. @permission_required(ROLE.dealer)
  11787. def saveInterconnectionDetail(request):
  11788. ownerId = str(request.user.bossId)
  11789. data = json.loads(request.body)
  11790. groupId = data.get('groupId', None)
  11791. if groupId is None:
  11792. return JsonErrorResponse(description=u"缺少参数")
  11793. group = Group.get_group(groupId)
  11794. if group is None:
  11795. return JsonErrorResponse(description=u"参数错误")
  11796. swapInfo = SwapGroup.objects(groupId=groupId).first()
  11797. if swapInfo is None:
  11798. swapInfo = SwapGroup(groupId=groupId, stationID=SwapGroup.make_stationID(groupId))
  11799. lng, lat = SwapGroup.bd09_to_gcj02(data['StationLng'], data['StationLat'])
  11800. swapInfo.ownerId = ownerId
  11801. swapInfo.swapFlag = data.get('swapFlag', False)
  11802. swapInfo.location = {'type':'Point', 'coordinates':[data['StationLng'], data['StationLat']]}
  11803. swapInfo.gcjLng = lng
  11804. swapInfo.gcjLat = lat
  11805. swapInfo.BusineHours = data['BusineHours']
  11806. swapInfo.SiteGuide = data['SiteGuide']
  11807. swapInfo.Construction = data['Construction']
  11808. swapInfo.SupportOrder = int(data['SupportOrder'])
  11809. ii = 0
  11810. picList = []
  11811. for pic in data['Pictures']:
  11812. ii += 1
  11813. picList.append(Picture(ii, pic['IsCover'], pic['Url'], pic['title'], pic['Title']))
  11814. swapInfo.Pictures = picList
  11815. swapInfo.MatchCars = data['MatchCars']
  11816. swapInfo.ParkInfo = data['ParkInfo']
  11817. swapInfo.StationStatus = data['StationStatus']
  11818. swapInfo.ParkNums = data['ParkNums']
  11819. swapInfo.originalAlternateFeeRemark = data['originalAlternateFeeRemark']
  11820. swapInfo.alternateFeeRemark = data['alternateFeeRemark']
  11821. swapInfo.originalDirectFeeRemark = data['originalDirectFeeRemark']
  11822. swapInfo.directFeeRemark = data['directFeeRemark']
  11823. swapInfo.PriceChargingInfo = [PriceCharging(info['FeeTime'], info['ElectricityFee'], info['ServiceFee']) for info in data['PriceChargingInfo']]
  11824. swapInfo.DiscountPriceChargingInfo = [DiscountPriceCharging(info['FeeTime'], info['ElectricityFee'], info['ServiceFee']) for info in data['DiscountPriceChargingInfo']]
  11825. swapInfo.ElectricityFee = data['ElectricityFee']
  11826. swapInfo.ServiceFee = data['ServiceFee']
  11827. swapInfo.ParkFee = data['ParkFee']
  11828. swapInfo.ChargeTagList = [ChargeTag(0, tag['tagType'], tag['tagDesc'], tag['tagOrder'], tag['tagName'], tag['color']) for tag in data.get('chargeTagList', [])]
  11829. swapInfo.StationTel = data['StationTel']
  11830. swapInfo.ServiceTel = data['ServiceTel']
  11831. swapInfo.Payment = data['Payment']
  11832. swapInfo.SupportOrder = data['SupportOrder']
  11833. swapInfo.Remark = data['Remark']
  11834. swapInfo.RightTag = data['RightTag']
  11835. swapInfo.StationType = data['StationType']
  11836. if swapInfo.swapFlag:
  11837. swapInfo.joinedTime = datetime.datetime.now()
  11838. try:
  11839. swapInfo.save()
  11840. except Exception, e:
  11841. return JsonResponse({"result": 2, "description": "配置失败,请重试"})
  11842. Group.update_group(group_id=groupId, swapFlag=swapInfo.swapFlag)
  11843. SwapGroup.recount_devnum(groupId)
  11844. return JsonOkResponse()
  11845. @permission_required(ROLE.dealer)
  11846. def getInterconnectionDisclaimer(request):
  11847. payload = {
  11848. 'version': '1.01',
  11849. 'content': '<p style="text-align:center;"> &nbsp;互联互通用户协议</p><p style="text-align:left;"> <br />一、【首部及导言】<br />欢迎您使用充电桩互联互通协议!<br />本系统互联互通协议遵从国家关于充电桩互联互通的协议《T/CEC中国电力企业联合会标准》,关于协议的具体规则,可以联系我们技术支持。<br />二、【协议的范围】<br />1、本协议是您与我们充电桩管理平台(以下简称我们)之间关于您使用互联互通功能服务所订立的协议。</p><p style="text-align:left;"> 2、本协议的用户,只指通过我们充电桩管理平台,管理设备的运营商组织和个人,都属于我们的用户。</p><p style="text-align:left;"> 三、【服务内容】<br /><span>1、本协议服务的设备,只有当您打开互联互通开关后,设备才会加入互联互通。关闭开关后,将会地址地址组下的互联互通功能。</span></p>\
  11850. <p style="text-align:left;"> 2、<span>互联互通主要是通过第三方的APP、小程序、H5应用,能够查询到您旗下的设备,并能够通过第三方能够启动充电,并根据账单进行结算。</span></p><p style="text-align:left;">\
  11851. <span>3、互联互通的第三方APP,包括不限于诸如:快电、小桔充电、恒大星脉等等第三方平台,而且每个第三方平台会存在不同的服务区别,包括通过第三方使用充电桩需要提取的佣金、费用结算方式、营销活动推广费用、提现费率等等,具体\
  11852. 情况,在互联互通开放时,请您和我们技术支持沟通确认。</span></p><p style="text-align:left;"> <span>四、【服务要求】</span></p><p style="text-align:left;"> <span>1、您提供的设备,包括交流桩和直流桩,能够保证设备的安全性、可靠性、可用性,以及设备本身的数据统计准确,应当尽量避免因此引起的纠纷。因此而引起的纠纷,我们要求由您负责并处理。</span>\
  11853. </p><p style="text-align:left;"> <span>2、您提供配置的设备信息,包括互联互通的信息,应当准确并符合实际,避免出现消费者对平台进行投诉,因此产生的投诉,将有您负责,并且我们将有权对不符合实际情况的互联互通进行关闭,以保障充电用户的权益。</span>\
  11854. </p><p style="text-align:left;"> <span>3、产生的一些售后处理,可能需要您和我们一起处理,我们希望您保持联系方式的畅通,以保证服务质量。如果用户或者第三方平台投诉到我们这里,我们却多次无法联系到您,我们有权强制禁用您的互联互通功能。</span></p>\
  11855. <p style="text-align:left;"> <span>五、【售后及其他】</span></p><p style="text-align:left;"> <span>1、平台的相关售后,包括您使用的后台、互联互通,由我们负责,如有疑问,可以直接联系我们。</span>\
  11856. </p><p style="text-align:left;"> <span>2、设备相关售后,诸如设备故障、设备维修等,导致的互联互通服务售后,由您负责,我们售后可能会联系您,需要您保持联系方式畅通。</span></p><p style="text-align:left;"> <span><br /></span></p>'
  11857. }
  11858. return JsonOkResponse(payload=payload)
  11859. @error_tolerate(nil=DefaultJsonErrorResponse)
  11860. @permission_required(ROLE.dealer, ROLE.subaccount)
  11861. def getCustomizePoint(request):
  11862. logicalCode = request.GET.get('logicalCode')
  11863. dev = Device.get_dev_by_l(logicalCode)
  11864. if dev is None:
  11865. return JsonErrorResponse(description=u"参数错误")
  11866. box = ActionDeviceBuilder.create_action_device(dev)
  11867. unit = box.get_customize_score_unit()
  11868. if unit is None:
  11869. return JsonResponse({'result': 0, 'description': "", 'payload': {}})
  11870. return JsonResponse({'result': 0, 'description': "", 'payload': [unit]})
  11871. @error_tolerate(nil=DefaultJsonErrorResponse)
  11872. @permission_required(ROLE.dealer, ROLE.subaccount)
  11873. def onCustomizePoint(request):
  11874. logicalCode = request.POST.get('logicalCode')
  11875. pointNum = request.POST.get('time')
  11876. portList = json.loads(request.POST.get('attachParas')).get('chargeIndex')
  11877. openId = request.user.managerialOpenId
  11878. dev = Device.get_dev_by_l(logicalCode)
  11879. if dev is None:
  11880. return JsonErrorResponse(description=u"参数错误")
  11881. box = ActionDeviceBuilder.create_action_device(dev)
  11882. address = Group.get_group(dev['groupId'])['address']
  11883. groupName = Group.get_group(dev['groupId'])['groupName']
  11884. errorList = []
  11885. errdesc = ''
  11886. for port in portList:
  11887. try:
  11888. box.start_customize_point(pointNum, openId, int(port))
  11889. UpscoreRecord(
  11890. logicalCode=dev['logicalCode'],
  11891. devNo=dev['devNo'],
  11892. ownerId=str(request.user.id),
  11893. time=datetime.datetime.now(),
  11894. score=pointNum,
  11895. address=address,
  11896. groupName=groupName,
  11897. devType=dev['devType']['name'],
  11898. type="",
  11899. remark=u'自定义上分:%s%s' % (pointNum, request.POST.get('unit'))
  11900. ).save()
  11901. except ServiceException, e:
  11902. errorList.append(port)
  11903. errdesc = ',' + e.result.get('description')
  11904. continue
  11905. except Exception, e:
  11906. errorList.append(port)
  11907. continue
  11908. if errorList:
  11909. return JsonResponse({'result': 0, 'description': u"出现上分失败" + errdesc, 'payload': {'errorList':errorList}})
  11910. return JsonResponse({'result': 0, 'description': u"上分成功", 'payload': {'errorList':errorList}})
  11911. @error_tolerate(nil=DefaultJsonErrorResponse)
  11912. @permission_required(ROLE.dealer)
  11913. def getPolicyInfos(request):
  11914. lc = request.GET.get('logicalCode')
  11915. dev = Device.get_dev_by_l(lc)
  11916. box = ActionDeviceBuilder.create_action_device(dev)
  11917. result = box.get_policy_infos()
  11918. return JsonOkResponse(payload=result)
  11919. @error_tolerate(nil=DefaultJsonErrorResponse)
  11920. @permission_required(ROLE.dealer)
  11921. def setPolicyInfos(request):
  11922. payload = json.loads(request.body)
  11923. lc = payload.get('logicalCode')
  11924. dev = Device.get_dev_by_l(lc)
  11925. box = ActionDeviceBuilder.create_action_device(dev)
  11926. try:
  11927. box.set_policy_infos(payload)
  11928. except ServiceException, e:
  11929. return JsonErrorResponse(description=e.result.get('description'))
  11930. return JsonOkResponse(description=u'计费配置保存成功')
  11931. @error_tolerate(logger = logger)
  11932. def refundOrderNotifier(request, pay_app_type):
  11933. """
  11934. 退款回调接口(经销商目前只有微信和京东聚合支付微信部分)
  11935. :param request:
  11936. :param pay_app_type:
  11937. :return:
  11938. """
  11939. assert pay_app_type in PayAppType.choices(), 'not support this pay app type({})'.format(pay_app_type)
  11940. notifier_cls = RefundManager().get_notifier(pay_app_type)
  11941. response = notifier_cls(request, lambda order_no: RefundDealerRechargeRecord.get_record(order_no)).do(
  11942. refund_post_pay)
  11943. return response