views.py 554 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871
  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
  54. from apps.web.common.transaction.refund import RefundManager
  55. from apps.web.common.validation import NAME_RE, PHONE_NUMBER_RE
  56. from apps.web.constant import (
  57. Const,
  58. DEALER_CONSUMPTION_AGG_KIND_TRANSLATION,
  59. DEALER_CONSUMPTION_AGG_KIND, DEALER_CONSUMPTION_AGG_KIND_UNIT,
  60. MONTH_DATE_KEY,
  61. FAULT_RECORD_STATUS, APP_TYPE, PollRecordDefine, TYPE_ADJUST_USER_VIRTUAL_CARD, DeviceCmdCode,
  62. ErrorCode, RECHARGE_CARD_TYPE, RECHARGE_RECORD_VIA_TRANSLATION, skip_package_unit_verify_list,
  63. skip_package_range_verify_list, skip_package_params_verify_list, USER_RECHARGE_TYPE, CONSUMETYPE,
  64. support_policy_weifule, support_policy_device)
  65. from apps.web.constant import RechargeRecordVia
  66. from apps.web.core import PayAppType, ROLE
  67. from apps.web.core.accounting import Accounting, devCoinTmpl
  68. from apps.web.core.auth.wechat import WechatAuthBridge
  69. from apps.web.core.bridge import WechatClientProxy
  70. from apps.web.core.db import paginate, prepare_query, search_query
  71. from apps.web.core.device_define.huopo import HuopoCacheMgr
  72. from apps.web.core.exceptions import ServiceException, InvalidParameter, ParameterError, InvalidFileSize, \
  73. InvalidFileName, RentDeviceError
  74. from apps.web.core.file import AliOssFileUploader, SwapGroupPicFileUploader
  75. from apps.web.core.helpers import ActionDeviceBuilder
  76. from apps.web.core.messages.sms import (
  77. dealerAutoWithdrawSMSProvider,
  78. dealerRegisterSMSProvider,
  79. dealerWithdrawSMSProvider,
  80. dealerBindWechatSMSProvider,
  81. dealerBindWalletWechatSMSProvider,
  82. dealerEditMonitorSMSProvider,
  83. dealerMonitorWithdrawSMSProvider)
  84. from apps.web.core.models import OfflineTask, WechatPayApp
  85. from apps.web.core.networking import MessageSender
  86. from apps.web.core.payment import WithdrawGateway, PaymentGateway
  87. from apps.web.core.payment.wechat import WechatPaymentGateway
  88. from apps.web.core.sysparas import SysParas
  89. from apps.web.core.utils import DefaultJsonErrorResponse, JsonErrorResponse, JsonOkResponse, parse_json_payload
  90. from apps.web.dealer import OfflineTaskType
  91. from apps.web.dealer.define import DEALER_INCOME_SOURCE, DEALER_INCOME_SOURCE_TRANSLATION, DEALER_INCOME_TYPE, \
  92. PAY_NOTIFY_URL, DEALER_BIND_WECHAT_URL, DEALER_BIND_WALLET_WECHAT_URL
  93. from apps.web.dealer.models import (
  94. Dealer, UpscoreRecord, DealerRechargeRecord,
  95. OnSale, OnSaleRecord, VirtualCard,
  96. ElecPriceTemplate, ItemType,
  97. SubAccount, DealerMessage, Complaint, AdjustUserVirtualCardRecord, ExchangeOrder, DealerAddr, UpCardScoreRecord,
  98. PermissionRole, PermissionRule, TodoMessage, ApiAppInfo, RefundDealerRechargeRecord)
  99. from apps.web.dealer.proxy import DealerIncomeProxy
  100. from apps.web.dealer.transaction import post_pay
  101. from apps.web.dealer.transaction_deprecated import refund_post_pay
  102. from apps.web.dealer.utils import gen_login_response, gen_home_response, gen_subaccount_login_response, \
  103. VirtualCardBuilder, create_dealer_sim_charge_order, DealerSessionBuilder, MyToken, \
  104. create_dealer_charge_order_for_api, create_dealer_charge_order_for_disable_ad
  105. from apps.web.dealer.validation import dealerSchema
  106. from apps.web.dealer.validator import UserListValidator
  107. from apps.web.dealer.withdraw import DealerWithdrawService
  108. from apps.web.device.define import DeviceChannelType
  109. from apps.web.device.models import Device, Group, FeedBack, DeviceType, StockRecord, Cell, FaultRecord, Part, Battery, \
  110. GroupDict, DeviceRentOrder, GroupCacheMgr
  111. from apps.web.device.models import DeviceDict, RequestBodyDict, SwapGroup, DiscountPriceCharging, PriceCharging, \
  112. ChargeTag, Picture
  113. from apps.web.device.timescale import SignalManager
  114. from apps.web.device.utils import device_control_cache_key
  115. from apps.web.exceptions import UserServerException
  116. from apps.web.helpers import get_wx_config, current_platform, get_app, \
  117. get_wechat_auth_bridge, \
  118. get_wechat_user_manager_mp_proxy, \
  119. remove_some_desc_for_consume, get_inhourse_wechat_env_pay_gateway
  120. from apps.web.management.models import Manager
  121. from apps.web.report.models import (
  122. DevReport, GroupReport, DealerReport,
  123. GroupDailyStat, DealerMonthlyStat, DealerDailyStat, DeviceDailyStat
  124. )
  125. from apps.web.report.utils import (
  126. consumption_unit_precision,
  127. to_quantity,
  128. translate_income,
  129. translate_consumption)
  130. from apps.web.south_intf.swap_carcharger import SwapContract
  131. from apps.web.south_intf.zhejiang_fire import Company
  132. from apps.web.south_intf.zhejiang_fire import handler_event_to_zhejiang
  133. from apps.web.user.models import RechargeRecord, ConsumeRecord, MyUser, CardConsumeRecord, Card, \
  134. CardRechargeRecord, CardRechargeOrder, UserVirtualCard, ServiceProgress, VirtualCardRechargeRecord, BlackListUsers, \
  135. SwapCardRecord, UniqueUser
  136. from apps.web.user.transaction_deprecated import refund_cash
  137. from apps.web.user.utils import check_black_user, BatteryInfo
  138. from apps.web.user.utils2 import get_paginate
  139. from apps.web.utils import (permission_required, LimitAttemptsManager,
  140. dealer_login, subAccount_login, error_tolerate,
  141. ensure_all_fields_are_not_empty,
  142. is_login, check_role, is_dealer, concat_server_end_url,
  143. ErrorResponseRedirect,
  144. FrontEndResponseRedirect, ExternalResponseRedirect, DealerBindIdResponseRedirect,
  145. ViewValidator, record_operation_behavior)
  146. from apps.web.wrapper import request_limit_by_user
  147. from library.wechatbase.exceptions import WeChatException
  148. from taskmanager.mediator import task_caller
  149. logger = logging.getLogger(__name__)
  150. merge_with = cytoolz.merge_with
  151. get_in = cytoolz.get_in
  152. if TYPE_CHECKING:
  153. from apps.web.core.db import CustomQuerySet
  154. from collections import Iterable
  155. from apps.web.core.db import Query
  156. from apps.web.common.models import UserSearchable
  157. from apps.web.core.adapter.bolai_gateway import ChargingGatewayBox
  158. from apps.web.core.adapter.bolai_node import ChargingBox
  159. from apps.web.core.adapter.huiteng import washerHTBox
  160. from apps.web.core.adapter.xiyiji import WasherBox
  161. @error_tolerate(nil=DefaultJsonErrorResponse)
  162. @permission_required(ROLE.dealer, ROLE.subaccount)
  163. def getCheckCodeForNewTel(request):
  164. # type: (WSGIRequest)->JsonResponse
  165. payload = json.loads(request.body)
  166. toNumber = payload.get('phone', None)
  167. agentId = request.user.agentId
  168. agent = Agent.get_agent(agentId)
  169. productName = agent['productName']
  170. status, msg = dealerRegisterSMSProvider.get(phoneNumber = toNumber,
  171. productName = productName,
  172. vendor = SysParas.get_sms_vendor(request.user.smsVendor))
  173. if not status:
  174. return JsonResponse({'result': 0, 'description': msg})
  175. else:
  176. return JsonResponse({'result': 1, 'description': ''})
  177. @error_tolerate(nil=DefaultJsonErrorResponse)
  178. def getCheckCode(request):
  179. # type: (WSGIRequest)->JsonResponse
  180. """
  181. 经销商获取注册短信验证码
  182. :param request:
  183. :return:
  184. """
  185. payload = json.loads(request.body)
  186. toNumber = payload.get('phone', None)
  187. agentId = request.COOKIES.get('agentId', settings.MY_PRIMARY_AGENT_ID)
  188. agent = Agent.objects(id = agentId).first() # type: Agent
  189. sessionId = payload.get('csessionid', None)
  190. sig = payload.get('sig', None)
  191. token = payload.get('nc_token', None)
  192. result = eval(AliyunSlider().check_validation_results(sessionId, sig, token))
  193. if type(result) is dict:
  194. resultCode = result.get('Code', 900)
  195. else:
  196. resultCode = 900
  197. if resultCode == 100:
  198. status, msg = dealerRegisterSMSProvider.get(phoneNumber = toNumber,
  199. productName = agent.productName,
  200. vendor = SysParas.get_sms_vendor(agent.smsVendor))
  201. if not status:
  202. return JsonResponse({'result': 0, 'description': msg})
  203. else:
  204. return JsonResponse({'result': 1, 'description': ''})
  205. else:
  206. return JsonResponse({'result': 0, 'description': u'非正常请求,验证码发送失败'})
  207. @error_tolerate(nil=DefaultJsonErrorResponse)
  208. def verifyForgetCode(request):
  209. # type: (WSGIRequest)->JsonResponse
  210. """
  211. 经销商验证短信验证码
  212. :param request:
  213. :return:
  214. """
  215. phone = request.POST.get('phone', None)
  216. code = request.POST.get('code', None)
  217. password = request.POST.get('password', "")
  218. agentId = request.POST.get('agentId')
  219. if not agentId:
  220. return JsonErrorResponse(u'未选择您对应的代理商,请刷新后再试')
  221. dealer = Dealer.objects(username=phone, agentId=agentId).first()
  222. while True:
  223. if dealer is None:
  224. response = JsonErrorResponse(u'该手机号尚未注册,请注册后再进行操作')
  225. break
  226. if password == "":
  227. response = JsonErrorResponse(u"请输入密码")
  228. break
  229. status, desc = dealerRegisterSMSProvider.verify(phone, code)
  230. if not status:
  231. response = JsonErrorResponse(desc)
  232. else:
  233. dealer.set_password(password)
  234. dealer.unlock_login()
  235. response = JsonResponse({"result": 1, "description": None, "payload": {}})
  236. break
  237. if agentId != request.COOKIES.get('agentId'):
  238. Agent.record_cookie(agentId, response)
  239. return response
  240. @error_tolerate(nil=DefaultJsonErrorResponse)
  241. def getSubAccountCheckCode(request):
  242. # type: (WSGIRequest)->JsonResponse
  243. """
  244. 经销商获取注册短信验证码
  245. :param request:
  246. :return:
  247. """
  248. payload = json.loads(request.body)
  249. toNumber = payload.get('phone', None)
  250. agentId = request.COOKIES.get('agentId', settings.MY_PRIMARY_AGENT_ID)
  251. agent = Agent.objects(id = agentId).first() # type: Agent
  252. sessionId = payload.get('csessionid', None)
  253. sig = payload.get('sig', None)
  254. token = payload.get('nc_token', None)
  255. result = eval(AliyunSlider().check_validation_results(sessionId, sig, token))
  256. if type(result) is dict:
  257. resultCode = result.get('Code', 900)
  258. else:
  259. resultCode = 900
  260. if resultCode == 100:
  261. status, msg = dealerRegisterSMSProvider.get(phoneNumber = toNumber,
  262. productName = agent.productName,
  263. vendor = SysParas.get_sms_vendor(agent.smsVendor))
  264. if not status:
  265. return JsonResponse({'result': 0, 'description': msg})
  266. else:
  267. return JsonResponse({'result': 1, 'description': ''})
  268. else:
  269. return JsonResponse({'result': 0, 'description': u'非正常请求,验证码发送失败'})
  270. @error_tolerate(nil=DefaultJsonErrorResponse)
  271. def verifySubAccountForgetCode(request):
  272. # type: (WSGIRequest)->JsonResponse
  273. """
  274. 经销商验证短信验证码
  275. :param request:
  276. :return:
  277. """
  278. phone = request.POST.get('phone', None)
  279. code = request.POST.get('code', None)
  280. password = request.POST.get('password', "")
  281. agentId = request.POST.get('agentId')
  282. if not agentId:
  283. return JsonErrorResponse(u'未选择您对应的代理商,请刷新后再试')
  284. subaccount = SubAccount.objects(username=phone, agentId=agentId).first()
  285. while True:
  286. if subaccount is None:
  287. response = JsonErrorResponse(u'该手机号不是子账号,请主账号添加此子账号后再进行操作')
  288. break
  289. if password == "":
  290. response = JsonErrorResponse(u"请输入密码")
  291. break
  292. status, desc = dealerRegisterSMSProvider.verify(phone, code)
  293. if not status:
  294. response = JsonErrorResponse(desc)
  295. else:
  296. subaccount.set_password(password)
  297. subaccount.unlock_login()
  298. response = JsonResponse({"result": 1, "description": None, "payload": {}})
  299. break
  300. if agentId != request.COOKIES.get('agentId'):
  301. Agent.record_cookie(agentId, response)
  302. return response
  303. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  304. def getDealerRegisterSMSCode(request):
  305. # type: (WSGIRequest)->JsonResponse
  306. payload = json.loads(request.body)
  307. phoneNumber = payload.get('phoneNumber', None)
  308. agentId = request.COOKIES.get('agentId', settings.MY_PRIMARY_AGENT_ID)
  309. agent = Agent.objects(id = agentId).first() # type: Agent
  310. sessionId = payload.get('csessionid', None)
  311. sig = payload.get('sig', None)
  312. token = payload.get('nc_token', None)
  313. result = eval(AliyunSlider().check_validation_results(sessionId, sig, token))
  314. if type(result) is dict:
  315. resultCode = result.get('Code', 900)
  316. else:
  317. resultCode = 900
  318. if not phoneNumber:
  319. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  320. if len(Dealer.objects.filter(username = phoneNumber, agentId = agentId)):
  321. return JsonResponse({'result': 0, 'description': u'该手机号已注册'})
  322. if resultCode == 100:
  323. status, msg = dealerRegisterSMSProvider.get(phoneNumber = phoneNumber,
  324. productName = agent.productName,
  325. vendor = SysParas.get_sms_vendor(agent.smsVendor))
  326. if not status:
  327. return JsonResponse({'result': 0, 'description': msg})
  328. else:
  329. return JsonResponse({'result': 1, 'description': ''})
  330. else:
  331. return JsonResponse({'result': 0, 'description': u'非正常请求,验证码发送失败'})
  332. def dealerRegister(request):
  333. # type: (WSGIRequest)->JsonResponse
  334. try:
  335. rawPayload = json.loads(request.body) # type: dict
  336. mid = rawPayload.pop('managerId', None)
  337. if mid:
  338. agentId = Manager.objects.get(id=ObjectId(mid)).primeAgentId
  339. rawPayload['agentId'] = str(agentId)
  340. else:
  341. agentId = rawPayload.pop('agentId', None)
  342. if agentId:
  343. rawPayload['agentId'] = str(agentId)
  344. try:
  345. payload = dealerSchema(rawPayload)
  346. except MultipleInvalid:
  347. return JsonErrorResponse(description=u'信息填入有误,请检查手机号码等信息是否合法')
  348. agentId = rawPayload.get('agentId')
  349. agent = Agent.objects(id=agentId).first() # type: Optional[Agent]
  350. if not agent:
  351. return JsonErrorResponse(description=u'请联系您的代理商获取正确的经销商注册地址')
  352. username = payload.pop('username').strip()
  353. password = payload.pop('password').strip()
  354. if PHONE_NUMBER_RE.match(username) is None:
  355. return JsonErrorResponse(description=u'请输入正确格式的手机号码')
  356. status, msg = dealerRegisterSMSProvider.verify(phoneNumber=username, smsCode=rawPayload["code"])
  357. if not status:
  358. return JsonErrorResponse(description=msg)
  359. payload['features'] = DEFAULT_DEALER_FEATURES
  360. try:
  361. Dealer.create_user(
  362. username = username,
  363. password = password,
  364. adShow = True,
  365. noAdPolicy = 'banner',
  366. annualTrafficCost = agent.annualTrafficCost if \
  367. agent.annualTrafficCost > agent.trafficCardCost else agent.trafficCardCost,
  368. trafficCardCost = agent.trafficCardCost,
  369. withdrawFeeRatio = agent.withdrawFeeRatio if \
  370. agent.withdrawFeeRatio > agent.withdrawFeeRatioCost else agent.withdrawFeeRatioCost,
  371. **payload
  372. )
  373. except NotUniqueError:
  374. return JsonErrorResponse(description=u'该经销商已注册')
  375. except MultipleInvalid as e:
  376. logger.exception('failed to validate register dealer payload due to %s' % e)
  377. return JsonErrorResponse(description=u'部分输入不合法,请重试')
  378. except Exception as e:
  379. logger.exception('cannot register dealer due to %s' % e)
  380. return JsonErrorResponse(description=u'注册失败请重试')
  381. return JsonOkResponse()
  382. def dealerAccess(request):
  383. # type: (WSGIRequest)->JsonResponse
  384. agentId = request.GET.get('agentId', '')
  385. if not is_login(request, ROLE.dealer):
  386. response = gen_login_response(agentId)
  387. else:
  388. agent = Agent.objects(id=str(request.user.agentId)).get()
  389. if (not agentId) or (agentId == request.user.agentId) or (agentId == str(agent.primary_agent.id)):
  390. agentId = request.user.agentId
  391. response = gen_home_response(agentId)
  392. else:
  393. response = gen_login_response(agentId)
  394. return response
  395. def subAccountAccess(request):
  396. agentId = request.GET.get('agentId', '')
  397. if not is_login(request, ROLE.subaccount):
  398. response = gen_subaccount_login_response(agentId)
  399. else:
  400. agent = Agent.objects(id=str(request.user.agentId)).get()
  401. if (not agentId) or (agentId == request.user.agentId) or (agentId == str(agent.primary_agent.id)):
  402. agentId = request.user.agentId
  403. response = gen_home_response(agentId)
  404. else:
  405. response = gen_subaccount_login_response(agentId)
  406. return response
  407. def login(request):
  408. # type: (WSGIRequest)->JsonResponse
  409. username = request.POST.get('name', None)
  410. password = request.POST.get('password', None)
  411. agentId = request.POST.get('agentId')
  412. if not agentId:
  413. return JsonResponse({'result': 100, 'description': u'未选择对应的代理商,请刷新后在试', 'payload': {}})
  414. if not all([username, password]):
  415. response = JsonResponse({'result': 0, 'description': u'缺少用户名或密码', 'payload': {}})
  416. else:
  417. response = dealer_login(request, logger, username, password, agentId=agentId)
  418. if agentId != request.COOKIES.get('agentId', None):
  419. Agent.record_cookie(agentId, response)
  420. return response
  421. def subAccountLogin(request):
  422. username = request.POST.get('name', None)
  423. password = request.POST.get('password', None)
  424. agentId = request.POST.get('agentId')
  425. if not all([username, password]):
  426. response = JsonResponse({'result': 0, 'description': u'缺少用户名或密码', 'payload': {}})
  427. else:
  428. response = subAccount_login(request, logger, username, password, agentId=agentId)
  429. if agentId != request.COOKIES.get('agentId', None):
  430. Agent.record_cookie(agentId, response)
  431. response.set_cookie(key='sub_account_login_agentid', value=str(agentId), max_age=24 * 3600 * 30, domain = settings.COOKIE_DOMAIN)
  432. return response
  433. @permission_required(ROLE.dealer, ROLE.subaccount)
  434. def homepageData(request):
  435. # type: (WSGIRequest)->JsonResponse
  436. currentDealer = request.user # type: Optional[Dealer, SubAccount]
  437. dealer = request.user.myBoss # type: Dealer
  438. # 显示经销商的总余额(资金池+消费分润) 分两级显示
  439. deviceBalance = dealer.sub_balance(DEALER_INCOME_TYPE.DEVICE_INCOME)
  440. ledgerBalance = dealer.sub_balance(DEALER_INCOME_TYPE.LEDGER_CONSUME)
  441. payload = {
  442. 'totalBalance': deviceBalance + ledgerBalance,
  443. 'deviceBalance': deviceBalance,
  444. 'ledgerBalance': ledgerBalance
  445. }
  446. groupIds = Group.get_group_ids_of_dealer(str(dealer.id))
  447. partnerGroupIds = Group.get_group_ids_of_partner(str(dealer.id))
  448. groupIds.extend(partnerGroupIds)
  449. devList = Device.get_devices_by_group(groupIds).values()
  450. offlineCount, expireCount, allCount = 0, 0, 0
  451. for dev in devList: # type: DeviceDict
  452. allCount += 1
  453. if not dev.online:
  454. offlineCount += 1
  455. if dev.is_authorized_to_dealer(str(dealer.id)) and (dev.sim_expire_notify or dev.is_expired):
  456. expireCount += 1
  457. onlineCount = allCount - offlineCount
  458. payload.update({'onlineCount': onlineCount, 'offlineCount': offlineCount})
  459. payload['adShow'] = currentDealer.adShow
  460. payload['feedback'] = FeedBack.get_unhandled_count(ownerId=str(dealer.id))
  461. if expireCount > 0:
  462. payload['simCardTip'] = {
  463. 'expireCount': expireCount,
  464. 'todoMsg': TodoMessage.sim_expire_message(str(currentDealer.id), expireCount)
  465. }
  466. payload['pushBrokerUrl'] = currentDealer.pushBrokerUrl
  467. payload['isPurePartner'] = currentDealer.isPurePartner
  468. payload['inhouseApp'] = currentDealer.is_inhouse_wallet
  469. # 获取agent的相关信息
  470. resultResponse = JsonResponse({'result': 1, 'description': None, 'payload': payload})
  471. resultResponse = Agent.record_cookie(currentDealer.agentId, resultResponse)
  472. return resultResponse
  473. @error_tolerate(nil=JsonErrorResponse(u'上分失败,请重试'))
  474. @permission_required(ROLE.dealer, ROLE.subaccount)
  475. def onPoints(request):
  476. # type: (WSGIRequest)->JsonResponse
  477. """
  478. 远程上分, 支持经销商和代理商进行操作,代理商通过上分测试机器系统流程正确。
  479. :param request:
  480. :return:
  481. """
  482. TYPE_POINTS = ''
  483. TYPE_CHARGE_CARD = 'chargeCard'
  484. def __points__(dev, ruleId):
  485. smartBox = ActionDeviceBuilder.create_action_device(dev)
  486. if dev.support_reliable:
  487. orderNo = dev.ownerId[-10:]+ConsumeRecord.make_no()
  488. order = ConsumeRecord(orderNo=orderNo, openId=dev.ownerId)
  489. order.package = dev.get('washConfig',{}).get(ruleId)
  490. order.attachParas = attachParas
  491. smartBox.start_device_realiable(order)
  492. lineInfo = {'port':attachParas.get('chargeIndex'), 'status':Const.DEV_WORK_STATUS_WORKING}
  493. Device.update_port_control_cache(dev.devNo, lineInfo)
  494. else:
  495. smartBox.start(ruleId, openId = None, attachParas = attachParas)
  496. address = Group.get_group(dev['groupId'])['address']
  497. groupName = Group.get_group(dev['groupId'])['groupName']
  498. score = dev.get('washConfig', {}).get(ruleId, {}).get('coins', 0)
  499. UpscoreRecord(
  500. logicalCode=dev['logicalCode'],
  501. devNo=devNo,
  502. ownerId=ownerId,
  503. time=datetime.datetime.now(),
  504. score=score,
  505. address=address,
  506. groupName=groupName,
  507. devType=dev['devType']['name'],
  508. type=TYPE_POINTS
  509. ).save()
  510. def __charge_card(dev, price):
  511. smartBox = ActionDeviceBuilder.create_action_device(dev)
  512. smartBox.remote_charge_card(price)
  513. address = Group.get_group(dev['groupId'])['address']
  514. groupName = Group.get_group(dev['groupId'])['groupName']
  515. UpscoreRecord(
  516. logicalCode=dev['logicalCode'],
  517. devNo=devNo,
  518. ownerId=ownerId,
  519. time=datetime.datetime.now(),
  520. score=price,
  521. address=address,
  522. groupName=groupName,
  523. devType=dev['devType']['name'],
  524. type=TYPE_CHARGE_CARD
  525. ).save()
  526. def __huopo_points(dev):
  527. ruleId = "1"
  528. smartBox = ActionDeviceBuilder.create_action_device(dev)
  529. smartBox.start(ruleId, openId = None, attachParas = attachParas)
  530. address = Group.get_group(dev['groupId'])['address']
  531. groupName = Group.get_group(dev['groupId'])['groupName']
  532. score = 0
  533. UpscoreRecord(
  534. logicalCode=dev['logicalCode'],
  535. devNo=devNo,
  536. ownerId=ownerId,
  537. time=datetime.datetime.now(),
  538. score=score,
  539. address=address,
  540. groupName=groupName,
  541. devType=dev['devType']['name'],
  542. type=TYPE_POINTS
  543. ).save()
  544. def __policy_points__(dev, ruleId):
  545. smartBox = ActionDeviceBuilder.create_action_device(dev)
  546. if dev.support_reliable:
  547. orderNo = dev.ownerId[-10:]+ConsumeRecord.make_no()
  548. order = ConsumeRecord(orderNo=orderNo, openId=dev.ownerId)
  549. order.package = smartBox.prepare_package(ruleId, attachParas)
  550. order.attachParas = attachParas
  551. smartBox.start_device_realiable(order)
  552. lineInfo = {
  553. 'port': attachParas.get('chargeIndex'),
  554. 'status': Const.DEV_WORK_STATUS_WORKING,
  555. 'nickName': '经销商远程上分',
  556. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  557. }
  558. data = smartBox._check_package(order.package)
  559. if 'needTime' in data:
  560. lineInfo.update({'needTime': data['needTime']})
  561. if 'needElec' in data:
  562. lineInfo.update({'needElec': data['needElec']})
  563. Device.update_port_control_cache(dev.devNo, lineInfo)
  564. address = Group.get_group(dev['groupId'])['address']
  565. groupName = Group.get_group(dev['groupId'])['groupName']
  566. UpscoreRecord(
  567. logicalCode=dev['logicalCode'],
  568. devNo=devNo,
  569. ownerId=ownerId,
  570. time=datetime.datetime.now(),
  571. package=order.package,
  572. address=address,
  573. groupName=groupName,
  574. devType=dev['devType']['name'],
  575. type=TYPE_POINTS
  576. ).save()
  577. try:
  578. ownerId = str(request.user.bossId)
  579. logicalCode = request.POST.get('logicalCode', None)
  580. attachParas = json.loads(request.POST.get('attachParas', '{}'))
  581. attachParas['onPoints'] = True
  582. type = request.POST.get('type', '')
  583. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  584. dev = Device.get_dev(devNo)
  585. if not dev:
  586. return JsonResponse({'result': 2, 'description': u'设备不存在'})
  587. if dev['ownerId'] != ownerId:
  588. return JsonResponse({'result': 2, 'description': u'不是你家设备,不能操作喔'})
  589. dealer = dev.owner
  590. agent = Agent.objects.filter(id=str(dealer.agentId)).first() # type: Agent
  591. if 'disable_dealer_onPoints_and_sendCoins' in agent.features:
  592. return JsonResponse(
  593. {'result': 0, 'description': '设备无法使用该功能奥, 如有问题, 请联系代理商', 'payload': {}})
  594. # 霍珀的道闸适配
  595. if dev["devType"]["code"] == Const.DEVICE_TYPE_CODE_HP_GATE:
  596. __huopo_points(dev)
  597. return JsonResponse({'result': 1, 'description': u'success'})
  598. if dev["devType"]["code"] in support_policy_device:
  599. ruleId = request.POST.get('ruleId', None)
  600. __policy_points__(dev, ruleId)
  601. return JsonResponse({'result': 1, 'description': u'success'})
  602. if type == TYPE_POINTS:
  603. ruleId = request.POST.get('ruleId', None)
  604. # 如果是串口设备,上分的话,直接使用套餐。这里把串口和非串口的上分统一起来,行为应该有创建者创建具备行为的实例
  605. if not ruleId:
  606. return JsonResponse(
  607. {'result': 0, 'description': u'没有找到对应的套餐信息,请您重新选择其他分值.或者检查设备是否没有注册到系统', 'payload': {}})
  608. __points__(dev, ruleId)
  609. elif type == TYPE_CHARGE_CARD:
  610. price = int(request.POST.get('coins', 0))
  611. if price <= 0:
  612. return JsonResponse({'result': 0, 'description': u'充值金额错,请重新输入', 'payload': {}})
  613. __charge_card(dev, price)
  614. return JsonResponse({'result': 1, 'description': u'success'})
  615. except ServiceException, e:
  616. logger.exception(e)
  617. return JsonResponse(e.result)
  618. @permission_required(ROLE.dealer, ROLE.subaccount)
  619. def onPointsRecords(request):
  620. # type: (WSGIRequest)->JsonResponse
  621. """
  622. 上分记录查询
  623. :param request:
  624. :return:
  625. """
  626. ownerId = str(request.user.bossId)
  627. pageIndex = int(request.GET.get('pageIndex', 1))
  628. pageSize = int(request.GET.get('pageSize', 10))
  629. objs = UpscoreRecord.objects.filter(ownerId=ownerId).order_by('-time')
  630. rcdList = []
  631. total = 0
  632. sumCoins = 0
  633. sumCoinsTotal = 0
  634. sumCharge = 0
  635. sumChargeTotal = 0
  636. for obj in objs:
  637. if obj.type == 'chargeCard':
  638. sumCharge += obj.score
  639. sumChargeTotal += 1
  640. else:
  641. sumCoins += obj.score
  642. sumCoinsTotal += 1
  643. total += 1
  644. rcdList.append({
  645. 'logicalCode': obj.logicalCode,
  646. 'devNo': obj.devNo,
  647. 'createdStr': obj.time.strftime('%Y-%m-%d %H:%M:%S'),
  648. 'coins': obj.score,
  649. 'et_type_name': obj.devType,
  650. 'address': obj.address,
  651. 'groupName': obj.groupName,
  652. 'type': obj.type})
  653. return JsonResponse({
  654. "result": 1,
  655. "description": None,
  656. "payload": {
  657. "sumCoins": sumCoins,
  658. 'sumCoinsTotal': sumCoinsTotal,
  659. 'sumCharge': sumCharge,
  660. 'sumChargeTotal': sumChargeTotal,
  661. "rcds": {
  662. "total": total,
  663. "items": rcdList[(pageIndex - 1) * pageSize:pageIndex * pageSize],
  664. }
  665. }
  666. })
  667. @permission_required(ROLE.dealer, ROLE.subaccount)
  668. def handlerKeepingOrder(request):
  669. """
  670. 关闭订单取消订单
  671. 霍珀道闸 由于出现后付费的情况,可能存在两种情况需要将订单取消 用户扫码进门,创建了订单但是门没开 用户扫码出门,钱已经扣了但门没开
  672. 此接口 供经销商对于此类订单的处理
  673. """
  674. TYPE_CANCEL = "cancel"
  675. TYPE_CLOSE = "close"
  676. _id = request.GET.get("id")
  677. _type = request.GET.get("type")
  678. # 取消订单
  679. sp = ServiceProgress.objects.get(id=_id)
  680. sp.isFinished = True
  681. sp.finished_time = int(time.time())
  682. order = ConsumeRecord.objects.get(id=sp.consumes[0])
  683. if _type == TYPE_CLOSE:
  684. order.isNormal = True
  685. order.finishedTime = datetime.datetime.now()
  686. order.remarks = u"经销商 %s 关闭订单" % request.user.nickname
  687. serviceInfo = {
  688. "finishedTime": str(order.finishedTime)[:19],
  689. }
  690. order.serviceInfo = serviceInfo
  691. elif _type == TYPE_CANCEL:
  692. order.finishedTime = datetime.datetime.now()
  693. order.remarks = u"经销商 %s 取消订单" % request.user.nickname
  694. order.isNormal = False
  695. try:
  696. sp.save()
  697. order.save()
  698. except Exception as e:
  699. logger.exception(e)
  700. return JsonResponse({'result': 0, 'description': u'数据查询出错', 'payload': {}})
  701. else:
  702. # 清除该停车数量 无论是终止订单还是取消订单,其进车数量始终 需要 -1
  703. key = "maxParking"
  704. if order.attachParas.get("vCardId"):
  705. key = "VIPMaxParking"
  706. serviceInfo = HuopoCacheMgr.get_parking_cache(order.groupId)
  707. if serviceInfo is not None:
  708. parkingInfo = serviceInfo.get("parkingInfo", {})
  709. parkingNum = parkingInfo.get(key, 0)
  710. else:
  711. parkingInfo = {}
  712. parkingNum = 0
  713. if parkingNum > 0:
  714. parkingNum -= 1
  715. parkingInfo.update({key: parkingNum})
  716. HuopoCacheMgr.set_parking_cache(order.groupId, {"parkingInfo": parkingInfo})
  717. return JsonResponse({'result': 1, 'description': u'success'})
  718. @permission_required(ROLE.dealer, ROLE.subaccount)
  719. def getKeepingOrder(request):
  720. """
  721. 获取正在进行的订单
  722. """
  723. pageIndex = int(request.GET.get("pageIndex", 1))
  724. pageSize = int(request.GET.get("pageSize", 10))
  725. ownerId = str(request.user.bossId)
  726. logicalCode = request.GET.get('logicalCode', None)
  727. attachParas = json.loads(request.POST.get('attachParas', '{}'))
  728. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  729. dev = Device.get_dev(devNo)
  730. if not dev:
  731. return JsonResponse({'result': 0, 'description': u'设备不存在'})
  732. if dev['ownerId'] != ownerId:
  733. return JsonResponse({'result': 0, 'description': u'不是你家设备,不能操作喔'})
  734. sps = ServiceProgress.objects.filter(device_imei=devNo, devTypeCode=dev["devType"]["code"], isFinished=False).all()
  735. dataList = list()
  736. for sp in sps:
  737. user = MyUser.objects.filter(openId=sp.open_id).first()
  738. order = ConsumeRecord.objects.get(id=sp.consumes[0])
  739. tempData = {
  740. "id": sp.id,
  741. "nickname": user.nickname,
  742. "avatar": user.avatar,
  743. "startTime": order.time
  744. }
  745. dataList.append(tempData)
  746. return JsonResponse(
  747. {'result': 1,
  748. 'description': u'',
  749. 'payload':
  750. {
  751. "total": len(dataList),
  752. "dataList": dataList[(pageIndex-1)*pageSize: pageIndex*pageSize]
  753. }
  754. })
  755. # 获取默认地址
  756. @permission_required(ROLE.dealer, ROLE.subaccount)
  757. def groupInfo(request):
  758. # 获取默认地址
  759. def groupInfoDefault(request):
  760. # type: (WSGIRequest)->JsonResponse
  761. groupId = request.GET.get('groupId', None)
  762. ownerId = str(request.user.bossId)
  763. group = Group.get_group(groupId)
  764. if group is None:
  765. return JsonResponse({"result": 0, "description": u"没有找到地址信息", "payload": {}})
  766. if group['ownerId'] == ownerId:
  767. group['isManager'] = True
  768. else:
  769. group['isManager'] = False
  770. groupOwner = Dealer.get_dealer(group['ownerId'])
  771. group['managerName'] = groupOwner['nickname'] + " " + groupOwner['username']
  772. group['partner'] = group['partnerDict'].values()
  773. for partner in group['partner']:
  774. if partner['id'] == ownerId:
  775. partner['self'] = True
  776. else:
  777. reload_parter = Dealer.get_dealer(partner['id'])
  778. partner['tel'] = reload_parter['username']
  779. partner['name'] = reload_parter['nickname']
  780. partner['self'] = False
  781. # 添加 合伙人商户的状态给前台显示 如果合伙人商户的状态是 初始状态 需要为合伙人绑定银行卡
  782. partner = Dealer.objects.get(id=partner["id"])
  783. district = District.get_district(group['districtId'])
  784. group['district'] = district
  785. if not group['isManager']:
  786. for i in range(len(group['partner'])-1,-1,-1):
  787. if not group['partner'][i]['self']:
  788. del group['partner'][i]
  789. return JsonResponse({"result": 1, "description": None, "payload": group})
  790. current_user = request.user # type: UserSearchable
  791. return groupInfoDefault(request)
  792. @permission_required(ROLE.dealer, ROLE.subaccount)
  793. def groupIncomeData(request):
  794. # type: (WSGIRequest)->JsonResponse
  795. """
  796. 查询地址组的收益
  797. 地址组收益的记录方式已经发生了改变 对于收益的部分 记录在 daily.incomeMap下面的数据,每个经销商一条,为总的收益,没有明细划分
  798. :param request:
  799. :return:
  800. """
  801. def get_group_info(g, _id):
  802. isM = _id == g.get("ownerId")
  803. if not isM:
  804. p = round_2_digits(float(g.get("partnerDict", dict()).get(_id, dict()).get("percent", 0)))
  805. else:
  806. fullPercent = 100
  807. for _partner in g.get("partnerDict", dict()).values():
  808. fullPercent -= float(_partner.get("percent", 0))
  809. p = round_2_digits(float(fullPercent))
  810. return isM, p
  811. current_user = request.user # type: Dealer
  812. dealerId = str(current_user.bossId)
  813. pageIndex = int(request.GET.get("pageIndex", 1))
  814. pageSize = int(request.GET.get("pageSize", 10))
  815. startDate = request.GET.get("startTime")
  816. endDate = request.GET.get("endTime")
  817. startDate, endDate = current_user.limit_filter_date(startDate, endDate)
  818. if endDate < startDate:
  819. return JsonResponse({
  820. 'result': 1, 'description': '', 'payload': {
  821. "total": 0,
  822. "dataList": [],
  823. "adShow": current_user.adShow
  824. }})
  825. else:
  826. searchKey = request.GET.get("searchKey", None)
  827. # 通过searchKey 获取组地址 作为查询的筛选条件
  828. # TODO 这个地方有一个问题在于 如果 地址组的合伙人一旦修改 之前的合伙人无法看到历史的数据 而新的合伙人能看到之前的数据
  829. groupIds = Group.search_group_ids_of_dealer(
  830. dealerId, searchKey
  831. ) + Group.search_group_ids_of_partner(
  832. dealerId, searchKey
  833. )
  834. groupIdSlice = groupIds[(pageIndex - 1) * pageSize: pageSize * pageIndex]
  835. if not groupIdSlice:
  836. return JsonResponse({
  837. 'result': 1, 'description': '', 'payload': {
  838. "total": len(groupIds),
  839. "dataList": [],
  840. "adShow": current_user.adShow
  841. }})
  842. groupStatisticMap = GroupDailyStatsModelProxy.get_groups_income_statistic(groupIds=groupIdSlice, startDate=startDate, endDate=endDate, dealerId=dealerId)
  843. groupDevCountMap = Device.get_device_count_by_group(groupIdSlice)
  844. rptDict = GroupReport.get_rpt(groupIdSlice, startDate, endDate) # 投币的信息
  845. # 经销商的特性判断 的相关信息的获取
  846. dealer = Dealer.objects.get(id=dealerId)
  847. showOfflineCoin = True if 'show_offline_coins' in dealer.features else False
  848. # 整合数据
  849. dataList = list()
  850. for _groupId in groupIdSlice:
  851. # 统计信息的过滤
  852. groupStatistic = groupStatisticMap.get(_groupId, {})
  853. # 要提前将这个不存在的统计值pop出来
  854. dealerActualIncome = RMB(groupStatistic.pop("dealerActualIncome", 0))
  855. incomeList = translate_income(groupStatistic)
  856. totalIncome = sum_rmb(_['value'] for _ in incomeList)
  857. # 组信息 以及分成比例的计算
  858. group = Group.get_group(_groupId) or dict()
  859. isManager, percent = get_group_info(group, dealerId)
  860. value = {
  861. "groupName": group.get("groupName", ""),
  862. "groupId": _groupId,
  863. "address": group.get("address", ""),
  864. "equipmentCount": groupDevCountMap.get(_groupId, 0),
  865. "isManager": isManager,
  866. "percent": percent,
  867. "agentProfitShare": request.user.agentProfitShare,
  868. "offlineCoins": rptDict.get(_groupId, dict()).get('lineCoins', 0),
  869. "incomeList": incomeList,
  870. "totalIncome": totalIncome,
  871. "dealerActualIncome": dealerActualIncome
  872. }
  873. if not showOfflineCoin:
  874. value.pop('offlineCoins', None)
  875. dataList.append(value)
  876. # 对 totalIncome 排序 优先返回金额最多的地址组
  877. dataList = sorted(dataList, key=lambda x: float(x["totalIncome"]), reverse=True)
  878. total = len(groupIds)
  879. return JsonResponse({"result": 1, "description": None, "payload": {
  880. "total": total,
  881. "dataList": dataList,
  882. "adShow": current_user.adShow
  883. }})
  884. @permission_required(ROLE.dealer, ROLE.subaccount)
  885. def getDevOffLineCoinStatByGroupId(request):
  886. # type: (WSGIRequest)->JsonResponse
  887. groupId = request.GET.get('groupId')
  888. group = Group.get_group(groupId)
  889. if not group:
  890. return JsonErrorResponse(u'找不到组ID')
  891. pageIndex = int(request.GET.get('pageIndex', 1))
  892. pageSize = int(request.GET.get('pageSize', 10))
  893. startDate = defaultTodayDate(request.GET.get('startTime'))
  894. endDate = defaultTodayDate(request.GET.get('endTime'))
  895. total = Device.get_collection().find({'groupId': groupId}).count()
  896. devNoList = Device.get_devNos_by_group([groupId])
  897. devInfo = Device.get_dev_by_nos(devNoList)
  898. dataList = [
  899. {
  900. 'logicalCode': devInfo[devNo]['logicalCode'],
  901. 'groupNumber': devInfo[devNo]['groupNumber'],
  902. 'devTypeName': devInfo[devNo].get('devType', {}).get('name', ''),
  903. 'offlineCoins': rpt['lineCoins'],
  904. }
  905. for devNo, rpt in DevReport.get_rpt(devNoList, startDate, endDate).iteritems()
  906. ]
  907. return JsonResponse(
  908. {
  909. 'result': 1,
  910. 'description': '',
  911. 'payload':
  912. {
  913. 'total': total,
  914. 'groupName': group['groupName'],
  915. 'dataList': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  916. }
  917. }
  918. )
  919. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  920. @permission_required(ROLE.dealer, ROLE.subaccount)
  921. def groupIncomeByGroupId(request):
  922. # type: (WSGIRequest)->JsonResponse
  923. """
  924. 获取 单一地址组的 收益 聚合信息
  925. :param request:
  926. :return:
  927. """
  928. dealerId = str(request.user.bossId)
  929. groupId = request.GET.get("groupId")
  930. startDate = request.GET.get("startTime")
  931. endDate = request.GET.get("endTime")
  932. if not groupId:
  933. return JsonErrorResponse(description=u'未提供地址ID')
  934. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  935. return JsonErrorResponse(description=u'无权限查看')
  936. group = Group.get_group(groupId)
  937. if not group:
  938. return JsonErrorResponse(description=u'组不存在')
  939. groupStatistic = GroupDailyStatsModelProxy.get_one_group_income_statistic(groupId, startDate, endDate)
  940. incomeTotalList = [{"name": u"总收益", "value": RMB(groupStatistic.get("totalIncome", 0))}]
  941. for _item in translate_income(groupStatistic):
  942. if _item.get("value", RMB(0)) > RMB(0):
  943. incomeTotalList.append(_item)
  944. return JsonResponse(
  945. {
  946. 'result': 1,
  947. 'description': 'ok',
  948. 'payload': {
  949. 'groupName': group['groupName'],
  950. "incomeTotalList": incomeTotalList
  951. }
  952. }
  953. )
  954. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  955. @permission_required(ROLE.dealer, ROLE.subaccount)
  956. def groupConsumptionByGroupId(request):
  957. # type: (WSGIRequest)->JsonResponse
  958. """
  959. 获取 单一地址组的 收益 聚合信息
  960. :param request:
  961. :return:
  962. """
  963. dealerId = str(request.user.bossId)
  964. groupId = request.GET.get("groupId")
  965. startDate = request.GET.get("startTime")
  966. endDate = request.GET.get("endTime")
  967. if not groupId:
  968. return JsonErrorResponse(description=u'未提供地址ID')
  969. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  970. return JsonErrorResponse(description=u'无权限查看')
  971. group = Group.get_group(groupId)
  972. if not group:
  973. return JsonErrorResponse(description=u'组不存在')
  974. groupStatistic = GroupDailyStatsModelProxy.get_one_group_consumption_statistic(groupId, startDate, endDate)
  975. agent = Agent.objects.get(id=request.user.agentId) # type: Agent
  976. consumptionTotalList = list()
  977. for _item in translate_consumption(groupStatistic, agent.hide_consume_kinds_dealer):
  978. if _item.get("value", Quantity(0)) > Quantity(0):
  979. consumptionTotalList.append(_item)
  980. return JsonResponse(
  981. {
  982. 'result': 1,
  983. 'description': 'ok',
  984. 'payload': {
  985. 'groupName': group['groupName'],
  986. "incomeTotalList": consumptionTotalList
  987. }
  988. }
  989. )
  990. EXTRA_INCOME_DEVICE_TYPE_CODES = [Const.DEVICE_TYPE_CODE_WASHCAR_LSHB]
  991. def realtime_income_available(typeCode):
  992. # type:(str)->bool
  993. return typeCode in EXTRA_INCOME_DEVICE_TYPE_CODES
  994. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  995. @permission_required(ROLE.dealer, ROLE.subaccount)
  996. def getRealtimeIncomeByDev(request):
  997. # type: (WSGIRequest)->JsonResponse
  998. # TODO 建立一个缓存的permission map 来将经销商ID与设备等相关权限对应起来
  999. logicalCode = request.GET.get('logicalCode')
  1000. device = Device.get_dev_by_logicalCode(logicalCode)
  1001. if not device:
  1002. return JsonErrorResponse(description=u'设备不存在')
  1003. typeCode = device['devType']['code']
  1004. if realtime_income_available(typeCode):
  1005. return JsonErrorResponse(description=u'不支持当前设备查询实时收入')
  1006. translation = {
  1007. 'cardFee': u'刷卡总额',
  1008. 'coinFee': u'投币总额',
  1009. 'mobileFee': u'支付总额'
  1010. }
  1011. if typeCode == Const.DEVICE_TYPE_CODE_CHARGING_SIJIANG:
  1012. try:
  1013. smartBox = ActionDeviceBuilder.create_action_device(device)
  1014. conf = smartBox.get_dev_consume_count()
  1015. return JsonResponse(
  1016. {
  1017. 'result': 1,
  1018. 'description': '',
  1019. 'payload':
  1020. {
  1021. 'realTimeIncome': [
  1022. {'name': translation[k], 'value': v} for k, v in conf.iteritems() if k in translation
  1023. ]
  1024. }
  1025. })
  1026. except ServiceException as e:
  1027. logger.debug('cannot get_extra_income_by_specific_devices device=%s' % (device,))
  1028. logger.exception(e)
  1029. return JsonErrorResponse(description=u'网络不畅通,请稍后再试')
  1030. elif typeCode == Const.DEVICE_TYPE_CODE_WASHCAR_LSHB:
  1031. try:
  1032. # 获取设备上的卡的总收入、投币的总收入
  1033. smartBox = ActionDeviceBuilder.create_action_device(device)
  1034. mapping = {
  1035. 'cardFee': smartBox.get_card_count(),
  1036. 'coinFee': smartBox.get_coins_count()
  1037. }
  1038. return JsonResponse(
  1039. {
  1040. 'result': 1,
  1041. 'description': '',
  1042. 'payload': {
  1043. 'realTimeIncome': [{'name': translation[k], 'value': v} for k, v in mapping.iteritems() if
  1044. k in translation]
  1045. }
  1046. })
  1047. except ServiceException as e:
  1048. logger.debug('cannot get_extra_income_by_specific_devices device=%s' % (device,))
  1049. logger.exception(e)
  1050. return JsonErrorResponse(description=u'网络不畅通,请稍后再试')
  1051. else:
  1052. return JsonErrorResponse(description=u'不支持当前设备查询实时收入')
  1053. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  1054. @permission_required(ROLE.dealer, ROLE.subaccount)
  1055. def groupEquipmentIncomeByGroupId(request):
  1056. # type: (WSGIRequest)->JsonResponse
  1057. """
  1058. 获取组下设备按日期收益聚合数据
  1059. :param request:
  1060. :return:
  1061. """
  1062. # TODO Nicolas 此接口以及 groupEquipmentConsumptionByGroupId 存在问题
  1063. # TODO Nicolas 当该地址下设备信息发生变更的时候 ,通过 GroupDaily 获取的信息 和通过 DeviceDaily 聚合获取的信息会不一致
  1064. dealerId = str(request.user.bossId)
  1065. groupId = request.GET.get("groupId", None)
  1066. pageIndex = int(request.GET.get('pageIndex', 1))
  1067. pageSize = int(request.GET.get('pageSize', 10))
  1068. startDate = request.GET.get('startTime')
  1069. endDate = request.GET.get('endTime')
  1070. if groupId is None:
  1071. return JsonErrorResponse(description=u'未找到地址组,请重试')
  1072. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  1073. return JsonErrorResponse(description=u'无权限查看')
  1074. group = Group.get_group(groupId)
  1075. if not group:
  1076. return JsonErrorResponse(description=u'组不存在')
  1077. # 获取设备的日统计信息
  1078. logicalCodes = Device.get_logicalCode_by_groupId(groupId)
  1079. logicalCodeSlice = sorted(logicalCodes[(pageIndex - 1) * pageSize: pageIndex * pageSize])
  1080. statisticMap = DeviceDailyStatsModelProxy.get_devices_income_statistic(logicalCodeSlice, startDate, endDate)
  1081. dataList = list()
  1082. for logicalCode in logicalCodeSlice:
  1083. devStatistic = translate_income(statisticMap.get(logicalCode, dict()))
  1084. devStatistic = [_statistic for _statistic in devStatistic if _statistic["value"] > RMB(0)]
  1085. dev = Device.get_dev_by_l(logicalCode)
  1086. dataList.append({
  1087. "incomeList": devStatistic,
  1088. "logicalCode": logicalCode,
  1089. "groupId": groupId,
  1090. "type": dev.get("devType", dict()).get("name"),
  1091. 'groupNumber': dev.get('groupNumber'),
  1092. 'realtimeIncomeAvailable': realtime_income_available(dev.get('devType', dict()).get('code'))
  1093. })
  1094. return JsonResponse(
  1095. {
  1096. 'result': 1,
  1097. 'description': None,
  1098. 'payload': {
  1099. 'total': len(logicalCodes),
  1100. 'dataList': dataList
  1101. }
  1102. }
  1103. )
  1104. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  1105. @permission_required(ROLE.dealer, ROLE.subaccount)
  1106. def groupEquipmentConsumptionByGroupId(request):
  1107. # type: (WSGIRequest)->JsonResponse
  1108. """
  1109. 获取组下设备按日期消费聚合数据
  1110. :param request:
  1111. :return:
  1112. """
  1113. dealerId = str(request.user.bossId)
  1114. groupId = request.GET.get("groupId", None)
  1115. pageIndex = int(request.GET.get('pageIndex', 1))
  1116. pageSize = int(request.GET.get('pageSize', 10))
  1117. startDate = request.GET.get('startTime')
  1118. endDate = request.GET.get('endTime')
  1119. if groupId is None:
  1120. return JsonErrorResponse(description=u'未找到地址组,请重试')
  1121. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  1122. return JsonErrorResponse(description=u'无权限查看')
  1123. group = Group.get_group(groupId)
  1124. if not group:
  1125. return JsonErrorResponse(description=u'组不存在')
  1126. # 获取设备的日统计信息
  1127. logicalCodes = Device.get_logicalCode_by_groupId(groupId)
  1128. logicalCodeSlice = sorted(logicalCodes[(pageIndex-1)*pageSize: pageIndex*pageSize])
  1129. statisticMap = DeviceDailyStatsModelProxy.get_devices_consumption_statistic(logicalCodeSlice, startDate, endDate)
  1130. agent = Agent.objects.get(id = request.user.agentId) # type: Agent
  1131. dataList = list()
  1132. for logicalCode in logicalCodeSlice:
  1133. devStatistic = translate_consumption(statisticMap.get(logicalCode, dict()), hides = agent.hide_consume_kinds_dealer)
  1134. devStatistic = [_statistic for _statistic in devStatistic if _statistic["value"] > Quantity(0)]
  1135. dev = Device.get_dev_by_l(logicalCode)
  1136. dataList.append({
  1137. "consumptionList": devStatistic,
  1138. "logicalCode": logicalCode,
  1139. "groupId": groupId,
  1140. "type": dev.get("devType", dict()).get("name"),
  1141. 'groupNumber': dev.get('groupNumber'),
  1142. })
  1143. return JsonResponse(
  1144. {
  1145. 'result': 1,
  1146. 'description': "",
  1147. 'payload': {
  1148. 'total': len(logicalCodes),
  1149. 'dataList': dataList
  1150. }
  1151. }
  1152. )
  1153. def get_income_by_cat(stat, date_range, field):
  1154. return RMB(stat.get(date_range, {}).get('income', {}).get(field, 0))
  1155. def get_daily_income_by_cat(stat, field):
  1156. return get_income_by_cat(stat, 'daily', field)
  1157. def get_monthly_income_by_cat(stat, field):
  1158. return get_income_by_cat(stat, 'monthly', field)
  1159. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1160. def lastMonthIncome(request):
  1161. """
  1162. 按月统计 经销商的月收益
  1163. 获取的数据是当月的收益数据累加的 以及 每天的收益累计总和
  1164. :param request:
  1165. :return:
  1166. """
  1167. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1168. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y-%m"))
  1169. startDate, endDate = get_start_and_end_by_month(monthStr = timeStr)
  1170. rpts = {r['date']: r for r in DealerReport.get_rpts(dealerId, startDate, endDate)}
  1171. # 获取每一天的数据 首先要对时间参数进行鉴别 如果是本月的话,那么最后一天就是今天
  1172. dataList = list()
  1173. totalIncome, payIncome, offlineCoins = RMB(0), RMB(0), VirtualCoin(0)
  1174. rv = DealerDailyStatsModelProxy.get_days_income_stat(dealerId, timeStr)
  1175. for day, stat in rv.iteritems():
  1176. day_offline_count = VirtualCoin(rpts.get(day, {}).get('lineCoins', 0))
  1177. offlineCoins += day_offline_count
  1178. day_pay_income = RMB(get_in(["income", format(DEALER_INCOME_SOURCE.RECHARGE)], stat, default = 0)) + \
  1179. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.REDPACK)], stat, default = 0)) + \
  1180. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.RECHARGE_CARD)], stat, default = 0)) + \
  1181. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.RECHARGE_VIRTUAL_CARD)], stat, default = 0)) + \
  1182. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.REFUND_CASH)], stat, default = 0))
  1183. payIncome += day_pay_income
  1184. day_total_income = RMB(get_in(["totalIncome"], stat, default = 0))
  1185. totalIncome += day_total_income
  1186. dataList.append({
  1187. 'dateStr': day,
  1188. 'dateText': u'%s年%s月%s日' % tuple(day.split('-')),
  1189. 'payIncome': day_pay_income,
  1190. 'offlineCoins': day_offline_count,
  1191. 'totalIncome': day_total_income
  1192. })
  1193. if dealerId == '5d132407003048494763a51b':
  1194. if int(timeStr[0:4]) < 2021:
  1195. dataList = []
  1196. offlineCoins = 0
  1197. payIncome = 0
  1198. totalIncome = 0
  1199. else:
  1200. pass
  1201. return JsonOkResponse(payload=
  1202. {
  1203. "adShow": request.user.adShow,
  1204. "totalIncome": totalIncome,
  1205. "payIncome": payIncome,
  1206. "offlineCoins": offlineCoins,
  1207. "dataList": dataList
  1208. })
  1209. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1210. def lastYearIncome(request):
  1211. # type: (WSGIRequest)->JsonResponse
  1212. """
  1213. 按年统计经销商的收益
  1214. :param request:
  1215. :return:
  1216. """
  1217. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1218. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y"))
  1219. timeStr = Dealer.limit_filter_year(dealerId, timeStr[0:4])
  1220. if not timeStr:
  1221. return JsonOkResponse(payload = {'adShow': request.user.adShow, 'dataList': []})
  1222. else:
  1223. startDay, endDay = get_start_and_end_by_year(timeStr)
  1224. monthRange = [datetime.datetime.strftime(item, "%Y-%m") for item in get_date_range(startDay, endDay, "MS")]
  1225. offline_report = DealerReportModelProxy.get_year_by_month(dealerId = dealerId, yearStr = timeStr)
  1226. # 获取一年里面 按月聚合分组的数据
  1227. statisticMap = DealerDailyStatsModelProxy.get_one_year_income_as_month(dealerId = dealerId, yearStr = timeStr)
  1228. dataList = list()
  1229. for month in monthRange:
  1230. monthIncomeMap = statisticMap.get(month, dict())
  1231. tempMonthStatistics = {
  1232. "totalIncome": RMB(monthIncomeMap.get("totalIncome", 0)),
  1233. "offlineCoins": VirtualCoin(
  1234. offline_report.get('%d-%02d' % tuple(map(int, month.split('-'))), {}).get('lineCoins', 0)),
  1235. "dateStr": month,
  1236. "dateText": u"{}年{}月".format(*month.split("-")),
  1237. "payIncome": sum([_v for _k, _v in monthIncomeMap.items() if
  1238. _k in [DEALER_INCOME_SOURCE.RECHARGE_VIRTUAL_CARD,
  1239. DEALER_INCOME_SOURCE.RECHARGE_CARD,
  1240. DEALER_INCOME_SOURCE.RECHARGE,
  1241. DEALER_INCOME_SOURCE.REFUND_CASH,
  1242. DEALER_INCOME_SOURCE.REDPACK]], RMB(0))
  1243. }
  1244. dataList.append(tempMonthStatistics)
  1245. return JsonOkResponse(payload = {'adShow': request.user.adShow, 'dataList': dataList})
  1246. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1247. def lastMonthConsumption(request):
  1248. # type: (WSGIRequest)->JsonResponse
  1249. """
  1250. 按月统计 经销商的消耗信息
  1251. :param request:
  1252. :return:
  1253. """
  1254. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1255. dealer = Dealer.objects.get(id=dealerId)
  1256. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y-%m"))
  1257. _year = Dealer.limit_filter_year(dealerId, timeStr[0:4])
  1258. if not _year:
  1259. return JsonOkResponse(payload = {'dataList': []})
  1260. else:
  1261. agent = Agent.objects.get(id = request.user.agentId)
  1262. dataList = list()
  1263. rv = DealerDailyStatsModelProxy.get_days_consume_stat(dealerId, timeStr)
  1264. for _day, stat in rv.iteritems():
  1265. consumptionList = translate_consumption(get_in(["consumption"], stat, dict()),
  1266. hides = agent.hide_consume_kinds_dealer)
  1267. if "not_show_about_elec" in dealer.features:
  1268. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"消耗电量"]
  1269. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"电费成本"]
  1270. dataList.append({
  1271. "dateStr": _day,
  1272. "dateText": u"{}年{}月{}日".format(*_day.split("-")),
  1273. "consumptionList": consumptionList
  1274. })
  1275. return JsonOkResponse(payload = {'dataList': dataList})
  1276. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1277. def lastYearConsumption(request):
  1278. # type: (WSGIRequest)->JsonResponse
  1279. """
  1280. 一年的消费概览
  1281. :param request:
  1282. :return:
  1283. """
  1284. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1285. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y"))
  1286. timeStr = Dealer.limit_filter_year(dealerId, timeStr)
  1287. if not timeStr:
  1288. return JsonOkResponse(payload = {'dataList': []})
  1289. else:
  1290. # 获取统计的时间范围 获取月份的区间
  1291. startDay, endDay = get_start_and_end_by_year(timeStr)
  1292. monthRange = [datetime.datetime.strftime(item, "%Y-%m") for item in get_date_range(startDay, endDay, "MS")]
  1293. # 获取一年里面 按月聚合分组的消费数据
  1294. statisticMap = DealerDailyStatsModelProxy.get_one_year_consume_as_month(dealerId = dealerId, yearStr = timeStr)
  1295. # 消费信息 某些字段和特性相关联 先取出代理商的特性 留作判断
  1296. agent = Agent.objects.get(id = request.user.agentId)
  1297. dataList = list()
  1298. for _month in monthRange:
  1299. _item = statisticMap.get(_month, dict())
  1300. consumptionList = translate_consumption(_item, hides=agent.hide_consume_kinds_dealer)
  1301. dataList.append({
  1302. "dateStr": _month,
  1303. "dateText": u"{}年{}月".format(*_month.split("-")),
  1304. "consumptionList": consumptionList
  1305. })
  1306. return JsonOkResponse(payload={'dataList': dataList})
  1307. @permission_required(ROLE.dealer, ROLE.subaccount)
  1308. def updateInfo(request):
  1309. # type: (WSGIRequest)->JsonResponse
  1310. """
  1311. 支持经销商更改用户信息
  1312. :param request:
  1313. :return:
  1314. """
  1315. name = request.POST.get('name', '')
  1316. if NAME_RE.match(name) is None:
  1317. logger.info('update dealer name doesn\'t fit format, name=%s' % (name.encode('utf-8'),))
  1318. return JsonResponse({"result": 0, "description": "请输入正确格式的名称(2-20位)"})
  1319. if check_role(request.user, ROLE.dealer):
  1320. dealer = Dealer.objects(id=request.user.bossId).first() # type: Union[Dealer,None]
  1321. if dealer is None:
  1322. return JsonResponse({"result": 0, "description": "该经销商不存在"})
  1323. updated = dealer.update_dealer(ownerId=str(dealer.id), nickname=name)
  1324. if not updated:
  1325. logger.info('Dealer [updateInfo] failed, name=%s' % (name.encode('utf-8'),))
  1326. return JsonResponse({"result": 0, "description": u'更新失败,请重试'})
  1327. else:
  1328. return JsonResponse({"result": 1, "description": None})
  1329. else:
  1330. subaccount = SubAccount.objects(id=request.user.id).first() # type: Union[Dealer,None]
  1331. if subaccount is None:
  1332. return JsonResponse({"result": 0, "description": "该经销商不存在"})
  1333. updated = subaccount.update(nickname=name)
  1334. if not updated:
  1335. logger.info('subaccount [updateInfo] failed, name=%s' % (name.encode('utf-8'),))
  1336. return JsonResponse({"result": 0, "description": u'更新失败,请重试'})
  1337. else:
  1338. return JsonResponse({"result": 1, "description": None})
  1339. @permission_required(ROLE.dealer, ROLE.subaccount)
  1340. def verifyNewPhoneNumber(request):
  1341. # type: (WSGIRequest)->JsonResponse
  1342. """
  1343. 修改经销商手机号
  1344. :param request:
  1345. :return:
  1346. """
  1347. code = request.POST.get('code')
  1348. if not code:
  1349. return JsonResponse({"result": 0, "description": u'请输入验证码'})
  1350. phoneNumber = request.POST.get('phone')
  1351. if PHONE_NUMBER_RE.match(phoneNumber) is None:
  1352. logger.info('phone number format error, phone=%s' % phoneNumber)
  1353. return JsonResponse({"result": 0, "description": u"请输入正确的手机号码"})
  1354. if check_role(request.user, ROLE.dealer):
  1355. dealer = Dealer.objects(id=request.user.bossId).first() # type: Optional[Dealer]
  1356. if dealer is None:
  1357. return JsonResponse({"result": 0, "description": u"该经销商不存在"})
  1358. # : 检测是否系统内已有该号码,为了防止混淆
  1359. if Dealer.objects(username=phoneNumber).first():
  1360. return JsonResponse({"result": 0, "description": u"已存在与该手机号码绑定的账户"})
  1361. status, msg = dealerRegisterSMSProvider.verify(phoneNumber, code)
  1362. if status:
  1363. updated = dealer.update_dealer(ownerId=str(dealer.id), username=phoneNumber)
  1364. if updated:
  1365. Dealer.invalid_cache(dealer.id)
  1366. return JsonResponse({"result": 1, "description": None})
  1367. else:
  1368. return JsonResponse({"result": 0, "description": u'更换失败'})
  1369. else:
  1370. return JsonResponse({"result": 0, "description": msg})
  1371. else:
  1372. subAccount = SubAccount.objects(id=request.user.id,
  1373. agentId=request.user.agentId).first() # type: Optional[Dealer]
  1374. if subAccount is None:
  1375. return JsonResponse({"result": 0, "description": u"该子账号不存在"})
  1376. # : 检测是否系统内已有该号码,为了防止混淆
  1377. if SubAccount.objects(username=phoneNumber, agentId=request.user.agentId).first():
  1378. return JsonResponse({"result": 0, "description": u"已存在与该手机号码绑定的子账户"})
  1379. status, msg = dealerRegisterSMSProvider.verify(phoneNumber, code)
  1380. if status:
  1381. updated = subAccount.update(username=phoneNumber)
  1382. if updated:
  1383. return JsonResponse({"result": 1, "description": None})
  1384. else:
  1385. return JsonResponse({"result": 0, "description": u'更换失败'})
  1386. else:
  1387. return JsonResponse({"result": 0, "description": msg})
  1388. @permission_required(ROLE.dealer, ROLE.subaccount)
  1389. def setAddressFree(request):
  1390. # type: (WSGIRequest)->JsonResponse
  1391. """
  1392. 设置部分地址为免费地址, 其同一地址下所有设备都会供免费使用
  1393. :param request:
  1394. :return:
  1395. """
  1396. payload = parse_json_payload(request.body)
  1397. groupId = payload.get('groupId', None)
  1398. isFree = payload.get('isFree', False)
  1399. currentDealer = request.user.myBoss # type: Optional[Dealer]
  1400. if currentDealer.get_feature('disable_set_group_free').get('disable_set_group_free', False):
  1401. return JsonResponse(
  1402. {'result': 0, 'description': '设备无法使用该功能奥, 如有问题, 请联系代理商', 'payload': {}})
  1403. if groupId is None:
  1404. return JsonResponse({"result": 0, "description": u'地址不可为空'})
  1405. try:
  1406. Group.update_group(group_id=groupId, isFree=isFree)
  1407. return JsonResponse({"result": 1, "description": None})
  1408. except Exception as e:
  1409. logger.exception(e)
  1410. return JsonResponse({"result": 0, "description": u'修改失败'})
  1411. #### `经销商报表版块` ###############################################################
  1412. @permission_required(ROLE.dealer, ROLE.subaccount)
  1413. def dateCoins(request):
  1414. """
  1415. TODO 线下投币相关数据与收益计算展现彻底分离,接口需要重新审视
  1416. :param request:
  1417. :return:
  1418. """
  1419. ownerId = str(request.user.bossId)
  1420. now = datetime.datetime.now()
  1421. rpt = Accounting.getOwnerIncome(ownerId, now)
  1422. return JsonResponse({"result": 1, "description": None, 'payload': {"coins": rpt["lineCoins"]}})
  1423. @permission_required(ROLE.dealer, ROLE.subaccount)
  1424. def dateCoinsDetail(request):
  1425. """
  1426. TODO 线下投币相关数据与收益计算展现彻底分离,接口需要重新审视
  1427. :param request:
  1428. :return:
  1429. """
  1430. ownerId = str(request.user.bossId)
  1431. pageIndex = int(request.GET.get('pageIndex', 1))
  1432. pageSize = int(request.GET.get('pageSize', 10))
  1433. nowDate = datetime.datetime.now().strftime('%Y-%m-%d')
  1434. groupIds = Group.get_group_ids_of_dealer(ownerId)
  1435. devNos = Device.get_devNos_by_group(groupIds)
  1436. keys = [devCoinTmpl(devNo, nowDate) for devNo in devNos]
  1437. devCoinDict = reportCache.get_many(keys)
  1438. devNoList = []
  1439. for key, coins in devCoinDict.items():
  1440. coins = int(coins)
  1441. if coins == 0:
  1442. continue
  1443. tempList = key.split('_')
  1444. devNo = tempList[1]
  1445. devNoList.append({'devNo': devNo, 'coins_count': coins})
  1446. sorted(devNoList, key=lambda dev: dev['coins_count'], reverse=True)
  1447. total = len(devNoList)
  1448. resultDevDictList = devNoList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  1449. devNoList = [dev['devNo'] for dev in resultDevDictList]
  1450. devDict = Device.get_dev_by_nos(devNoList)
  1451. groupIds = [dev['groupId'] for dev in devDict.values()]
  1452. groupDict = Group.get_groups_by_group_ids(groupIds)
  1453. dataList = []
  1454. for dev in resultDevDictList:
  1455. if dev['devNo'] not in devDict:
  1456. logger.warning('dev<IMEI={}> not belong to dealer<id={}>'.format(dev['devNo'], ownerId))
  1457. continue
  1458. devDetail = devDict[dev['devNo']]
  1459. groupDetail = groupDict[devDetail['groupId']]
  1460. dataList.append({
  1461. 'value': devDetail['logicalCode'],
  1462. 'coins_count': dev['coins_count'],
  1463. "online": devDetail["online"],
  1464. "remark": devDetail["remarks"],
  1465. "type": devDetail['devType']['name'],
  1466. "groupNumber": devDetail["groupNumber"],
  1467. "groupName": groupDetail['groupName'],
  1468. "status": devDetail['status'],
  1469. "statusInfo": devDetail['statusInfo']
  1470. })
  1471. return JsonResponse({"result": 1, "description": None, 'payload': {"total": total, "dataList": dataList}})
  1472. ########################
  1473. #### 经销商收益消费数据中心
  1474. ########################
  1475. @require_GET
  1476. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益统计失败'))
  1477. @permission_required(ROLE.dealer, ROLE.subaccount)
  1478. def getIncomeStatistics(request):
  1479. # type: (WSGIRequest)->JsonResponse
  1480. """
  1481. 经销商经营统计 首页获取入口
  1482. :param request:
  1483. :return:
  1484. """
  1485. currentDealer = request.user # type: cast(Dealer)
  1486. groupIds = Group.get_group_ids_of_dealer_and_partner(str(currentDealer.bossId))
  1487. stats = [
  1488. {
  1489. "name": u"完成订单",
  1490. "value": GroupDailyStat.get_today_recharge_count(groupIds=groupIds),
  1491. "effect": "good",
  1492. "unit": "",
  1493. "necessary": True
  1494. }
  1495. ]
  1496. agent = Agent.objects(id=currentDealer.agentId).get() # type: Agent
  1497. start, end = today_datetime_range()
  1498. if not agent.supports('hide_dealer_newly_user_added_count'):
  1499. stats.append({
  1500. "name": u"新增用户",
  1501. "value": MyUser.get_new_user_count(groupIds=groupIds, start=start, end=end),
  1502. "effect": "good",
  1503. "unit": "",
  1504. "necessary": True
  1505. })
  1506. dailyStat = DealerDailyStat.get_today(currentDealer.bossId)
  1507. consumption = dailyStat.get("consumption", dict())
  1508. for kind in agent.hide_consume_kinds_dealer:
  1509. consumption.pop(kind, None)
  1510. for kind, value in consumption.iteritems():
  1511. stats.append(
  1512. {
  1513. "source": kind,
  1514. "name": DEALER_CONSUMPTION_AGG_KIND_TRANSLATION.get(kind, ''),
  1515. "value": to_quantity(kind, value),
  1516. "effect": "good",
  1517. "unit": DEALER_CONSUMPTION_AGG_KIND_UNIT.get(kind, ''),
  1518. "necessary": False
  1519. }
  1520. )
  1521. # 将非必须的并且值为 0的过滤掉
  1522. todayStatList = filter(lambda _: float(str((_.get("value", 0)))) > 0 or _.get("necessary"), stats)
  1523. now = datetime.datetime.now()
  1524. monthStr = MONTH_DATE_KEY.format(year=now.year, month=now.month)
  1525. return JsonOkResponse(
  1526. payload={
  1527. "monthIncome": DealerDailyStatsModelProxy.get_one_month_income(
  1528. dealerId = currentDealer.bossId, monthStr = monthStr),
  1529. "todayIncome": DealerDailyStat.get_today_income(dealerId = currentDealer.bossId),
  1530. 'todayRefundCash': abs(DealerDailyStat.get_today_refund_cash(dealerId = currentDealer.bossId)),
  1531. "todayStatList": todayStatList
  1532. }
  1533. )
  1534. @require_GET
  1535. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益消费来源失败'))
  1536. @permission_required(ROLE.dealer, ROLE.subaccount)
  1537. def getIncomeConsumptionCategories(request):
  1538. # type: (WSGIRequest)->JsonResponse
  1539. """
  1540. :param request:
  1541. :return:
  1542. """
  1543. currentDealer = request.user # type: cast(Dealer)
  1544. expand = lambda _: [{'text': v, 'value': k} for k, v in _.items()]
  1545. return JsonResponse(
  1546. {
  1547. 'result': 1,
  1548. 'description': '',
  1549. 'payload': {
  1550. 'income': expand(currentDealer.income_aggregate_source),
  1551. 'consumption': expand(currentDealer.consumption_aggregate_source)
  1552. }
  1553. })
  1554. @require_GET
  1555. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益列表失败'))
  1556. @permission_required(ROLE.dealer, ROLE.subaccount)
  1557. def getIncomeList(request):
  1558. # type: (WSGIRequest)->JsonResponse
  1559. """
  1560. 经销商经营统计的列表 从incomeProxy维度读取
  1561. :param request:
  1562. :return:
  1563. """
  1564. current_dealer = request.user # type: Union[Dealer, SubAccount]
  1565. current_dealer_id = str(current_dealer.bossId)
  1566. pageIndex = int(request.GET.get('pageIndex', 1))
  1567. pageSize = int(request.GET.get('pageSize', 10))
  1568. startTime = request.GET.get("startTime")
  1569. endTime = request.GET.get("endTime")
  1570. logicalCode = request.GET.get("logicalCode")
  1571. source = request.GET.get("secondary")
  1572. groupId = request.GET.get('groupId')
  1573. if groupId and groupId == 'undefined':
  1574. return JsonErrorResponse(description = u'地址过滤参数错误,请刷新后重试')
  1575. if not groupId:
  1576. groupIds = [ObjectId(groupId) for groupId in Group.get_group_ids_of_dealer_and_partner(current_dealer_id)]
  1577. else:
  1578. groupIds = [ObjectId(groupId)]
  1579. searchKey = request.GET.get("searchKey")
  1580. filters = {
  1581. "groupId__in": groupIds,
  1582. "hint": [('groupId', 1), ('dateTimeAdded', -1)],
  1583. }
  1584. if logicalCode:
  1585. filters.update({"logicalCode": logicalCode})
  1586. # 将source为 保险的排除 经销商的主营收益仅仅为以下几种
  1587. if source:
  1588. sources = [source]
  1589. else:
  1590. sources = [
  1591. DEALER_INCOME_SOURCE.REFUND_CASH,
  1592. DEALER_INCOME_SOURCE.RECHARGE,
  1593. DEALER_INCOME_SOURCE.REDPACK,
  1594. DEALER_INCOME_SOURCE.OFFLINE_COIN,
  1595. DEALER_INCOME_SOURCE.RECHARGE_CARD,
  1596. DEALER_INCOME_SOURCE.RECHARGE_VIRTUAL_CARD
  1597. ]
  1598. filters.update({"source__in": sources})
  1599. if searchKey:
  1600. filters.update({"searchKey": searchKey})
  1601. startTime, endTime = current_dealer.limit_filter_date(startTime, endTime)
  1602. if startTime > endTime:
  1603. return JsonResponse({
  1604. 'result': 1,
  1605. 'description': None,
  1606. 'payload': {
  1607. 'total': 0,
  1608. 'adShow': current_dealer.adShow,
  1609. 'totalAmount': RMB(0),
  1610. 'dataList': [],
  1611. }
  1612. })
  1613. # 获取收益集合
  1614. st = datetime.datetime.strptime(startTime, "%Y-%m-%d")
  1615. et = datetime.datetime.strptime(endTime, "%Y-%m-%d")
  1616. incomeQuery = DealerIncomeProxy.objects.filter(dateTimeAdded__gte=st, dateTimeAdded__lt=et+datetime.timedelta(days=1), **filters) # type: CustomQuerySet
  1617. total, totalAmount = incomeQuery.sum_and_count("actualAmountMap.{}".format(current_dealer_id))
  1618. # 第一次循环提取出收益模型以及其对应的充值单号
  1619. incomes = list()
  1620. ref_ids = list()
  1621. for _income in incomeQuery.paginate(pageIndex, pageSize): # type: DealerIncomeProxy
  1622. incomes.append(_income)
  1623. ref_ids.append(_income.ref_id)
  1624. # 取出所有的充值记录
  1625. recharges = dict()
  1626. if ref_ids:
  1627. for item in RechargeRecord.objects.filter(id__in=ref_ids): # type: RechargeRecord
  1628. recharges[str(item.id)] = item
  1629. # 最后看是否需要执行内存合单
  1630. dataList = list()
  1631. for _record in incomes:
  1632. if str(_record.ref_id) not in recharges:
  1633. logger.warning('order<id={}> not exist.'.format(str(_record.ref_id)))
  1634. continue
  1635. rechargeOrder = recharges[str(_record.ref_id)] # type: RechargeRecord
  1636. # 找到同级的子单 然后一起合并
  1637. if rechargeOrder.isSubOrder:
  1638. _subOrders = RechargeRecord.objects.filter(
  1639. id__ne=rechargeOrder.id,
  1640. ownerId=rechargeOrder.ownerId,
  1641. devNo=rechargeOrder.devNo,
  1642. openId=rechargeOrder.openId,
  1643. wxOrderNo=rechargeOrder.wxOrderNo
  1644. )
  1645. # 找到该笔支付单的所有分账单proxy
  1646. _incomes = DealerIncomeProxy.objects.filter(ref_id__in=[_.id for _ in _subOrders])
  1647. _data = _record.to_dict(dealerId=current_dealer_id)
  1648. _data["subs"] = [_record.to_dict(current_dealer_id)]
  1649. for _income in _incomes:
  1650. _incomeDict = _income.to_dict(current_dealer_id)
  1651. _data["totalAmount"] += _incomeDict["totalAmount"]
  1652. _data["amount"] += _incomeDict["amount"]
  1653. _data["subs"].append(_incomeDict)
  1654. else:
  1655. _data = _record.to_dict(dealerId=current_dealer_id)
  1656. dataList.append(_data)
  1657. return JsonResponse(
  1658. {
  1659. 'result': 1,
  1660. 'description': "",
  1661. 'payload': {
  1662. 'total': total,
  1663. 'adShow': current_dealer.adShow,
  1664. 'totalAmount': RMB(totalAmount),
  1665. 'dataList': dataList,
  1666. }
  1667. }
  1668. )
  1669. @require_GET
  1670. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益详情失败'))
  1671. @permission_required(ROLE.dealer, ROLE.subaccount)
  1672. def getIncomeDetail(request):
  1673. # type: (WSGIRequest)->JsonResponse
  1674. """
  1675. 根据 存在收入代理里的`ref_id`来获取真实的收入对应的对象,以拼装出真实的详情
  1676. :param request:
  1677. :return:
  1678. """
  1679. currentDealerId = str(request.user.bossId)
  1680. _id = request.GET.get("id")
  1681. _ref_id = request.GET.get("ref_id")
  1682. if not any([_id, _ref_id]) or 'groupId' not in request.GET:
  1683. return JsonErrorResponse(description=u'参数错误,请刷新后再试')
  1684. filters = {"id": _id} if _id else {"ref_id": ObjectId(_ref_id)}
  1685. filters.update({'shard_filter': {'groupId': request.GET.get('groupId')}})
  1686. record = ClientDealerIncomeModelProxy.get_one(**filters) # type: DealerIncomeProxy
  1687. if not record:
  1688. return JsonErrorResponse(description=u"未查询到该笔订单")
  1689. data = record.ref_detail(currentDealerId)
  1690. startKey = data.get("startKey", None)
  1691. if startKey:
  1692. consumeRecord = ConsumeRecord.objects(startKey=data.get('startKey', '')).first()
  1693. if consumeRecord is not None:
  1694. data.update({'orderNo': consumeRecord.orderNo})
  1695. data.update({'consumeId': str(consumeRecord.id)})
  1696. rechargeRecord = RechargeRecord.objects.filter(id=record.ref_id).first()
  1697. if rechargeRecord is not None and rechargeRecord.via == 'redpack':
  1698. data.update({'gateway': 'redpack'})
  1699. # 新加入一个判断,如果是group owner则显示全部正常信息,如果不是只显示全部金额和自己分到的金额信息
  1700. # 判断是否是group owner,如果是group显示全部完整信息
  1701. for partnerInfo in data['incomePartitionList']:
  1702. if partnerInfo['owner']:
  1703. if partnerInfo['role'] == 'me':
  1704. return JsonResponse({'result': 1, 'description': '', 'payload': data})
  1705. # 判断是role是否是me,如果不是本人信息则不显示
  1706. for i in range(len(data['incomePartitionList']) - 1, -1, -1):
  1707. if data['incomePartitionList'][i]['role'] != 'me':
  1708. del data['incomePartitionList'][i]
  1709. return JsonResponse({'result': 1, 'description': '', 'payload': data})
  1710. @require_GET
  1711. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取消费列表失败'))
  1712. @permission_required(ROLE.dealer, ROLE.subaccount)
  1713. def getConsumptionList(request):
  1714. # type: (WSGIRequest)->JsonResponse
  1715. """
  1716. :param request:
  1717. :return:
  1718. """
  1719. def coin_quantity(amount):
  1720. # type:(float)->Quantity
  1721. return Quantity(amount, places=consumption_unit_precision(DEALER_CONSUMPTION_AGG_KIND.COIN))
  1722. current_dealer = request.user # type: cast(Dealer)
  1723. current_dealer_id = str(current_dealer.bossId)
  1724. pageIndex = int(request.GET.get('pageIndex', 1))
  1725. pageSize = int(request.GET.get('pageSize', 10))
  1726. startTime = request.GET.get('startTime')
  1727. endTime = request.GET.get('endTime')
  1728. startTime, endTime = current_dealer.limit_filter_date(startTime, endTime)
  1729. if endTime < startTime:
  1730. return JsonResponse({
  1731. 'result': 1,
  1732. 'description': None,
  1733. 'payload': {
  1734. 'total': 0,
  1735. 'adShow': current_dealer.adShow,
  1736. 'totalAmount': RMB(0),
  1737. 'dataList': []
  1738. }
  1739. })
  1740. else:
  1741. logicalCode = request.GET.get("logicalCode")
  1742. source = request.GET.get("secondary")
  1743. groupId = request.GET.get('groupId')
  1744. filters = {
  1745. 'isNormal': True
  1746. }
  1747. if not groupId:
  1748. filters.update({
  1749. 'ownerId__in': Dealer.get_cooperative_dealer_ids(current_dealer_id),
  1750. 'groupId__in': Dealer.get_cooperative_group_ids(current_dealer_id)
  1751. })
  1752. else:
  1753. group = Group.get_group(groupId) # type: GroupDict
  1754. filters.update({
  1755. 'shard_filter': {'ownerId': group.ownerId},
  1756. 'groupId': groupId
  1757. })
  1758. searchKey = request.GET.get("searchKey")
  1759. if logicalCode:
  1760. filters.update({
  1761. "logicalCode": logicalCode
  1762. })
  1763. if source:
  1764. filters.update({"aggInfo__{}__exists".format(source): True})
  1765. if searchKey:
  1766. filters.update({"searchKey": searchKey})
  1767. # 获取的是总的数据条目
  1768. records = ClientConsumeModelProxy.get_data_list(startTime=startTime, endTime=endTime,
  1769. **filters) # type: CustomQuerySet
  1770. total, totalAmount = records.sum_and_count("coin")
  1771. totalAmount = coin_quantity(totalAmount)
  1772. agent = Agent.objects.get(id=current_dealer.agentId) # type: Agent
  1773. return JsonResponse(
  1774. {
  1775. 'result': 1,
  1776. 'description': None,
  1777. 'payload':
  1778. {
  1779. 'total': total,
  1780. 'adShow': current_dealer.adShow,
  1781. 'totalAmount': totalAmount,
  1782. 'dataList': [
  1783. _record.to_dict(source=source, hides=agent.hide_consume_kinds_dealer) for _record in
  1784. records.paginate(pageIndex, pageSize)
  1785. ],
  1786. }
  1787. })
  1788. @require_GET
  1789. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取消费详情失败'))
  1790. @permission_required(ROLE.dealer, ROLE.subaccount)
  1791. def getConsumptionDetail(request):
  1792. # type: (WSGIRequest)->JsonResponse
  1793. """
  1794. 消费详情应该附上成本信息(如果有)
  1795. 通过RECHARGE查询CONSUME有两种情况. 一个是CONSUME一定在RECHARGE之后; 还有一个是
  1796. 后支付, RECHARGE后建立起来. 这种情况下会在RECHARGE保存consumeid
  1797. :param request:
  1798. :return:
  1799. """
  1800. id_ = request.GET.get('id')
  1801. start_key = request.GET.get('startKey')
  1802. filters = {'shard_filter': {"ownerId": request.GET.get('ownerId')}}
  1803. if id_:
  1804. filters.update({"id": str(id_)})
  1805. record = ClientConsumeModelProxy.get_one(**filters) # type: ConsumeRecord
  1806. elif start_key:
  1807. filters.update({"startKey": start_key, "hint": [("startKey", 1)]})
  1808. record = ClientConsumeModelProxy.get_one(foreign_id=request.GET.get('ref_id'),
  1809. **filters) # type: ConsumeRecord
  1810. else:
  1811. logger.error("[getConsumptionDetail] not id and not startKey !")
  1812. return JsonErrorResponse(description=u'参数错误,请刷新后再试')
  1813. payload = record.to_detail()
  1814. if payload.has_key('aggInfo'):
  1815. newAggInfo = [remove_some_desc_for_consume(value, u'使用时长') for value in payload['aggInfo']]
  1816. payload['aggInfo'] = newAggInfo
  1817. if record.isNormal:
  1818. device = Device.get_dev(record.devNo) # type: DeviceDict
  1819. if device:
  1820. payload.update({
  1821. 'showPG': device.support_power_graph
  1822. })
  1823. else:
  1824. payload.update({'showPG': False})
  1825. return JsonOkResponse(payload=payload)
  1826. @require_POST
  1827. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"关闭订单失败"))
  1828. @permission_required(ROLE.dealer)
  1829. def closeOrder(request):
  1830. payload = json.loads(request.body)
  1831. orderId = payload.get("orderId", "")
  1832. order = ClientConsumeModelProxy.get_one(id=orderId)
  1833. order.status = "finished"
  1834. order.save()
  1835. return JsonOkResponse()
  1836. @permission_required(ROLE.dealer, ROLE.subaccount)
  1837. def groupConsumptionData(request):
  1838. # type: (WSGIRequest)->JsonResponse
  1839. """
  1840. 经销商旗下所有组的消费数据
  1841. :param request:
  1842. :return:
  1843. """
  1844. def get_group_info(g, _id):
  1845. isM = _id == g.get("ownerId")
  1846. if not isM:
  1847. p = round_2_digits(float(g.get("partnerDict", dict()).get(_id, dict()).get("percent", 0)))
  1848. else:
  1849. fullPercent = 100
  1850. for _partner in g.get("partnerDict", dict()).values():
  1851. fullPercent -= float(_partner.get("percent", 0))
  1852. p = round_2_digits(float(fullPercent))
  1853. return isM, p
  1854. current_user = request.user # type: Dealer
  1855. dealerId = str(current_user.bossId)
  1856. dealer = Dealer.objects.get(id=dealerId)
  1857. pageIndex = int(request.GET.get("pageIndex", 1))
  1858. pageSize = int(request.GET.get("pageSize", 10))
  1859. startDate = request.GET.get("startTime")
  1860. endDate = request.GET.get("endTime")
  1861. startDate, endDate = current_user.limit_filter_date(startDate, endDate)
  1862. if endDate < startDate:
  1863. return JsonResponse({
  1864. 'result': 1,
  1865. 'description': '',
  1866. 'payload': {
  1867. 'dataList': [],
  1868. 'total': 0,
  1869. 'adShow': current_user.adShow
  1870. }
  1871. })
  1872. else:
  1873. searchKey = request.GET.get("searchKey", None)
  1874. # 通过searchKey 获取组地址 作为查询的筛选条件
  1875. groupIds = Group.search_group_ids_of_dealer(dealerId, searchKey) + \
  1876. Group.search_group_ids_of_partner(dealerId, searchKey)
  1877. # 每个地址组一个单位 ,根据地址组ID来完成对数据分页
  1878. groupIdSlice = groupIds[(pageIndex - 1) * pageSize: pageSize * pageIndex]
  1879. groupStatisticMap = GroupDailyStatsModelProxy.get_groups_consumption_statistic(groupIds=groupIdSlice,
  1880. startDate=startDate,
  1881. endDate=endDate)
  1882. groupDevCountMap = Device.get_device_count_by_group(groupIdSlice)
  1883. agent = Agent.objects.get(id=current_user.agentId)
  1884. isHiddenUsedTime = True if 'hiddenUsedTime' in agent.features else False
  1885. dataList = list()
  1886. for _groupId in groupIdSlice:
  1887. groupStatistic = groupStatisticMap.get(_groupId, dict())
  1888. consumptionList = translate_consumption(groupStatistic, hides=agent.hide_consume_kinds_dealer)
  1889. # 志高电子隐藏经销商后台消耗电量和电费成本统计
  1890. if "not_show_about_elec" in dealer.features:
  1891. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"消耗电量"]
  1892. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"电费成本"]
  1893. if isHiddenUsedTime:
  1894. consumptionList = [_c for _c in consumptionList if _c.get("name") != u"使用时长"]
  1895. group = Group.get_group(_groupId)
  1896. isManager, percent = get_group_info(group, dealerId)
  1897. dataList.append({
  1898. 'groupName': group['groupName'],
  1899. 'groupId': group['groupId'],
  1900. 'address': group['address'],
  1901. 'equipmentCount': groupDevCountMap.get(_groupId, 0),
  1902. 'agentProfitShare': request.user.agentProfitShare,
  1903. 'isManager': group.get("ownerId") == dealerId,
  1904. 'consumptionList': consumptionList
  1905. })
  1906. dataList = sorted(dataList, key=lambda x: float(x['equipmentCount']), reverse=True)
  1907. total = len(groupIds)
  1908. return JsonResponse({
  1909. 'result': 1,
  1910. 'description': '',
  1911. 'payload': {
  1912. 'dataList': dataList,
  1913. 'total': total,
  1914. 'adShow': request.user.adShow
  1915. }
  1916. })
  1917. ##################################################################################
  1918. #### `经销商信息设置` ###############################################################
  1919. ##################################################################################
  1920. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新失败'))
  1921. @permission_required(ROLE.dealer, ROLE.subaccount)
  1922. def resetPassword(request):
  1923. # type: (WSGIRequest)->JsonResponse
  1924. dealer = request.user
  1925. oldPassword = request.POST.get('oldPassword', "")
  1926. if not oldPassword:
  1927. return JsonErrorResponse(description=u"请输入旧密码")
  1928. limitManager = LimitAttemptsManager('resetPassword', oldPassword)
  1929. if limitManager.is_exceeded_limit():
  1930. return JsonErrorResponse(description=u'超出输入错误次数限制,请明日再试')
  1931. if dealer.check_password(oldPassword):
  1932. password = request.POST.get('password', "")
  1933. if password == "":
  1934. return JsonErrorResponse(description=u"请输入密码")
  1935. else:
  1936. dealer.set_password(password)
  1937. request.session['password'] = password
  1938. limitManager.clear()
  1939. return JsonOkResponse()
  1940. else:
  1941. limitManager.incr()
  1942. return JsonErrorResponse(description=u'旧密码输入错误,您还可输入%s次' % limitManager.times_left())
  1943. # : 开关
  1944. # : 可考虑以后整合成一个接口
  1945. # : @url('service/toggleSwitches')
  1946. # : def f(request):
  1947. # : dealer.update(**json.loads(request.body))
  1948. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  1949. @permission_required(ROLE.dealer, ROLE.subaccount)
  1950. def setWithdrawMsgSwitch(request):
  1951. # type: (WSGIRequest)->JsonResponse
  1952. ownerId = str(request.user.bossId)
  1953. payload = json.loads(request.body) if request.body else {}
  1954. if not payload:
  1955. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  1956. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  1957. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  1958. updated = Dealer.objects(id=ownerId).update(withdrawlNotify=payload.get('on', False))
  1959. if updated:
  1960. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  1961. else:
  1962. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  1963. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  1964. @permission_required(ROLE.dealer, ROLE.subaccount)
  1965. def setOfflineNotifySwitch(request):
  1966. # type: (WSGIRequest)->JsonResponse
  1967. """
  1968. :param request:
  1969. :return:
  1970. """
  1971. ownerId = str(request.user.bossId)
  1972. payload = json.loads(request.body) if request.body else {}
  1973. if not payload:
  1974. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  1975. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  1976. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  1977. updated = Dealer.objects(id=ownerId).update(offlineNotifySwitch=payload.get('on', False))
  1978. if updated:
  1979. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  1980. else:
  1981. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  1982. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  1983. @permission_required(ROLE.dealer, ROLE.subaccount)
  1984. def saveOfflineNotifyTime(request):
  1985. # type: (WSGIRequest)->JsonResponse
  1986. """
  1987. :param request:
  1988. :return:
  1989. """
  1990. ownerId = str(request.user.bossId)
  1991. payload = json.loads(request.body) if request.body else {}
  1992. if not payload:
  1993. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  1994. if payload['offlineNotifyTime'] and (not request.user.isManagerialOpenIdBound):
  1995. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  1996. updated = Dealer.objects(id=ownerId).update(offlineNotifyTime=str(payload.get('offlineNotifyTime', '')))
  1997. if updated:
  1998. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  1999. else:
  2000. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  2001. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  2002. @permission_required(ROLE.dealer, ROLE.subaccount)
  2003. def toggleNewUserPaymentOrderPushSwitch(request):
  2004. # type: (WSGIRequest)->JsonResponse
  2005. """
  2006. 用户支付订单后,即时推送给经销商
  2007. :param request:
  2008. :return:
  2009. """
  2010. ownerId = str(request.user.bossId)
  2011. payload = json.loads(request.body) if request.body else {}
  2012. if not payload:
  2013. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  2014. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  2015. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  2016. updated = Dealer.objects(id=ownerId).update(newUserPaymentOrderPushSwitch=payload.get('on', False))
  2017. if updated:
  2018. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2019. else:
  2020. return JsonResponse({"result": 0, "description": u'更新写入失败', 'payload': {}})
  2021. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  2022. @permission_required(ROLE.dealer, ROLE.subaccount)
  2023. def toggleDailyIncomeReportPushSwitch(request):
  2024. # type: (WSGIRequest)->JsonResponse
  2025. """
  2026. 每日9点推送昨日报表
  2027. :param request:
  2028. :return:
  2029. """
  2030. ownerId = str(request.user.bossId)
  2031. payload = json.loads(request.body) if request.body else {}
  2032. if not payload:
  2033. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  2034. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  2035. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  2036. updated = Dealer.objects(id=ownerId).update(dailyIncomeReportPushSwitch=payload.get('on', False))
  2037. if updated:
  2038. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2039. else:
  2040. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  2041. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'查询错误'))
  2042. @permission_required(ROLE.dealer, ROLE.subaccount)
  2043. def paymentOrderRecords(request):
  2044. # type: (WSGIRequest)->JsonResponse
  2045. """
  2046. 经销商后台查询充值订单(仅仅查询充值订单的 退币一些列的不要展示了)
  2047. :param request:
  2048. :return:
  2049. """
  2050. ownerId = str(request.user.bossId)
  2051. payload = json.loads(request.body)
  2052. pageIndex = payload.get("pageIndex")
  2053. pageSize = payload.get("pageSize")
  2054. startTime = payload.get("startTime")
  2055. endTime = payload.get("endTime")
  2056. if not endTime:
  2057. endTime = datetime.datetime.now()
  2058. else:
  2059. endTime = get_tomorrow_zero_time(datetime.datetime.strptime(endTime, "%Y-%m-%d"))
  2060. if not startTime:
  2061. startTime = get_zero_time(endTime)
  2062. else:
  2063. startTime = get_zero_time(datetime.datetime.strptime(startTime, "%Y-%m-%d"))
  2064. if startTime > endTime:
  2065. startTime = endTime
  2066. orderStatus = payload.get("orderStatus")
  2067. groupInfo = payload.get("group", dict())
  2068. deviceInfo = payload.get("device", dict())
  2069. queryFilters = {
  2070. 'dateTimeAdded': {
  2071. '$gte': startTime,
  2072. '$lt': endTime
  2073. },
  2074. "via": {
  2075. "$in": map(format, [
  2076. USER_RECHARGE_TYPE.RECHARGE_MIX,
  2077. USER_RECHARGE_TYPE.RECHARGE,
  2078. USER_RECHARGE_TYPE.RECHARGE_CARD,
  2079. USER_RECHARGE_TYPE.RECHARGE_VIRTUAL_CARD,
  2080. USER_RECHARGE_TYPE.RECHARGE_CASH,
  2081. USER_RECHARGE_TYPE.RECHARGE_MONTHLY_PACKAGE,
  2082. USER_RECHARGE_TYPE.RECHARGE_REDPACK,
  2083. USER_RECHARGE_TYPE.RECHARGE_INSURANCE
  2084. ])
  2085. }
  2086. }
  2087. search_key = payload.get('searchKey', None)
  2088. if search_key:
  2089. if len(search_key) < 15:
  2090. dev = Device.get_dev_by_logicalCode(search_key)
  2091. if dev:
  2092. queryFilters.update({'devNo': dev.devNo})
  2093. if 'devNo' not in queryFilters:
  2094. queryFilters.update({
  2095. '$or': [
  2096. {'orderNo': search_key},
  2097. {'wxOrderNo': search_key},
  2098. {'transactionId': search_key}
  2099. ]
  2100. })
  2101. else:
  2102. # 订单的状态
  2103. if orderStatus:
  2104. queryFilters.update({"result": orderStatus})
  2105. # 查找的逻辑 自下从上查找 依次是 设备 --> 组 --> 当前查询人 --> 空查询
  2106. # TODO 这个地方的信息安全性 完全依赖上次调度的接口, 目前没有做检查 记得加上
  2107. if deviceInfo:
  2108. queryFilters.update({"devNo": deviceInfo.get("devNo"), "ownerId": deviceInfo.get("ownerId")})
  2109. elif groupInfo:
  2110. queryFilters.update({"groupId": groupInfo.get("groupId"), "ownerId": groupInfo.get("ownerId")})
  2111. else:
  2112. # TODO 这个地方有个BUG 经销商的ID 防止部分新加入的组合伙人 能看到之前组的经营统计信息
  2113. groupIds = list(set(Group.get_group_ids_of_dealer_and_partner(ownerId)))
  2114. groups = Group.get_groups_by_group_ids(groupIds)
  2115. dealer_id_list = list(set([group['ownerId'] for group in groups.values()]))
  2116. queryFilters.update({
  2117. 'ownerId': {'$in': dealer_id_list},
  2118. 'groupId': {'$in': groupIds}
  2119. })
  2120. logger.debug('query recharges between {} and {}. filters = {}'.format(startTime, endTime, queryFilters))
  2121. # 添加筛选条件 选出不是交易子单的订单
  2122. query_set = RechargeRecord.objects.filter(__raw__=queryFilters).filter(attachParas__tradeOrderId=None).order_by('-dateTimeAdded') # type: CustomQuerySet
  2123. totalSum = query_set.sum(RechargeRecord.money.name)
  2124. total_count = query_set.count()
  2125. records = query_set.paginate(pageIndex, pageSize)
  2126. dataList = list()
  2127. for _item in records: # type: RechargeRecord
  2128. # 订单的基本信息
  2129. data = {
  2130. 'id': str(_item.id),
  2131. 'ownerId': _item.ownerId,
  2132. 'gateway': _item.gateway if _item.gateway else 'wechat',
  2133. 'result': _item.result if _item.result else '',
  2134. 'totalFee': _item.money if _item.money else 0,
  2135. 'address': _item.address if _item.address else '',
  2136. 'name': _item.groupName if _item.groupName else '',
  2137. 'nickname': _item.nickname if _item.nickname else '',
  2138. 'devTypeName': _item.dev_type_name,
  2139. 'groupNumber': _item.groupNumber if _item.groupNumber else '',
  2140. 'value': Device.get_logicalCode_by_devNo(_item.devNo) if _item.devNo else '',
  2141. 'wechatTrxid': _item.wxOrderNo if _item.wxOrderNo else '',
  2142. 'outTradeNo': _item.orderNo if _item.orderNo else '',
  2143. 'createdTime': _item.to_datetime_str(_item.dateTimeAdded),
  2144. 'description': _item.my_description if _item.my_description else '',
  2145. 'userId': _item.openId if _item.openId else '',
  2146. 'groupId': _item.groupId if _item.groupId else '',
  2147. 'via': _item.via if _item.via else '',
  2148. 'isQuickPay': _item.isQuickPay if _item.isQuickPay else False,
  2149. 'startKey': _item.attachParas.get('startKey', '') if _item.result == 'success' else '',
  2150. 'consumeId': _item.attachParas.get('consumeRecordId', ''),
  2151. 'isLedgered': _item.is_ledgered,
  2152. 'notLedgerDesc': _item.notLedgerDesc
  2153. }
  2154. # TODO 需要修改 加上子订单的信息
  2155. tradeOrders = RechargeRecord.objects.filter(
  2156. openId=_item.openId,
  2157. attachParas__tradeOrderId=str(_item.id)
  2158. )
  2159. _subs = list()
  2160. for _trade in tradeOrders: # type: RechargeRecord
  2161. _subData = {
  2162. 'id': str(_trade.id),
  2163. 'ownerId': _trade.ownerId,
  2164. 'gateway': _trade.gateway if _trade.gateway else 'wechat',
  2165. 'result': _trade.result if _trade.result else '',
  2166. 'totalFee': _trade.money if _trade.money else 0,
  2167. 'address': _trade.address if _trade.address else '',
  2168. 'name': _trade.groupName if _trade.groupName else '',
  2169. 'nickname': _trade.nickname if _trade.nickname else '',
  2170. 'devTypeName': _trade.dev_type_name,
  2171. 'groupNumber': _trade.groupNumber if _trade.groupNumber else '',
  2172. 'value': Device.get_logicalCode_by_devNo(_trade.devNo) if _trade.devNo else '',
  2173. 'wechatTrxid': _trade.wxOrderNo if _trade.wxOrderNo else '',
  2174. 'outTradeNo': _trade.orderNo if _trade.orderNo else '',
  2175. 'createdTime': _trade.to_datetime_str(_trade.dateTimeAdded),
  2176. 'description': _trade.my_description if _trade.my_description else '',
  2177. 'userId': _trade.openId if _trade.openId else '',
  2178. 'groupId': _trade.groupId if _trade.groupId else '',
  2179. 'via': _trade.via if _trade.via else '',
  2180. 'isQuickPay': _trade.isQuickPay if _trade.isQuickPay else False,
  2181. 'startKey': _trade.attachParas.get('startKey', '') if _trade.result == 'success' else '',
  2182. 'consumeId': _trade.attachParas.get('consumeRecordId', ''),
  2183. 'isLedgered': _trade.is_ledgered,
  2184. 'notLedgerDesc': _trade.notLedgerDesc
  2185. }
  2186. _subs.append(_subData)
  2187. data["subs"] = _subs
  2188. dataList.append(data)
  2189. return JsonResponse({
  2190. "result": 1,
  2191. "description": "",
  2192. 'payload': {
  2193. "page": pageIndex,
  2194. "pageSize": pageSize,
  2195. "total": total_count,
  2196. "totalSum":totalSum,
  2197. "items": dataList
  2198. }
  2199. })
  2200. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'查询错误'))
  2201. @permission_required(ROLE.dealer, ROLE.subaccount)
  2202. def consumeOrderRecords(request):
  2203. # type: (WSGIRequest)->JsonResponse
  2204. """
  2205. 经销商后台查询消费订单
  2206. :param request:
  2207. :return:
  2208. """
  2209. ownerId = str(request.user.bossId)
  2210. payload = json.loads(request.body)
  2211. pageIndex = payload.get("pageIndex")
  2212. pageSize = payload.get("pageSize")
  2213. startTime = payload.get("startTime")
  2214. endTime = payload.get("endTime")
  2215. if not endTime:
  2216. endTime = datetime.datetime.now()
  2217. else:
  2218. endTime = get_tomorrow_zero_time(datetime.datetime.strptime(endTime, "%Y-%m-%d"))
  2219. if not startTime:
  2220. startTime = get_zero_time(endTime)
  2221. else:
  2222. startTime = get_zero_time(datetime.datetime.strptime(startTime, "%Y-%m-%d"))
  2223. if startTime > endTime:
  2224. startTime = endTime
  2225. groupInfo = payload.get("group", dict())
  2226. deviceInfo = payload.get("device", dict())
  2227. filters = {
  2228. 'dateTimeAdded': {
  2229. '$gte': startTime,
  2230. '$lt': endTime
  2231. }
  2232. }
  2233. search_key = payload.get('searchKey', None)
  2234. if search_key:
  2235. if len(search_key) < 15:
  2236. dev = Device.get_dev_by_logicalCode(search_key)
  2237. if dev:
  2238. filters.update({'devNo': dev.devNo})
  2239. if 'devNo' not in filters:
  2240. filters.update({
  2241. 'orderNo': search_key
  2242. })
  2243. else:
  2244. # 查找的逻辑 自下从上查找 依次是 设备 --> 组 --> 当前查询人 --> 空查询
  2245. # TODO 这个地方的信息安全性 完全依赖上次调度的接口, 目前没有做检查 记得加上
  2246. if deviceInfo:
  2247. filters.update({"devNo": deviceInfo.get("devNo"), "ownerId": deviceInfo.get("ownerId")})
  2248. elif groupInfo:
  2249. filters.update({"groupId": groupInfo.get("groupId"), "ownerId": groupInfo.get("ownerId")})
  2250. else:
  2251. # TODO 这个地方有个BUG 经销商的ID 防止部分新加入的组合伙人 能看到之前组的经营统计信息
  2252. groupIds = list(set(Group.get_group_ids_of_dealer_and_partner(ownerId)))
  2253. groups = Group.get_groups_by_group_ids(groupIds)
  2254. dealer_id_list = list(set([group['ownerId'] for group in groups.values()]))
  2255. filters.update({
  2256. 'ownerId': {'$in': dealer_id_list},
  2257. 'groupId': {'$in': groupIds}
  2258. })
  2259. logger.debug('query consumes between {} and {}. filters = {}'.format(startTime, endTime, filters))
  2260. records = ConsumeRecord.objects.filter(__raw__=filters).order_by("-dateTimeAdded") # type: CustomQuerySet
  2261. count = records.count()
  2262. dataList = []
  2263. for rcd in records.paginate(pageIndex, pageSize):
  2264. try:
  2265. dataList.append(rcd.to_detail())
  2266. except Exception as e:
  2267. logger.exception(e)
  2268. continue
  2269. return JsonOkResponse(payload={"dataList": dataList, "total": count})
  2270. @permission_required(ROLE.dealer, ROLE.subaccount)
  2271. def discountRuleData(request):
  2272. # type: (WSGIRequest)->JsonResponse
  2273. groupId = request.GET.get('groupId', None)
  2274. ownerId = str(request.user.bossId)
  2275. if groupId is None:
  2276. ruleList = []
  2277. for k, v in request.user.format_default_discount.items():
  2278. ruleList.append({'ruleId': k, 'payAmount': k, 'coins': v})
  2279. return JsonResponse({"result": 1,
  2280. "description": None,
  2281. 'payload': {"ruleList": ruleList, "groupData": {}}})
  2282. else:
  2283. group = Group.get_group(groupId)
  2284. if group is None:
  2285. return JsonResponse({"result": 0, "description": u"找不到组", 'payload': {}})
  2286. devNos = Device.get_devNos_by_group([groupId])
  2287. group['equipmentCount'] = len(devNos)
  2288. if ownerId == group['ownerId']:
  2289. group['isManager'] = True
  2290. else:
  2291. group['isManager'] = False
  2292. ruleList = []
  2293. for k, v in group['ruleDict'].items():
  2294. ruleList.append({'ruleId': k, 'payAmount': k, 'coins': v})
  2295. return JsonResponse({"result": 1,
  2296. "description": None,
  2297. 'payload': {"ruleList": ruleList, "groupData": group}})
  2298. @permission_required(ROLE.dealer, ROLE.subaccount)
  2299. def discountCardRuleData(request):
  2300. """
  2301. 经销商端的卡优惠获取显示
  2302. # 新的规则修改为
  2303. 如果经销商设置有卡优惠规则 返还卡优惠规则
  2304. 如果经销商没有设置卡优惠规则 但是设置有金币优惠规则 返还金币优惠规则
  2305. 两个都没有设置 默认卡优惠规则
  2306. :param request:
  2307. :return:
  2308. """
  2309. groupId = request.GET.get("groupId", None)
  2310. # 没有组ID的情况获取的是经销商的默认 优惠套餐
  2311. ruleList = list()
  2312. if not groupId:
  2313. for k, v in request.user.format_card_discount.items():
  2314. ruleList.append({"ruleId": k, "payAmount": k, "coins": v})
  2315. return JsonOkResponse(payload={"ruleList": ruleList, "groupData": {}})
  2316. group = Group.get_group(groupId)
  2317. if not group:
  2318. return JsonErrorResponse(description=u"错误的地址信息")
  2319. # 经销商没有设置过卡的优惠规则
  2320. if not group.get("cardRuleDict"):
  2321. cardRuleDict = request.user.defaultCardDiscountConfig
  2322. Group.objects.filter(id=groupId).update(cardRuleDic=cardRuleDict)
  2323. Group.CacheMgr.invalid_group_cache([groupId])
  2324. group = Group.get_group(groupId)
  2325. devNos = Device.get_devNos_by_group([groupId])
  2326. ownerId = str(request.user.bossId)
  2327. group['equipmentCount'] = len(devNos)
  2328. if ownerId == group['ownerId']:
  2329. group['isManager'] = True
  2330. else:
  2331. group['isManager'] = False
  2332. ruleList = []
  2333. for k, v in group['cardRuleDict'].items():
  2334. ruleList.append({'ruleId': k, 'payAmount': k, 'coins': v})
  2335. return JsonResponse({"result": 1,
  2336. "description": None,
  2337. 'payload': {"ruleList": ruleList, "groupData": group}})
  2338. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  2339. @permission_required(ROLE.dealer, ROLE.subaccount)
  2340. def saveDiscountRule(request):
  2341. # type: (WSGIRequest)->JsonResponse
  2342. """
  2343. TODO TO REFACTOR
  2344. :param request:
  2345. :return:
  2346. """
  2347. currentDealer = request.user # type: cast(Dealer)
  2348. # 校验优惠规则
  2349. def check_rule_data(fields, rules):
  2350. for ruleDict in rules:
  2351. for field in fields:
  2352. if len(str(ruleDict[field])) > 12:
  2353. return False, u"%s数额超过限制" % ruleDict[field]
  2354. try:
  2355. float(ruleDict[field])
  2356. except ValueError:
  2357. return False, u"%s类型错误,请输入数字" % ruleDict[field]
  2358. return True, u''
  2359. def update_rule(ruleDict, rules):
  2360. isNewlyAdded = lambda d: d["payAmount"] not in ruleDict.keys()
  2361. if len(ruleDict) >= 10 and any(map(isNewlyAdded, rules)):
  2362. raise ParameterError(u'最多只能设置10条优惠充值信息')
  2363. for rule in rules:
  2364. if rule['ruleId']:
  2365. ruleDict.pop(str(rule['ruleId']), None)
  2366. if rule['ruleId'] != 0 and (float(rule['coins']) in ruleDict.values()):
  2367. raise ParameterError(u'同一套餐下,不能出现充不一样的钱,但是兑币的数目却相同')
  2368. ruleDict.update({str(rule['payAmount']): float(rule['coins'])})
  2369. return ruleDict
  2370. payload = json.loads(request.body) if request.body else {}
  2371. ruleList = payload.get('ruleData', None)
  2372. if ruleList is None:
  2373. return JsonErrorResponse(description=u'没有找到正确的规则')
  2374. status, msg = check_rule_data(["payAmount", "coins"], ruleList)
  2375. if not status:
  2376. return JsonErrorResponse(description=msg)
  2377. groupId = payload.get('groupId', None)
  2378. # groupId为空表示修改默认充值套餐
  2379. if groupId is None:
  2380. try:
  2381. newRuleDict = update_rule(currentDealer.format_default_discount, ruleList)
  2382. currentDealer.update(defaultDiscountConfig=newRuleDict)
  2383. return JsonResponse({"result": 1, "description": '', 'payload': {}})
  2384. except ParameterError as e:
  2385. return JsonErrorResponse(description=e.message)
  2386. else:
  2387. try:
  2388. group = Group.objects(id=groupId).first() # type: Group
  2389. if not group:
  2390. return JsonErrorResponse(description=u'组不存在,请刷新后再试')
  2391. isRecovery = payload.get('isRecovery', 'N')
  2392. if isRecovery == 'Y':
  2393. rule_dict = currentDealer.format_default_discount
  2394. else:
  2395. rule_dict = group.format_rule_dict
  2396. update_rule(rule_dict, ruleList)
  2397. Group.update_group(group_id=groupId, ruleDict=rule_dict)
  2398. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2399. except ParameterError as e:
  2400. return JsonErrorResponse(description=e.message)
  2401. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"更新错误"))
  2402. @permission_required(ROLE.dealer, ROLE.subaccount)
  2403. def saveDiscountCardData(request):
  2404. """
  2405. 保存卡优惠设置
  2406. :param request:
  2407. :return:
  2408. """
  2409. def _check(rules, fieldnames=None):
  2410. """
  2411. 校验 ruleList 的每一个字段和字段值
  2412. :param rules:
  2413. :param fieldnames:
  2414. :return:
  2415. """
  2416. if fieldnames is None:
  2417. fieldnames = ["payAmount", "coins"]
  2418. for ruleDict in rules:
  2419. for field in fieldnames:
  2420. if len(str(ruleDict[field])) > 12:
  2421. return False, u"%s数额超过限制" % ruleDict[field]
  2422. try:
  2423. float(ruleDict[field])
  2424. except ValueError:
  2425. return False, u"%s类型错误,请输入数字" % ruleDict[field]
  2426. return True, u""
  2427. def _update(ruleDict, rules):
  2428. """
  2429. 更新优惠套餐
  2430. :param ruleDict:
  2431. :param rules:
  2432. :return:
  2433. """
  2434. isNewlyAdded = lambda d: d["payAmount"] not in ruleDict.keys()
  2435. if len(ruleDict) >= 10 and any(map(isNewlyAdded, rules)):
  2436. raise ParameterError(u'最多只能设置10条优惠充值信息')
  2437. for rule in rules:
  2438. if rule['ruleId']:
  2439. ruleDict.pop(str(rule['ruleId']), None)
  2440. if rule['ruleId'] != 0 and (float(rule['coins']) in ruleDict.values()):
  2441. raise ParameterError(u'同一套餐下,不能出现充不一样的钱,但是兑币的数目却相同')
  2442. ruleDict.update({str(rule['payAmount']): float(rule['coins'])})
  2443. return ruleDict
  2444. payload = json.loads(request.body) if request.body else dict()
  2445. ruleList = payload.get("ruleData", None)
  2446. if ruleList is None:
  2447. return JsonErrorResponse(description=u"请设置正确的优惠规则")
  2448. status, msg = _check(ruleList)
  2449. if not status:
  2450. return JsonErrorResponse(description=msg)
  2451. groupId = payload.get("groupId", None)
  2452. if groupId is None:
  2453. try:
  2454. newDict = _update(request.user.format_card_discount, ruleList)
  2455. request.user.update(defaultCardDiscountConfig=newDict)
  2456. except ParameterError as e:
  2457. return JsonErrorResponse(description=e.message)
  2458. else:
  2459. return JsonOkResponse(payload={})
  2460. else:
  2461. try:
  2462. group = Group.objects(id=groupId).first() # type: Group
  2463. if not group:
  2464. return JsonErrorResponse(description=u'组不存在,请刷新后再试')
  2465. isRecovery = payload.get('isRecovery', 'N')
  2466. # if isRecovery == 'Y':
  2467. # rule_dict = request.user.format_card_discount
  2468. # else:
  2469. rule_dict = group.format_card_dict
  2470. newDict = _update(rule_dict, ruleList)
  2471. Group.update_group(group_id=groupId, cardRuleDict=newDict)
  2472. except ParameterError as e:
  2473. return JsonErrorResponse(description=e.message)
  2474. else:
  2475. return JsonOkResponse(payload={})
  2476. @permission_required(ROLE.dealer, ROLE.subaccount)
  2477. def delDiscountRule(request):
  2478. # type: (WSGIRequest)->JsonResponse
  2479. ruleId = request.POST.get('ruleId', None)
  2480. if not ruleId:
  2481. return JsonResponse({"result": 0, "description": u"缺少参数ruleId或为空", 'payload': {}})
  2482. groupId = request.POST.get('groupId', None)
  2483. if not groupId:
  2484. default_discount = request.user.format_default_discount
  2485. default_discount.pop(ruleId, None)
  2486. request.user.update(defaultDiscountConfig=default_discount)
  2487. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2488. else:
  2489. try:
  2490. group = Group.objects(id=str(groupId)).first()
  2491. if not group:
  2492. return JsonResponse({"result": 0, "description": u"组不存在,请刷新后再试", 'payload': {}})
  2493. rule_dict = group.format_rule_dict # type: dict
  2494. rule_dict.pop(ruleId, None)
  2495. Group.update_group(group_id=groupId, ruleDict=rule_dict)
  2496. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2497. except Exception, e:
  2498. logger.exception("update db error=%s,groupId=%s" % (e, groupId))
  2499. return JsonResponse({"result": 0, "description": u"更新异常,请重试", 'payload': {}})
  2500. @permission_required(ROLE.dealer, ROLE.subaccount)
  2501. def delDiscountCardData(request):
  2502. """
  2503. 删除卡优惠设置
  2504. :param request:
  2505. :return:
  2506. """
  2507. ruleId = request.POST.get('ruleId', None)
  2508. if not ruleId:
  2509. return JsonResponse({"result": 0, "description": u"缺少参数ruleId或为空", 'payload': {}})
  2510. groupId = request.POST.get('groupId', None)
  2511. if not groupId:
  2512. default_discount = request.user.format_card_discount
  2513. default_discount.pop(ruleId, None)
  2514. request.user.update(defaultCardDiscountConfig=default_discount)
  2515. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2516. else:
  2517. try:
  2518. group = Group.objects(id=str(groupId)).first()
  2519. if not group:
  2520. return JsonResponse({"result": 0, "description": u"组不存在,请刷新后再试", 'payload': {}})
  2521. rule_dict = group.format_card_dict # type: dict
  2522. rule_dict.pop(ruleId, None)
  2523. Group.update_group(group_id=groupId, cardRuleDict=rule_dict)
  2524. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2525. except Exception, e:
  2526. logger.exception("update db error=%s,groupId=%s" % (e, groupId))
  2527. return JsonResponse({"result": 0, "description": u"更新异常,请重试", 'payload': {}})
  2528. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取经销商信息错误'))
  2529. @permission_required(ROLE.dealer, ROLE.subaccount)
  2530. def accountInfo(request):
  2531. # type: (WSGIRequest)->JsonResponse
  2532. if check_role(request.user, ROLE.dealer):
  2533. dealer = Dealer.objects(id=str(request.user.bossId)).get() # type: Dealer
  2534. payload = dealer.to_dict()
  2535. else:
  2536. subaccount = SubAccount.objects(id=str(request.user.id)).get() # type: subaccount
  2537. payload = subaccount.to_dict()
  2538. agent = Agent.objects(id=payload['agentId']).first() # type: Agent
  2539. payload['servicePhone'] = agent.service_phone
  2540. payload['serviceQrcodeUrl'] = agent.serviceQrcodeUrl
  2541. return JsonResponse({"result": 1, "description": None, 'payload': payload})
  2542. ####`经销商金融版块(提现,银行卡信息)` ####################################################
  2543. @permission_required(ROLE.dealer, ROLE.subaccount)
  2544. def walletData(request):
  2545. # type: (WSGIRequest)->JsonResponse
  2546. dealerId = str(request.user.bossId)
  2547. dealer = Dealer.objects(id=dealerId).first() # type: Optional[Dealer]
  2548. if not dealer:
  2549. return JsonErrorResponse(description=u"没有找到经销商")
  2550. my_source_key = dealer.current_wallet_withdraw_source_key
  2551. inhouse_source_key = Agent.get_inhouse_prime_agent().current_wallet_withdraw_source_key
  2552. device_income_list = []
  2553. for source_key, balance in dealer.deviceBalance.iteritems():
  2554. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  2555. device_income_list.append({
  2556. 'id': source_key,
  2557. 'balance': balance.balance,
  2558. 'name': current_platform(source_key, my_source_key),
  2559. 'current': source_key == my_source_key
  2560. })
  2561. ad_income_list = []
  2562. for source_key, balance in dealer.adBalance.iteritems():
  2563. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  2564. ad_income_list.append({
  2565. 'id': source_key,
  2566. 'balance': balance.balance,
  2567. 'name': current_platform(source_key, inhouse_source_key),
  2568. 'current': source_key == inhouse_source_key
  2569. })
  2570. ledger_income_list = []
  2571. for source_key, balance in dealer.ledgerBalance.iteritems():
  2572. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  2573. ledger_income_list.append({
  2574. 'id': source_key,
  2575. 'balance': balance.balance,
  2576. 'name': current_platform(source_key, inhouse_source_key),
  2577. 'current': source_key == inhouse_source_key
  2578. })
  2579. payload = {
  2580. }
  2581. if len(device_income_list) > 0:
  2582. payload.update({
  2583. DEALER_INCOME_TYPE.DEVICE_INCOME: device_income_list
  2584. })
  2585. if len(ad_income_list) > 0:
  2586. payload.update({
  2587. DEALER_INCOME_TYPE.AD_INCOME: ad_income_list
  2588. })
  2589. if len(ledger_income_list) > 0:
  2590. payload.update({
  2591. DEALER_INCOME_TYPE.LEDGER_CONSUME: ledger_income_list
  2592. })
  2593. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  2594. # 经销商获取提现短信验证码
  2595. @error_tolerate(nil=DefaultJsonErrorResponse)
  2596. @permission_required(ROLE.dealer)
  2597. def getWithdrawCode(request):
  2598. # type: (WSGIRequest)->JsonResponse
  2599. currentDealer = request.user # type: Dealer
  2600. toNumber = request.user.username
  2601. agentId = request.user.agentId
  2602. agent = Agent.get_agent(agentId)
  2603. productName = agent['productName']
  2604. if not currentDealer.monitorPhone: # 没有监管的,直接发送验证码到本机
  2605. status, msg = dealerWithdrawSMSProvider.get(phoneNumber=toNumber,
  2606. productName=productName,
  2607. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  2608. else:
  2609. toNumber = currentDealer.monitorPhone
  2610. status, msg = dealerMonitorWithdrawSMSProvider.get(phoneNumber=toNumber,
  2611. productName=productName,
  2612. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  2613. if not status:
  2614. return JsonErrorResponse(description=msg)
  2615. else:
  2616. return JsonOkResponse()
  2617. @permission_required(ROLE.dealer)
  2618. def withdrawalsHistoryList(request):
  2619. # type: (WSGIRequest)->JsonResponse
  2620. """
  2621. 需要连同整个提现数据层整改
  2622. :param request:
  2623. :return:
  2624. """
  2625. current_user = request.user # type: Dealer
  2626. pageIndex = int(request.GET.get('pageIndex', 1))
  2627. pageSize = int(request.GET.get('pageSize', 10))
  2628. status = request.GET.get('status')
  2629. ownerId = str(request.user.bossId)
  2630. startTime = '2016-01-01'
  2631. startTime, _ = current_user.limit_filter_date(startTime, None)
  2632. startTime = datetime.datetime.strptime(startTime, "%Y-%m-%d")
  2633. if status:
  2634. records = WithdrawRecord.objects(ownerId=ownerId,
  2635. role=request.user.role,
  2636. status=status,
  2637. postTime__gte=startTime).order_by('-postTime')
  2638. else:
  2639. records = WithdrawRecord.objects(ownerId=ownerId,
  2640. role=request.user.role,
  2641. postTime__gte=startTime).order_by('-postTime')
  2642. return JsonResponse({
  2643. "result": 1,
  2644. "description": None,
  2645. 'payload': {
  2646. "total": records.count(),
  2647. "withdrawalTotal": RMB(records(status=WithdrawStatus.SUCCEEDED).sum('amount')),
  2648. "dataList": [
  2649. {
  2650. 'bankName': record.parentBankName,
  2651. 'paymentId': str(record.id),
  2652. 'withdrawalsDate': record.postTime.strftime("%Y-%m-%d %H:%M:%S"),
  2653. 'amount': record.amount,
  2654. 'statusText': translate_withdraw_state(record.status),
  2655. 'refunded': record.refunded
  2656. } for record in records.paginate(pageIndex, pageSize)
  2657. ]
  2658. }
  2659. })
  2660. @permission_required(ROLE.dealer)
  2661. def dealerWithdraw(request):
  2662. # type: (WSGIRequest)->JsonResponse
  2663. """
  2664. :param request:
  2665. :return:
  2666. """
  2667. currentDealer = request.user # type: cast(Dealer)
  2668. payload = json.loads(request.body)
  2669. open_id = payload.get('openId')
  2670. if not open_id:
  2671. return JsonResponse({"result": 0, "description": u'鉴权失败,请刷新后再试', 'payload': {}})
  2672. request.user.withdraw_open_id = open_id
  2673. amount = RMB(payload.get('amount', 0.0))
  2674. pay_type = payload.get('payType')
  2675. assert pay_type in (
  2676. WITHDRAW_PAY_TYPE.WECHAT, WITHDRAW_PAY_TYPE.BANK, WITHDRAW_PAY_TYPE.ALIPAY), 'not support this pay type'
  2677. assert amount > RMB(0), 'amount must be bigger than zero'
  2678. status, msg = request.user.withdraw_sms_provider.verify(phoneNumber=request.user.withdraw_sms_phone_number,
  2679. smsCode=payload.get('code'))
  2680. if not status:
  2681. return JsonResponse({"result": 0, "description": msg, 'payload': {}})
  2682. withdraw_service = DealerWithdrawService(payee=request.user,
  2683. income_type=payload.get('sourceType'),
  2684. amount=amount,
  2685. pay_type=pay_type,
  2686. bank_card_no=payload.get('bankAccount', ''))
  2687. result = withdraw_service.execute(source_key=payload.get('sourceId'), recurrent=False)
  2688. logger.debug('withdraw result is: {}'.format(result))
  2689. return JsonResponse(result)
  2690. @permission_required(ROLE.dealer, ROLE.subaccount)
  2691. def paymentInfo(request):
  2692. # type: (WSGIRequest)->JsonResponse
  2693. """
  2694. 展示提现页面数据
  2695. :param request:
  2696. :return:
  2697. """
  2698. ownerId = str(request.user.bossId)
  2699. paymentId = request.GET.get('paymentId', None)
  2700. if not paymentId:
  2701. return JsonErrorResponse(description=u'没有提供提现单ID')
  2702. record = WithdrawRecord.objects(id=str(paymentId)).first() # type: Optional[WithdrawRecord]
  2703. if not record:
  2704. return JsonErrorResponse(description=u"没有找到提现记录")
  2705. return JsonOkResponse(
  2706. payload={
  2707. 'type': record.parentBankName,
  2708. 'amount': record.amount,
  2709. 'preBalance': record.balance,
  2710. 'serviceFee': record.serviceFee,
  2711. 'actualPay': record.actualPay,
  2712. 'refunded': record.refunded,
  2713. 'statusText': translate_withdraw_state(record.status),
  2714. 'description': record.description,
  2715. 'withdrawalsDate': record.postTime.strftime("%Y-%m-%d %H:%M:%S")
  2716. }
  2717. )
  2718. @permission_required(ROLE.dealer)
  2719. def getDealerAutoWithdrawCode(request):
  2720. # type: (WSGIRequest)->JsonResponse
  2721. """
  2722. 经销商确认开启自动提现
  2723. :param request:
  2724. :return:
  2725. """
  2726. try:
  2727. phoneNumber = request.GET.get('phoneNumber', None)
  2728. if not phoneNumber:
  2729. return JsonErrorResponse(description=u'手机号码为空')
  2730. agent = Agent.get_agent(request.user.agentId)
  2731. productName = agent['productName']
  2732. status, msg = dealerAutoWithdrawSMSProvider.get(phoneNumber=phoneNumber,
  2733. productName=productName,
  2734. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  2735. if not status:
  2736. return JsonErrorResponse(description=msg)
  2737. else:
  2738. return JsonOkResponse()
  2739. except Exception as e:
  2740. logger.exception(e)
  2741. return JsonErrorResponse()
  2742. #### `Utils related` ###########################################################
  2743. @permission_required(ROLE.dealer, ROLE.subaccount)
  2744. def deviceMem(request):
  2745. # type: (WSGIRequest)->JsonResponse
  2746. logicalCode = request.GET.get('logicalCode')
  2747. if not logicalCode:
  2748. return JsonErrorResponse(description=u'未提供设备逻辑编码')
  2749. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  2750. dev = Device.get_dev(devNo)
  2751. return JsonResponse(dev)
  2752. @permission_required(ROLE.dealer, ROLE.subaccount)
  2753. def deviceInfo(request):
  2754. # type: (WSGIRequest)->JsonResponse
  2755. logicalCode = request.GET.get('logicalCode', '')
  2756. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  2757. dev = Device.get_dev(devNo)
  2758. if dev is None:
  2759. return JsonErrorResponse(description=u'设备不存在')
  2760. return JsonResponse(MessageSender.send(dev, DeviceCmdCode.GET_DEVINFO, {'IMEI': devNo}))
  2761. @permission_required(ROLE.dealer, ROLE.subaccount)
  2762. def getServiceInfo(request):
  2763. # type: (WSGIRequest)->JsonResponse
  2764. currentDealer = request.user.myBoss # type: Optional[Dealer]
  2765. if not currentDealer:
  2766. return JsonResponse({"result": 0, "description": u"没有找到经销商"})
  2767. value = {
  2768. "qrcodeUrl": currentDealer.qrcodeUrl,
  2769. "serviceName": currentDealer.serviceName,
  2770. "servicePhone": currentDealer.servicePhone
  2771. }
  2772. return JsonResponse({"result": 1, "description": "", 'payload': value})
  2773. @permission_required(ROLE.dealer)
  2774. def saveServiceInfo(request):
  2775. # type: (WSGIRequest)->JsonResponse
  2776. ownerId = request.user.bossId # type: ObjectId
  2777. qrcodeUrl = request.POST.get('qrcodeUrl')
  2778. serviceName = request.POST.get('serviceName')
  2779. if serviceName:
  2780. if NAME_RE.match(serviceName) is None:
  2781. logger.error('name formatting error, name=%s' % serviceName)
  2782. return JsonResponse({"result": 0, "description": u"请输入正确格式的名称, 2-20位"})
  2783. servicePhone = request.POST.get('servicePhone')
  2784. if servicePhone:
  2785. if PHONE_NUMBER_RE.match(servicePhone) is None:
  2786. logger.error('phone number format error, phone=%s' % servicePhone)
  2787. return JsonResponse({"result": 0, "description": u"请输入正确的手机号码"})
  2788. status, desc = dealerRegisterSMSProvider.verify(servicePhone, request.POST.get('code'))
  2789. if not status:
  2790. return JsonErrorResponse(desc)
  2791. result = Dealer.update_dealer(ownerId, qrcodeUrl=qrcodeUrl, serviceName=serviceName, servicePhone=servicePhone)
  2792. if not result:
  2793. return JsonResponse({"result": 0, "description": u"更新经销商服务信息错误"})
  2794. return JsonResponse({"result": 1, "description": "", 'payload': {}})
  2795. # : 报告老板
  2796. @permission_required(ROLE.dealer, ROLE.subaccount)
  2797. def userFeedbackRecords(request):
  2798. # type: (WSGIRequest)->JsonResponse
  2799. """
  2800. 获取用户反馈记录
  2801. :param request:
  2802. :return:
  2803. """
  2804. ownerId = str(request.user.bossId)
  2805. searchKey = request.GET.get('searchKey', '')
  2806. feedType = request.GET.get('feedType', '')
  2807. pageIndex = int(request.GET.get('pageIndex', '1'))
  2808. pageSize = int(request.GET.get('pageSize', '10'))
  2809. status = request.GET.get('status', None)
  2810. if status and status != 'null':
  2811. status = int(status)
  2812. else:
  2813. status = None
  2814. dateStart = request.GET.get('dateStart', '')
  2815. if dateStart == '':
  2816. startTime = '2000-01-01 00:00:00'
  2817. else:
  2818. startTime = dateStart + " 00:00:00"
  2819. dateEnd = request.GET.get('dateEnd', '')
  2820. if dateEnd == '':
  2821. endTime = '2100-01-01 00:00:00'
  2822. else:
  2823. endTime = dateEnd + " 23:59:59"
  2824. query = {
  2825. 'ownerId': str(ownerId),
  2826. '$and': [
  2827. {
  2828. 'createTime': {
  2829. '$gte': startTime
  2830. }
  2831. },
  2832. {
  2833. 'createTime': {
  2834. '$lte': endTime
  2835. }
  2836. },
  2837. ],
  2838. }
  2839. if feedType:
  2840. if feedType == 'other':
  2841. feed_type_list = ['refund', 'upper']
  2842. query.update({
  2843. 'feedType': {'$in': feed_type_list},
  2844. 'consumeRecordOrderNo': {'$in': [None, '']}
  2845. })
  2846. else:
  2847. feed_type_list = [feedType]
  2848. query.update({
  2849. 'feedType': {'$in': feed_type_list}
  2850. })
  2851. if status is not None:
  2852. query.update({
  2853. 'status': status
  2854. })
  2855. results = FeedBack.objects(__raw__ = query).search(searchKey).order_by('-createTime')
  2856. total = results.count()
  2857. rv = []
  2858. for item in results.paginate(pageIndex, pageSize): # type: FeedBack
  2859. rv.append(item.summary)
  2860. data = {'page': pageIndex, 'total': total, 'pageSize': pageSize, 'items': rv}
  2861. return JsonResponse({'result': 1, 'description': "", 'payload': data})
  2862. @permission_required(ROLE.dealer, ROLE.subaccount)
  2863. def userFeedbackInfo(request):
  2864. # type: (WSGIRequest)->JsonResponse
  2865. fdId = str(request.GET.get('id'))
  2866. fd = FeedBack.objects(id = fdId).first() # type: FeedBack
  2867. if not fd:
  2868. return JsonResponse({'result': 0, 'description': u"投诉订单不存在,请刷新页面重试", 'payload': {}})
  2869. else:
  2870. return JsonResponse({'result': 1, 'description': "", 'payload': fd.detail})
  2871. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'处理失败'))
  2872. @permission_required(ROLE.dealer, ROLE.subaccount)
  2873. def userFeedbackHandle(request):
  2874. # type: (WSGIRequest)->JsonResponse
  2875. """
  2876. :param request:
  2877. :return:
  2878. """
  2879. payload = json.loads(request.body) if request.body else {}
  2880. if not payload:
  2881. return JsonErrorResponse(description = u'传入数据为空')
  2882. action = payload.get('action')
  2883. if not action:
  2884. return JsonOkResponse()
  2885. dealerRemark = payload.get('dealerRemark', u'(未填写回复内容)')
  2886. dealerImgList = payload.get('dealerImgList', [])
  2887. options = {} if dealerRemark is None else {'dealerRemark': dealerRemark, 'dealerImgList': dealerImgList}
  2888. feedback = FeedBack.objects(id = payload['id']).first() # type: Optional[FeedBack]
  2889. if not feedback:
  2890. return JsonErrorResponse(description = u'没有找到该反馈单')
  2891. dealer = Dealer.objects(id = feedback.ownerId).first() # type: Optional[Dealer]
  2892. if not dealer:
  2893. return JsonErrorResponse(description = u'未找到该反馈单的经销商')
  2894. feedType = feedback.feedType
  2895. if feedback.my_logicalCode:
  2896. device = Device.objects(logicalCode = feedback.my_logicalCode).first() # type: Optional[Device]
  2897. else:
  2898. device = None
  2899. if not device:
  2900. return JsonErrorResponse(description = u'找不到相关设备')
  2901. wechat_mp_proxy = get_wechat_user_manager_mp_proxy(dealer) # type: WechatClientProxy
  2902. user = MyUser.objects(openId = feedback.openId, groupId = feedback.my_group_id).first() # type: Optional[MyUser]
  2903. if not user:
  2904. logger.warning('user<openId={}> not exists for feedback<id={}>'.format(feedback.openId, str(feedback.id)))
  2905. if action in ['close', 'reject']:
  2906. feedback.handle(action, **options)
  2907. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2908. 'title': u'您反馈的问题已经处理' if action == 'close' else u'您反馈的问题已经被驳回',
  2909. 'event': '%s:%s' % (feedback.message_type, feedback.description),
  2910. 'remark': '%s: %s' % (u'设备老板回复', dealerRemark),
  2911. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2912. }) if user else None
  2913. return JsonOkResponse()
  2914. elif action == 'stop':
  2915. assert feedType == 'fault', u'投诉类型错误'
  2916. device.set_fault()
  2917. feedback.handle(action, **options)
  2918. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2919. 'title': u'您反馈的问题已经处理',
  2920. 'event': u'设备已经暂停使用,等待维修中',
  2921. 'remark': '%s: %s' % (u'设备老板回复', dealerRemark),
  2922. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2923. }) if user else None
  2924. return JsonResponse({'result': 1, 'description': "", 'payload': {}})
  2925. elif action == 'refund':
  2926. if not user:
  2927. return JsonErrorResponse(description = u'用户不存在,无法派币')
  2928. agent = Agent.objects.get(id = request.user.agentId)
  2929. if 'coinIsMoney' in agent.features:
  2930. return JsonResponse({'result': 2, 'description': u"代理商的配置,不允许给用户派币", 'payload': {}})
  2931. refundCoins = VirtualCoin(payload.get('refundCoins'))
  2932. if refundCoins > VirtualCoin(0):
  2933. inced = user.incr_balance(refundCoins)
  2934. if not inced:
  2935. logger.error('failed to incr balance for %r' % (user,))
  2936. return JsonErrorResponse(description = u'退币失败')
  2937. RechargeRecord.from_feedback(feedback, refundCoins).save()
  2938. feedback.handle(action, **options)
  2939. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2940. 'title': u'您反馈的问题已经处理',
  2941. 'event': u'%s:%s' % (feedback.message_type, feedback.description),
  2942. 'remark': '%s: %s' % (u'设备老板回复', dealerRemark),
  2943. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2944. }) if user else None
  2945. return JsonOkResponse()
  2946. else:
  2947. logger.warning('invalid action<value={}> for feedback<id=>'.format(action, str(feedback.id)))
  2948. return JsonOkResponse()
  2949. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'处理失败'))
  2950. @permission_required(ROLE.dealer, ROLE.subaccount)
  2951. def userFeedbackBatchHandle(request):
  2952. # type: (WSGIRequest)->JsonResponse
  2953. """
  2954. :param request:
  2955. :return:
  2956. """
  2957. payload = json.loads(request.body) if request.body else {}
  2958. if not payload:
  2959. return JsonErrorResponse(description = u'传入数据为空')
  2960. dealerRemark = payload.get('dealerRemark')
  2961. options = {} if dealerRemark is None else {'dealerRemark': dealerRemark}
  2962. feedbacks = FeedBack.objects(id__in = payload['ids'])
  2963. if feedbacks.count() == 0:
  2964. return JsonErrorResponse(description = u'没有找到反馈单')
  2965. for feedback in feedbacks:
  2966. feedback.handle('close', **options)
  2967. dealer = Dealer.objects(id = feedback.ownerId).first() # type: Optional[Dealer]
  2968. if not dealer:
  2969. logger.warning(
  2970. 'not find this dealer<id={}> for feedback<id={}>'.format(feedback.ownerId, str(feedback.id)))
  2971. continue
  2972. wechat_mp_proxy = get_wechat_user_manager_mp_proxy(dealer) # type: WechatClientProxy
  2973. user = MyUser.objects(openId = feedback.openId, groupId = feedback.my_group_id).first() # type: Optional[MyUser]
  2974. if not user:
  2975. logger.warning(
  2976. 'not find this user<openId={}> for feedback<id={}>'.format(feedback.openId, str(feedback.id)))
  2977. continue
  2978. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2979. 'title': u'您反馈的问题已经处理',
  2980. 'event': '%s:%s' % (feedback.message_type, feedback.description),
  2981. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2982. })
  2983. return JsonOkResponse()
  2984. @error_tolerate(nil=DefaultJsonErrorResponse)
  2985. @permission_required(ROLE.dealer, ROLE.subaccount)
  2986. def getCustomerDetailInfo(request):
  2987. # type: (WSGIRequest)->JsonResponse
  2988. """
  2989. 获取用户部分详细信息,如累计充值
  2990. :param request:
  2991. :return:
  2992. """
  2993. customerOpenId = request.GET.get('id')
  2994. if not customerOpenId:
  2995. return JsonErrorResponse(description=u'传入用户ID为空,无法获取详情')
  2996. ownerId = request.user.bossId
  2997. groupIds = list(set(Group.get_group_ids_of_dealer_and_partner(ownerId)))
  2998. users = MyUser.get_collection().find({"openId": customerOpenId, "groupId": {"$in": groupIds}})
  2999. rechargeTotal = RMB(0)
  3000. bestowTotal = RMB(0)
  3001. consumptionTotal = RMB(0)
  3002. balance = RMB(0)
  3003. nickname = ""
  3004. phone = ""
  3005. openId = ""
  3006. idStr = ""
  3007. breakRuleTimes = 0
  3008. orderRemindType = 2
  3009. for user in users:
  3010. nickname = user.get('nickname', "")
  3011. balance += (RMB(user.get("chargeBalance", 0)) + RMB(user.get("bestowBalance", 0)))
  3012. rechargeTotal += RMB(user.get("total_recharged", 0))
  3013. bestowTotal += RMB(user.get("total_bestow", 0))
  3014. consumptionTotal += RMB(user.get("total_consumed", 0))
  3015. openId = user.get("openId", "")
  3016. idStr = str(user.get('_id', ''))
  3017. if user.get('blacklistConfig', {}).get('orderRemindType', 2) != 2:
  3018. orderRemindType = user['blacklistConfig']['orderRemindType']
  3019. if user.get('blacklistConfig', {}).get('breakRuleTimes', 0) != 0:
  3020. breakRuleTimes = user['blacklistConfig']['breakRuleTimes']
  3021. if breakRuleTimes > 0 and orderRemindType != 0:
  3022. orderRemindType = 0
  3023. us = MyUser.objects(openId=user['openId'], groupId__in=groupIds)
  3024. for _ in us:
  3025. _.blacklistConfig['orderRemindType'] = orderRemindType
  3026. _.save()
  3027. status = "black" if check_black_user(dealerId=str(ownerId), openId=openId) else "white"
  3028. if idStr:
  3029. user = MyUser.objects.filter(id=idStr).first()
  3030. phone = user.phone
  3031. return JsonResponse({
  3032. 'result': 1,
  3033. 'description': None,
  3034. 'payload': {
  3035. 'balance': balance,
  3036. 'nickname': nickname,
  3037. 'phone': phone,
  3038. 'rechargeTotal': rechargeTotal,
  3039. 'consumptionTotal': consumptionTotal,
  3040. 'status': status,
  3041. 'breakRuleTimes': breakRuleTimes,
  3042. 'orderRemindType': orderRemindType
  3043. }
  3044. })
  3045. @error_tolerate(nil=DefaultJsonErrorResponse)
  3046. @permission_required(ROLE.dealer, ROLE.subaccount)
  3047. def getCustomerListUnderDealer(request):
  3048. """ 获取经销商名下的用户 按照openId做归并 查询需要根据特性来决定是否做手机号码查询"""
  3049. pageIndex = int(request.GET.get('pageIndex', 1))
  3050. pageSize = int(request.GET.get('pageSize', 10))
  3051. searchKey = request.GET.get('searchKey', "")
  3052. sortKey = request.GET.get('sortName', 'last_login')
  3053. sortOrder = request.GET.get('sortType', 'des')
  3054. isNew = True if request.GET.get('isNew', 'false') == 'true' else False
  3055. ownerId = request.user.bossId
  3056. groupIds = Group.get_group_ids_of_dealer_and_partner(ownerId=ownerId)
  3057. # 获取用户默认头像
  3058. default_avatar = Agent.get_agent(request.user.agentId).get("productLogo")
  3059. sortFilters = True if sortOrder == "des" else False
  3060. groupFilters = {
  3061. "_id": "$openId",
  3062. "chargeBalance": {"$sum": "$chargeBalance"},
  3063. "bestowBalance": {"$sum": "$bestowBalance"},
  3064. "total_recharged": {"$sum": "$total_recharged"},
  3065. "total_bestow": {"$sum": "$total_bestow"},
  3066. "total_consumed": {"$sum": "$total_consumed"},
  3067. "nickname": {"$first": "$nickname"},
  3068. "sex": {"$first": "$sex"},
  3069. "avatar": {"$first": "$avatar"},
  3070. "openId": {"$first": "$openId"},
  3071. "last_login": {"$max": "$last_login"}
  3072. }
  3073. matchFilters = {
  3074. "groupId": {"$in": groupIds}
  3075. }
  3076. by_phone = False
  3077. by_user_id = False
  3078. by_others = False
  3079. if re.match(r'1[3-9][0-9]{9}$', searchKey):
  3080. by_phone = True
  3081. elif re.match(r'^[0-9]{5,10}$', searchKey):
  3082. by_user_id = True
  3083. else:
  3084. by_others = True
  3085. # 符合手机号码的正则
  3086. if by_phone or by_user_id:
  3087. if by_phone:
  3088. agent = Agent.objects.filter(id = str(request.user.myBoss.agentId)).first() # type: Agent
  3089. if agent.supports('user_identify'):
  3090. user = MyUser.objects.filter(phoneNumber = searchKey).first()
  3091. else:
  3092. user = UniqueUser.objects.filter(phone = searchKey).first() # type: UniqueUser
  3093. else:
  3094. user = UniqueUser.objects.filter(userId=searchKey).first() # type: UniqueUser
  3095. if not user:
  3096. return JsonErrorResponse(description=u"未查询到该用户")
  3097. matchFilters.update({
  3098. 'openId': user.openId
  3099. })
  3100. else:
  3101. startTime = request.GET.get('startTime', None)
  3102. endTime = request.GET.get('endTime', None)
  3103. if startTime:
  3104. startDataTime = to_datetime(startTime + ' 00:00:00')
  3105. now = datetime.datetime.now()
  3106. if not endTime:
  3107. endDateTime = now + datetime.timedelta(days=1)
  3108. else:
  3109. endDateTime = to_datetime(endTime, "%Y-%m-%d")
  3110. if endDateTime > now:
  3111. endDateTime = now
  3112. endDateTime = endDateTime + datetime.timedelta(days=1)
  3113. if startDataTime >= endDateTime:
  3114. endDateTime = startDataTime + datetime.timedelta(days=1)
  3115. timeFilters = {
  3116. "$gte": startDataTime,
  3117. "$lt": endDateTime
  3118. }
  3119. if isNew:
  3120. timeKey = "dateTimeAdded"
  3121. else:
  3122. timeKey = "last_login"
  3123. matchFilters.update({
  3124. timeKey: timeFilters
  3125. })
  3126. if searchKey:
  3127. matchFilters.update({
  3128. "nickname": {"$regex": "%s" % searchKey}
  3129. })
  3130. users = MyUser.get_collection().aggregate([
  3131. {"$match": matchFilters},
  3132. {"$group": groupFilters},
  3133. ])
  3134. totalUsers = list(users)
  3135. if sortKey == "last_login":
  3136. totalUsers.sort(key=lambda x: x.get(sortKey), reverse=sortFilters)
  3137. else:
  3138. totalUsers.sort(key=lambda x: VirtualCoin(x.get(sortKey)), reverse=sortFilters)
  3139. tempUsers = totalUsers[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  3140. for user in tempUsers:
  3141. if not user["avatar"]: user["avatar"] = default_avatar
  3142. if 'total_recharged' in user:
  3143. user['total_recharged'] = RMB(user['total_recharged'])
  3144. if 'total_consumed' in user:
  3145. user['total_consumed'] = RMB(user['total_consumed'])
  3146. if 'chargeBalance' or 'bestowBalance' in user:
  3147. user["chargeBalance"] = RMB(user.get("chargeBalance", 0))
  3148. user["bestowBalance"] = RMB(user.get("bestowBalance", 0))
  3149. user['balance'] = user['chargeBalance'] + user['bestowBalance']
  3150. return JsonResponse({
  3151. "result": 1,
  3152. "description": None,
  3153. "payload": {
  3154. "total": len(totalUsers),
  3155. "dataList": tempUsers
  3156. }
  3157. })
  3158. @error_tolerate(nil=DefaultJsonErrorResponse)
  3159. @permission_required(ROLE.dealer, ROLE.subaccount)
  3160. def getRechargeRecordByCustomer(request):
  3161. # type: (WSGIRequest)->JsonResponse
  3162. """
  3163. 由用户详情 查询用户的充值记录
  3164. :param request:
  3165. :return:
  3166. """
  3167. pageIndex = int(request.GET.get("pageIndex"))
  3168. pageSize = int(request.GET.get("pageSize"))
  3169. openId = request.GET.get("id")
  3170. cardId = request.GET.get("cardTicketId") # 直接查看某一张虚拟卡的充值记录
  3171. startTime = request.GET.get('startTime', Const.QUERY_START_DATE)
  3172. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  3173. if cardId:
  3174. orderNoList = VirtualCardRechargeRecord.get_link_orderNo_list(
  3175. cardId = cardId, startTime = to_datetime(startTime, '%Y-%m-%d'), endTime = to_datetime(endTime, '%Y-%m-%d'))
  3176. queryFilter = {
  3177. 'orderNo__in': orderNoList
  3178. }
  3179. else:
  3180. queryFilter = {
  3181. 'ownerId__in': Dealer.get_cooperative_dealer_ids(str(request.user.bossId)),
  3182. "openId": openId,
  3183. "result": "success",
  3184. "via__in": map(format, [
  3185. USER_RECHARGE_TYPE.RECHARGE,
  3186. USER_RECHARGE_TYPE.RECHARGE_CARD,
  3187. USER_RECHARGE_TYPE.RECHARGE_VIRTUAL_CARD,
  3188. USER_RECHARGE_TYPE.RECHARGE_CASH,
  3189. USER_RECHARGE_TYPE.RECHARGE_MONTHLY_PACKAGE
  3190. ]),
  3191. 'hint': [("openId", 1)]
  3192. }
  3193. records = RechargeRecord.objects.filter(
  3194. dateTimeAdded__gte=to_datetime(startTime, '%Y-%m-%d'),
  3195. dateTimeAdded__lt=to_datetime(endTime, '%Y-%m-%d'),
  3196. **queryFilter
  3197. )
  3198. dataList = list()
  3199. for record in records.paginate(pageIndex, pageSize):
  3200. _data = {
  3201. "gateway": record.gateway or 'wechat',
  3202. "createdTime": record.created_date,
  3203. "totalFee": record.money,
  3204. "gatewayTradeNo": record.wxOrderNo,
  3205. "outTradeNo": record.orderNo,
  3206. "address": record.address,
  3207. "name": record.groupName,
  3208. "groupNumber": record.groupNumber,
  3209. "devTypeName": record.dev_type_name,
  3210. "logicalCode": record.logicalCode,
  3211. "isQuickPay": record.isQuickPay,
  3212. "result": getattr(record, "result", 'success'),
  3213. "description": getattr(record, "description", ''),
  3214. "via": record.via,
  3215. "coins": record.coins
  3216. }
  3217. if "refundOrder" in request.user.features:
  3218. _data["showRefund"] = (record.is_refund_available(request.user)) and (not record.has_refund_order)
  3219. dataList.append(_data)
  3220. total = pageIndex * pageSize if len(dataList) < pageSize else (pageIndex + 1) * pageSize
  3221. return JsonResponse({'result': 1, 'description': "", 'payload': {'dataList': dataList, 'total': total}})
  3222. @error_tolerate(nil=DefaultJsonErrorResponse)
  3223. @permission_required(ROLE.dealer, ROLE.subaccount)
  3224. def getConsumptionRecordByCustomer(request):
  3225. # type: (WSGIRequest)->JsonResponse
  3226. """
  3227. :param request:
  3228. :return:
  3229. """
  3230. pageIndex = int(request.GET.get("pageIndex", 1))
  3231. pageSize = int(request.GET.get("pageSize", 10))
  3232. openId = request.GET.get("id")
  3233. groupId = request.GET.get("groupId")
  3234. lastYear = datetime.date((datetime.date.today().year - 1), datetime.date.today().month,
  3235. datetime.date.today().day).strftime("%Y-%m-%d")
  3236. startTime = request.GET.get('startTime', lastYear)
  3237. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  3238. queryFilter = {"ownerId": str(request.user.bossId), "openId": openId}
  3239. if groupId:
  3240. queryFilter.update({"groupId": groupId})
  3241. records = ClientConsumeModelProxy.get_data_list(startTime=startTime, endTime=endTime, **queryFilter)
  3242. # 修改 列表仅仅展示基础数据 详细信息在详单中查询
  3243. dataList = []
  3244. for record in records.paginate(pageIndex, pageSize):
  3245. newData = {
  3246. "groupName": record.groupName,
  3247. "groupNumber": record.groupNumber,
  3248. "devTypeName": record.devTypeName,
  3249. "logicalCode": record.logicalCode,
  3250. "createdTime": record.dateTimeAdded,
  3251. "orderNo": record.orderNo,
  3252. "id": str(record.id),
  3253. "ownerId": record.ownerId
  3254. }
  3255. newData.update(record.service)
  3256. dev = Device.get_dev_by_logicalCode(record.logicalCode) # type: DeviceDict
  3257. if dev and dev.is_registered and dev.ownerId == record.ownerId:
  3258. if (record.devTypeCode or dev.devTypeCode) == Const.DEVICE_TYPE_CODE_HP_GATE: # 霍珀道闸分支
  3259. newData.update({'desc': record.servicedInfo.get('oper', u'未知')})
  3260. elif record.devTypeCode in support_policy_weifule + support_policy_device:
  3261. if record.status != ConsumeRecord.Status.FINISHED:
  3262. if (datetime.datetime.now() - record.dateTimeAdded).total_seconds() > 60 * 60 * 12:
  3263. newData.update({'desc': '超12小时未结束'})
  3264. if record.status == ConsumeRecord.Status.RUNNING:
  3265. newData.update({'showStopButton': True})
  3266. if record.status == ConsumeRecord.Status.END:
  3267. newData.update({'showStopButton': True})
  3268. else:
  3269. continue
  3270. dataList.append(newData)
  3271. total = pageIndex * pageSize if len(dataList) < pageSize else (pageIndex + 1) * pageSize
  3272. return JsonResponse({'result': 1, 'description': "", 'payload': {'dataList': dataList, 'total': total}})
  3273. @error_tolerate(nil=DefaultJsonErrorResponse)
  3274. @permission_required(ROLE.dealer, ROLE.subaccount)
  3275. def modifyCustomerBalance(request):
  3276. # type: (WSGIRequest)->JsonResponse
  3277. """
  3278. 给终端用户派币或扣币(通常情况不支持)
  3279. :param request:
  3280. :return:
  3281. """
  3282. currentDealer = request.user.myBoss # type: Optional[Dealer]
  3283. agent = Agent.objects.filter(id=str(currentDealer.agentId)).first() # type: Agent
  3284. if 'disable_dealer_onPoints_and_sendCoins' in agent.features:
  3285. return JsonResponse(
  3286. {'result': 0, 'description': '设备无法使用该功能奥, 如有问题, 请联系代理商', 'payload': {}})
  3287. payload = json.loads(request.body) if request.body else {}
  3288. if not payload: return JsonErrorResponse(description=u'传入数据为空')
  3289. coins = VirtualCoin(payload.get('coins', 0.0))
  3290. desc = payload.get('description')
  3291. customerOpenId = payload.get('userId')
  3292. groupId = payload.get('groupId')
  3293. ownerId = str(currentDealer.bossId)
  3294. operator = currentDealer.nickname
  3295. customer = MyUser.objects(groupId=groupId, openId=customerOpenId).first() # type: Optional[MyUser]
  3296. if not customer:
  3297. return JsonResponse({'result': 0, 'description': u'该用户不存在', 'payload': {}})
  3298. if coins < VirtualCoin(0) and -coins > customer.balance:
  3299. return JsonResponse({'result': 0, 'description': u'最多只能扣除掉%s个币' % customer.balance, 'payload': {}})
  3300. agent = Agent.objects.get(id=currentDealer.agentId)
  3301. if 'coinIsMoney' in agent.features:
  3302. return JsonResponse({'result': 0, 'description': u'代理商的配置,不允许给用户派币', 'payload': {}})
  3303. group = Group.get_group(groupId)
  3304. if group['ownerId'] != ownerId:
  3305. return JsonResponse({'result': 0, 'description': u'不是您家设备喔,不能派币', 'payload': {}})
  3306. payload = {
  3307. 'orderNo': str(uuid.uuid1()),
  3308. 'openId': customerOpenId,
  3309. 'coins': coins,
  3310. 'description': desc,
  3311. 'groupId': groupId,
  3312. 'groupName': group.groupName,
  3313. 'address': group.address,
  3314. 'ownerId': ownerId,
  3315. 'operator': operator,
  3316. 'result': 'success',
  3317. 'via': 'sendcoin'
  3318. }
  3319. record = RechargeRecord(**payload)
  3320. customer.recharge(RMB(0), RMB(coins))
  3321. record.save()
  3322. customer.account_recharge(record)
  3323. if coins > VirtualCoin(0):
  3324. try:
  3325. task_caller(
  3326. 'report_to_user_via_wechat', openId=customerOpenId,
  3327. dealerId=str(request.user.bossId),
  3328. templateName='refund_coins', **{
  3329. 'title': u'尊敬的客户,已经退回%s金币到您的余额,您下次可以接着使用。祝您生活愉快。' % coins,
  3330. 'backCount': u'金币:%s' % coins,
  3331. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  3332. }
  3333. )
  3334. except Exception as e:
  3335. logger.exception(e)
  3336. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  3337. @error_tolerate(nil=DefaultJsonErrorResponse)
  3338. @permission_required(ROLE.dealer, ROLE.subaccount)
  3339. def getModifyCustomerBalanceRecord(request):
  3340. # type: (WSGIRequest)->JsonResponse
  3341. """
  3342. 获取派币记录
  3343. :param request:
  3344. :return:
  3345. """
  3346. pageIndex = int(request.GET.get('pageIndex', 1))
  3347. pageSize = int(request.GET.get('pageSize', 10))
  3348. customerOpenId = request.GET.get('id', None)
  3349. user = MyUser.objects(openId=customerOpenId).first()
  3350. if not user:
  3351. records = RechargeRecord.objects(
  3352. ownerId=str(request.user.bossId),
  3353. via='sendcoin').order_by('-dateTimeAdded').skip((pageIndex - 1) * pageSize).limit(pageSize)
  3354. else:
  3355. records = RechargeRecord.objects(
  3356. ownerId=str(request.user.bossId),
  3357. openId=customerOpenId,
  3358. via='sendcoin').order_by('-dateTimeAdded').skip((pageIndex - 1) * pageSize).limit(pageSize)
  3359. dataList = []
  3360. if not user:
  3361. for r in records:
  3362. u = MyUser.objects(openId=r.openId).first()
  3363. if u is None:
  3364. logger.error('invalid openId, openId=%s' % r.openId)
  3365. continue
  3366. dataList.append({
  3367. 'name': u.nickname if u.nickname is not None else '',
  3368. 'avatar': u.avatar,
  3369. 'id': customerOpenId,
  3370. 'remarks': r.my_description,
  3371. 'operator': r.operator,
  3372. 'coins': r.coins,
  3373. 'groupName': r.groupName,
  3374. 'createdTime': r.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  3375. })
  3376. else:
  3377. dataList = [
  3378. {
  3379. 'name': user.nickname if user.nickname is not None else '',
  3380. 'avatar': user.avatar,
  3381. 'id': customerOpenId,
  3382. 'remarks': r.my_description,
  3383. 'operator': r.operator,
  3384. 'coins': r.coins,
  3385. 'groupName': r.groupName,
  3386. 'createdTime': r.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  3387. } for r in records
  3388. ]
  3389. count = records.count()
  3390. if count <= pageSize:
  3391. total = (pageIndex - 1) * pageSize + count
  3392. else:
  3393. total = (pageIndex - 1) * pageSize + 100
  3394. return JsonResponse(
  3395. {
  3396. 'result': 1,
  3397. 'description': None,
  3398. 'payload':
  3399. {
  3400. 'dataList': paginate(dataList, pageIndex, pageSize),
  3401. 'total': total,
  3402. 'sendCoinsTotal': VirtualCoin(records.sum('coins'))
  3403. }
  3404. }
  3405. )
  3406. # 导出派币记录
  3407. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取派币记录失败"))
  3408. @permission_required(ROLE.dealer)
  3409. def reportModifyCustomerBalanceRecord(request):
  3410. """
  3411. 导出派币记录
  3412. """
  3413. dealer = request.user
  3414. def get_offline_task_name(task_type, user, **kwargs):
  3415. # type: (basestring, Dealer, Dict)->basestring
  3416. tmp_list = [task_type, user.username]
  3417. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  3418. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  3419. if 'groupId' in kwargs and kwargs['groupId']:
  3420. address = Group.get_group(kwargs['groupId']).get('address', '')
  3421. tmp_list.append(u'地址_%s' % (address,))
  3422. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  3423. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  3424. return '-'.join(tmp_list).replace("/", "_")
  3425. query_dict = {
  3426. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  3427. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  3428. 'pageIndex': int(request.GET.get('pageIndex', 1)),
  3429. 'pageSize': int(request.GET.get('pageSize', 10)),
  3430. 'customerOpenId': request.GET.get('id', None),
  3431. "ownerId": str(request.user.bossId),
  3432. }
  3433. offline_task_name = get_offline_task_name(
  3434. task_type=u'地址用户充值消费情况统计报表',
  3435. user=dealer,
  3436. **query_dict)
  3437. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  3438. process_func_name='export_modify_customer_balance_record_excel_from_db',
  3439. task_type=OfflineTaskType.BUSINESS_REPORT,
  3440. userid=str(dealer.id),
  3441. role=ROLE.dealer)
  3442. task_caller(func_name=offline_task.process_func_name,
  3443. offline_task_id=str(offline_task.id),
  3444. filepath=file_path,
  3445. queryDict=query_dict)
  3446. return JsonResponse({
  3447. 'result': 1,
  3448. 'description': u"请前往离线任务查看任务处理情况",
  3449. 'payload': str(offline_task.id)})
  3450. @error_tolerate(nil=DefaultJsonErrorResponse)
  3451. @permission_required(ROLE.dealer, ROLE.subaccount)
  3452. def getRefundRecord(request):
  3453. # type: (WSGIRequest)->JsonResponse
  3454. """
  3455. 获取退币记录
  3456. :param request:
  3457. :return:
  3458. """
  3459. pageIndex = int(request.GET.get('pageIndex', 1))
  3460. pageSize = int(request.GET.get('pageSize', 10))
  3461. customerOpenId = request.GET.get('id', None)
  3462. if not customerOpenId:
  3463. return JsonErrorResponse(description=u'提交的用户id为空')
  3464. user = MyUser.objects(openId=customerOpenId).first().to_dict()
  3465. records = RechargeRecord.objects(ownerId=str(request.user.bossId), openId=customerOpenId, via='refund').order_by("-dateTimeAdded")
  3466. dealer = Dealer.objects(id=str(request.user.bossId)).get()
  3467. dataList = [
  3468. {
  3469. 'name': user['nickname'],
  3470. 'avatar': user['avatar'],
  3471. 'id': customerOpenId,
  3472. 'description': r.my_description,
  3473. 'operator': dealer.nickname,
  3474. 'coins': r.coins,
  3475. 'groupName': r.groupName,
  3476. 'createdTime': r.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  3477. } for r in records
  3478. ]
  3479. total = records.count()
  3480. return JsonResponse(
  3481. {
  3482. 'result': 1,
  3483. 'description': None,
  3484. 'payload':
  3485. {
  3486. 'dataList': paginate(dataList, pageIndex, pageSize),
  3487. 'total': total,
  3488. 'refundTotal': VirtualCoin(records.sum('coins'))
  3489. }
  3490. }
  3491. )
  3492. @error_tolerate(nil=DefaultJsonErrorResponse)
  3493. @permission_required(ROLE.dealer, ROLE.subaccount)
  3494. def payGateway(request):
  3495. # type: (WSGIRequest)->JsonResponse
  3496. current_user = request.user # type: Dealer
  3497. try:
  3498. # TODO # 此处流量卡传的是param 其他 加盟 api支付的都是传 params
  3499. payload = json.loads(request.GET.get('param') or request.GET.get('params'))
  3500. order_no = payload.get('orderNo')
  3501. if not order_no:
  3502. return JsonErrorResponse(u'参数错误,请刷新后再试')
  3503. record = DealerRechargeRecord.objects(orderNo=order_no).first() # type: DealerRechargeRecord
  3504. if not record:
  3505. return JsonErrorResponse(u'订单不存在,请刷新后再试')
  3506. payment_gateway = PaymentGateway.from_gateway_key(
  3507. record.gateway,
  3508. record.payGatewayKey,
  3509. record.payAppType) # type: Optional[WechatPaymentGateway]
  3510. logger.info('dealer wechat charge: gateway = %s; orderNo = %s, totalFee = %s' % (
  3511. repr(payment_gateway), order_no, record.totalFee))
  3512. OrderCacheMgr(record).initial()
  3513. attach = {'dealerId': record.dealerId}
  3514. body = record.get_body()
  3515. # 转成以元为单位的钱,后面流程统一处理
  3516. money = RMB(record.totalFee) * Decimal('0.01')
  3517. if payment_gateway.pay_app_type == PayAppType.WECHAT:
  3518. data = payment_gateway.generate_js_payment_params(
  3519. payOpenId=payload.get('openId'),
  3520. out_trade_no=order_no,
  3521. notify_url=PAY_NOTIFY_URL.WECHAT_PAY_BACK,
  3522. money=money,
  3523. body=body,
  3524. attach=attach)
  3525. data.update({
  3526. 'outTradeNo': record.orderNo, 'adShow': current_user.ad_show
  3527. })
  3528. response = JsonResponse({'result': 1, 'description': '', 'payload': data})
  3529. else:
  3530. raise Exception(cn(u'不支持该支付类型'))
  3531. task_caller(func_name='poll_dealer_recharge_record',
  3532. delay=PollRecordDefine.DELAY_BEFORE,
  3533. expires=PollRecordDefine.TASK_EXPIRES,
  3534. record_id=str(record.id),
  3535. pay_app_type=payment_gateway.pay_app_type,
  3536. interval=PollRecordDefine.WAIT_EACH_ROUND,
  3537. total_count=PollRecordDefine.TOTAL_ROUNDS)
  3538. return response
  3539. except WeChatException as e:
  3540. logger.exception(e)
  3541. return JsonErrorResponse(description = e.tip)
  3542. except Exception as e:
  3543. logger.exception(e)
  3544. return JsonErrorResponse(description=u'系统开小差了,请刷新后再试')
  3545. @error_tolerate(nil=DefaultJsonErrorResponse)
  3546. @permission_required(ROLE.dealer, ROLE.subaccount)
  3547. def getDeviceCardList(request):
  3548. # type: (WSGIRequest)->JsonResponse
  3549. def cmp_expire_time(x, y):
  3550. if not x['simExpireDate']:
  3551. return 1
  3552. if not y['simExpireDate']:
  3553. return -1
  3554. if x['simExpireDate'] > y['simExpireDate']:
  3555. return -1
  3556. elif x['simExpireDate'] < y['simExpireDate']:
  3557. return 1
  3558. else:
  3559. return 0
  3560. searchKey = request.GET.get('searchKey', '')
  3561. dealerId = str(request.user.bossId)
  3562. agent = Agent.objects(id=request.user.agentId).first() # type: Optional[Agent]
  3563. if not agent:
  3564. logger.error('agent<id={}> is not exist.'.format(request.user.agentId))
  3565. return JsonErrorResponse(description=u'系统错误')
  3566. groupIds = Group.get_group_ids_of_dealer(dealerId)
  3567. groupDict = Group.get_groups_by_group_ids(groupIds)
  3568. devNoList = Device.get_devNos_by_group(groupIds)
  3569. devices = Device.get_dev_by_nos(devNoList).values()
  3570. annualTrafficCost = request.user.annualTrafficCost
  3571. devList = []
  3572. for dev in devices: # type: DeviceDict
  3573. try:
  3574. if searchKey in dev['groupNumber'] or searchKey in dev.devNo or searchKey in dev[
  3575. 'remarks'] or searchKey in dev.logicalCode:
  3576. group = groupDict.get(dev.groupId)
  3577. if (settings.DEBUG and dev.logicalCode.startswith('DUMMY')) or dev.is_expired or dev.sim_expire_notify:
  3578. item = {
  3579. 'logicalCode': dev.logicalCode,
  3580. 'devNo': dev.devNo,
  3581. 'devTypeName': dev.devType['name'],
  3582. 'groupName': group['groupName'],
  3583. 'groupNumber': dev['groupNumber'],
  3584. 'groupId': group['groupId'],
  3585. 'simExpireDate': dev.fixedSimExpireDate,
  3586. 'channelType': dev.channelType
  3587. }
  3588. devList.append(item)
  3589. except Exception, e:
  3590. logger.exception('[device]some error=%s' % e)
  3591. continue
  3592. devList.sort(cmp=cmp_expire_time)
  3593. pageIndex = int(request.GET.get('pageIndex', 1))
  3594. pageSize = int(request.GET.get('pageSize', 100))
  3595. items = devList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  3596. devObjs = { obj.devNo: obj for obj in Device.objects.filter(devNo__in=[item['devNo'] for item in items])}
  3597. for item in items:
  3598. dev_obj = devObjs[item['devNo']] # type: Device
  3599. trafficCardCost = dev_obj.trafficCardCost
  3600. if not trafficCardCost:
  3601. if request.user.trafficCardCost:
  3602. trafficCardCost = request.user.trafficCardCost
  3603. else:
  3604. trafficCardCost = agent.trafficCardCost
  3605. item['price'] = trafficCardCost if trafficCardCost > annualTrafficCost else annualTrafficCost
  3606. items = sorted(items, key=lambda x:x['groupId'])
  3607. return JsonResponse({
  3608. 'result': 1,
  3609. 'description': None,
  3610. 'payload': {'page': pageIndex, 'total': len(devList), 'pageSize': pageSize, 'offset': 0,
  3611. 'items': items}
  3612. })
  3613. @error_tolerate(nil=DefaultJsonErrorResponse)
  3614. @permission_required(ROLE.dealer, ROLE.subaccount)
  3615. def getSimRechargeOrderList(request):
  3616. # type: (WSGIRequest)->JsonResponse
  3617. filterQuery = Q(
  3618. __raw__ = {
  3619. 'dealerId': str(request.user.bossId),
  3620. 'product': {'$in': [DealerRechargeRecord.ProductType.SimCard, DealerRechargeRecord.ProductType.AutoSimCard]}
  3621. })
  3622. status = request.GET.get('status', None)
  3623. if status:
  3624. filterQuery &= Q(__raw__={'status': status})
  3625. else:
  3626. filterQuery &= Q(
  3627. __raw__={'status': {'$nin': [DealerRechargeRecord.PayState.Cancel, DealerRechargeRecord.PayState.Close]}})
  3628. searchKey = request.GET.get('searchKey', '')
  3629. if searchKey:
  3630. pattern = Regex.from_native(re.compile('.*' + searchKey + '.*'))
  3631. filterQuery &= (Q(__raw__={'items': {'$elemMatch': {'name': {'$regex': pattern}}}}) | Q(
  3632. __raw__={'orderNo': {"$regex": pattern}}))
  3633. records = DealerRechargeRecord.objects(
  3634. __raw__=filterQuery.to_query(DealerRechargeRecord)).order_by("-createdTime")
  3635. items = []
  3636. for record in records: # type: DealerRechargeRecord
  3637. item = {
  3638. 'name': record.name,
  3639. 'totalFee': str(RMB(float(record['totalFee']) / 100)),
  3640. 'orderNo': record.orderNo,
  3641. 'status': record.status,
  3642. 'createdTime': record.createdTime,
  3643. 'finishedTime': record.finishedTime
  3644. }
  3645. items.append(item)
  3646. pageIndex = int(request.GET.get('pageIndex', 1))
  3647. pageSize = int(request.GET.get('pageSize', 10))
  3648. return JsonResponse({
  3649. 'result': 1,
  3650. 'description': '',
  3651. 'payload': {
  3652. 'page': pageIndex, 'total': len(items), 'pageSize': pageSize, 'offset': 0,
  3653. 'items': items[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  3654. }
  3655. })
  3656. @error_tolerate(nil=DefaultJsonErrorResponse)
  3657. @permission_required(ROLE.dealer, ROLE.subaccount)
  3658. def createSimRechargeOrder(request):
  3659. # type: (WSGIRequest)->JsonResponse
  3660. current_user = request.user # type: Dealer
  3661. devNoList = set(request.POST.getlist('list[]'))
  3662. payment_gateway = get_inhourse_wechat_env_pay_gateway(
  3663. ROLE.dealer) # type: Union[WechatPaymentGateway]
  3664. record = create_dealer_sim_charge_order(payment_gateway, current_user, devNoList)
  3665. if record:
  3666. return JsonResponse({'result': 1, 'description': u'创建订单成功', 'payload': record.orderNo})
  3667. else:
  3668. return JsonErrorResponse(u'创建订单异常失败')
  3669. @error_tolerate(nil=DefaultJsonErrorResponse)
  3670. @permission_required(ROLE.dealer, ROLE.subaccount)
  3671. def cancelSimRechargeOrder(request):
  3672. # type: (WSGIRequest)->JsonResponse
  3673. try:
  3674. payload = json.loads(request.body) if request.body else {}
  3675. if not payload:
  3676. return JsonErrorResponse(description=u'数据不完整,请重试')
  3677. order_no = payload['orderNo']
  3678. order = DealerRechargeRecord.objects(orderNo=order_no).first() # type: DealerRechargeRecord
  3679. if not order:
  3680. return JsonErrorResponse(u'订单不存在,请刷新后再试')
  3681. if not order.is_unpay:
  3682. return JsonErrorResponse(u'订单已经处理,无法取消')
  3683. if order.cancel():
  3684. return JsonOkResponse('ok')
  3685. else:
  3686. return JsonErrorResponse(u'订单已经处理,无法取消')
  3687. except Exception as e:
  3688. logger.exception('unable to cancel dealer order, error=%s' % (e,))
  3689. return JsonErrorResponse(description=u"系统错误")
  3690. @error_tolerate(nil=DefaultJsonErrorResponse)
  3691. @permission_required(ROLE.dealer, ROLE.subaccount)
  3692. def getSimRechargeOrderDetail(request):
  3693. # type: (WSGIRequest)->JsonResponse
  3694. try:
  3695. orderNo = request.GET.get('orderNo')
  3696. order = DealerRechargeRecord.objects(orderNo = orderNo).first() # type: DealerRechargeRecord
  3697. if not order:
  3698. return JsonErrorResponse(u'订单不存在,请刷新后再试')
  3699. else:
  3700. return JsonResponse({'result': 1, 'description': '', 'payload':
  3701. {
  3702. 'orderNo': order.orderNo,
  3703. 'totalFee': '%.02f' % (float(order.totalFee) / 100),
  3704. 'status': order.status,
  3705. 'createdTime': order.createdTime,
  3706. 'items': order.items
  3707. }})
  3708. except Exception as e:
  3709. logger.exception('get dealer pay order list failure, error = %s' % (e,))
  3710. return JsonErrorResponse(description = u'查询订单失败')
  3711. @error_tolerate(nil=DefaultJsonErrorResponse)
  3712. def getOwnerAgents(request):
  3713. try:
  3714. username = request.GET.get('username')
  3715. managerId = request.GET.get('managerId')
  3716. logger.debug('getOwnerAgents: username = %s; managerId = %s' % (username, managerId))
  3717. agents = [str(a.id) for a in Agent.objects(managerId=str(managerId)).all()]
  3718. items = []
  3719. dealers = Dealer.get_collection().find({'username': username, 'agentId': {'$in': agents}})
  3720. for dealer in dealers:
  3721. agentId = dealer['agentId']
  3722. agent = Agent.get_agent(agentId)
  3723. item = {
  3724. 'agentId': agentId,
  3725. 'userHeadImg': agent['avatar'],
  3726. 'agentLogoUrl': agent['productLogo'],
  3727. 'agentBrandName': agent['productName'],
  3728. 'displayName': agent['productName']
  3729. }
  3730. items.append(item)
  3731. return JsonResponse({
  3732. 'result': 1,
  3733. 'description': None,
  3734. 'payload': {'total': len(items),
  3735. 'items': items}
  3736. })
  3737. except Exception as e:
  3738. logger.exception('get dealer owner agents failure, error = %s' % (e,))
  3739. return JsonErrorResponse(description=u'网络错误,请刷新后再试')
  3740. @error_tolerate(nil=DefaultJsonErrorResponse)
  3741. @permission_required(ROLE.dealer, ROLE.subaccount)
  3742. def getEquipmentTotal(request):
  3743. # type: (WSGIRequest)->JsonResponse
  3744. dealerId = str(request.user.bossId)
  3745. groupIds = Group.get_group_ids_of_dealer(dealerId)
  3746. devNoList = Device.get_devNos_by_group(groupIds)
  3747. return JsonResponse({'result': 1, 'description': '', 'payload': len(devNoList)})
  3748. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'设备类型不支持'))
  3749. @permission_required(ROLE.dealer, ROLE.subaccount)
  3750. def getPackageList(request):
  3751. # type: (WSGIRequest)->JsonResponse
  3752. devTypeId = request.GET.get('typeId', None)
  3753. if not devTypeId:
  3754. return JsonResponse({'result': 0, 'description': u'设备类型为空', 'payload': {}})
  3755. dealer = request.user.myBoss # type: Dealer
  3756. devType = DeviceType.objects.filter(id=str(devTypeId)).first() # type: DeviceType
  3757. if devType['code'] in support_policy_weifule + support_policy_device:
  3758. isTemp = request.GET.get('isTemp', None) == 'true'
  3759. from apps.web.core.models import DriverAdapter
  3760. adapter = DriverAdapter.get_driver_adapter(devType['code'], None)
  3761. if adapter.support_device_package:
  3762. payload = adapter.get_reg_model(dealer, devTypeId, isTemp=isTemp)
  3763. return JsonResponse({'result': 1, 'description': None, 'payload': payload})
  3764. dataList = {}
  3765. if devTypeId in dealer.defaultWashConfig:
  3766. dataList = dealer.defaultWashConfig[devTypeId]
  3767. if not dataList:
  3768. dataList = DeviceType.objects(id=str(devTypeId)).get().package
  3769. no_unit_list = filter(lambda x: x.get("unit") == None, dataList)
  3770. if len(no_unit_list) == len(dataList):
  3771. datalist = map(lambda x: (x.update({"unit": "分钟"}), x)[1], dataList)
  3772. displaySwitchs = {}
  3773. if hasattr(devType, "displayPriceSwitch"):
  3774. displaySwitchs.update({"displayPriceSwitch": devType.displayPriceSwitch})
  3775. if hasattr(devType, "displayCoinsSwitch"):
  3776. displaySwitchs.update({"displayCoinsSwitch": devType.displayCoinsSwitch})
  3777. if hasattr(devType, "displayTimeSwitch"):
  3778. displaySwitchs.update({"displayTimeSwitch": devType.displayTimeSwitch})
  3779. if hasattr(devType, "setPulseAble"):
  3780. displaySwitchs.update({"setPulseAble": devType.setPulseAble})
  3781. if hasattr(devType, "setBasePriceAble"):
  3782. displaySwitchs.update({"setBasePriceAble": devType.setBasePriceAble})
  3783. 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]:
  3784. displaySwitchs = {
  3785. 'displayPriceSwitch': True,
  3786. 'displayCoinsSwitch': False,
  3787. 'displayTimeSwitch': False,
  3788. 'setPulseAble': False,
  3789. 'setBasePriceAble': False,
  3790. }
  3791. return JsonResponse({'result': 1, 'description': None, 'payload': {'ruleList':dataList, 'displaySwitchs':displaySwitchs}})
  3792. # ## 经销商绑定微信(为了接受微信推送)
  3793. @permission_required(ROLE.dealer, ROLE.subaccount)
  3794. def getDealerBindWechatSMSCode(request):
  3795. # type: (WSGIRequest)->JsonResponse
  3796. """
  3797. :param request:
  3798. :return:
  3799. """
  3800. try:
  3801. phoneNumber = request.user.username
  3802. agent = Agent.get_agent(request.user.agentId)
  3803. productName = agent['productName']
  3804. if not phoneNumber:
  3805. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  3806. status, msg = dealerBindWechatSMSProvider.get(phoneNumber=phoneNumber,
  3807. productName=productName,
  3808. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  3809. if not status:
  3810. return JsonResponse({'result': 0, 'description': msg})
  3811. else:
  3812. return JsonResponse({'result': 1, 'description': ''})
  3813. except Exception, e:
  3814. logger.exception('unable to get %s' % e)
  3815. return JsonResponse({'result': 0, 'description': ''})
  3816. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误'))
  3817. @permission_required(ROLE.dealer, ROLE.subaccount)
  3818. def verifyNewWechatBinding(request):
  3819. # type: (WSGIRequest)->JsonResponse
  3820. """
  3821. 跳转到微信授权页面绑定
  3822. :param request:
  3823. :return:
  3824. """
  3825. currentDealer = request.user # type: cast(Dealer)
  3826. code = request.POST.get('code')
  3827. if not code:
  3828. return JsonErrorResponse(description=u'code未提供')
  3829. status, msg = dealerBindWechatSMSProvider.verify(phoneNumber=request.user.username, smsCode=code)
  3830. if not status:
  3831. return JsonErrorResponse(description=msg)
  3832. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_MANAGER)
  3833. return JsonResponse(
  3834. {
  3835. 'result': 1,
  3836. 'description': None,
  3837. 'payload': {
  3838. 'redirect_uri': auth_bridge.generate_auth_url_user_scope(
  3839. redirect_uri=DEALER_BIND_WECHAT_URL)
  3840. }
  3841. })
  3842. @error_tolerate(logger=logger, nil=DealerBindIdResponseRedirect(result='error'))
  3843. @permission_required(ROLE.dealer, ROLE.subaccount)
  3844. def verifyNewWechatBindingCallback(request):
  3845. # type: (WSGIRequest)->JsonResponse
  3846. """
  3847. 绑定后台openId
  3848. TODO: 加入变更记录
  3849. :param request:
  3850. :return:
  3851. """
  3852. auth_code = request.GET.get('code')
  3853. if not auth_code:
  3854. return JsonErrorResponse(description=u'未收到code,请刷新重试')
  3855. currentDealer = request.user # type: cast(Dealer)
  3856. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_MANAGER)
  3857. user_info = auth_bridge.get_user_info(auth_code=auth_code)
  3858. user_info_payload = {
  3859. 'avatar': user_info['avatar'],
  3860. 'country': user_info['country'],
  3861. 'province': user_info['province'],
  3862. 'city': user_info['city'],
  3863. 'sex': user_info['sex'],
  3864. 'nickname': user_info['nickname']
  3865. }
  3866. logger.debug('dealer(id=%s) is binding wechat for messaging, bridge=%s' % (str(request.user.bossId), auth_bridge))
  3867. dealerWechatBindingUpdated = request.user.update(
  3868. managerialAppId=auth_bridge.app.appid,
  3869. managerialOpenId=user_info['openId'],
  3870. wechatAuthUserInfo=user_info_payload,
  3871. managerialWechatBoundTime=datetime.datetime.now())
  3872. if dealerWechatBindingUpdated:
  3873. return DealerBindIdResponseRedirect(result='ok')
  3874. else:
  3875. return DealerBindIdResponseRedirect(result='error')
  3876. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误'))
  3877. @permission_required(ROLE.dealer, ROLE.subaccount)
  3878. def getBoundWechat(request):
  3879. # type: (WSGIRequest)->JsonResponse
  3880. """
  3881. 获取绑定后台openId的用户信息
  3882. :param request:
  3883. :return:
  3884. """
  3885. ownerId = str(request.user.bossId)
  3886. dealer = Dealer.objects(id=ownerId).get() # type: Dealer
  3887. return JsonResponse(
  3888. {
  3889. "result": 1,
  3890. "description": None,
  3891. 'payload': {
  3892. "bound": dealer.isManagerialOpenIdBound,
  3893. "avatar": dealer.wechatAuthUserInfo.get('avatar'),
  3894. "sex": dealer.wechatAuthUserInfo.get('sex'),
  3895. "nickname": dealer.wechatAuthUserInfo.get('nickname')
  3896. }
  3897. })
  3898. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  3899. def setAdShow(request):
  3900. # type: (WSGIRequest)->JsonResponse
  3901. try:
  3902. payload = json.loads(request.body) if request.body else {}
  3903. if not payload:
  3904. return JsonErrorResponse(description=u'数据不完整,请重试')
  3905. user = Dealer.objects.get(id=payload['id']) if 'id' in payload else request.user # type: Dealer
  3906. adShow = payload.get('adShow', user.adShow)
  3907. user.adShow = adShow
  3908. user.save()
  3909. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  3910. except DoesNotExist, e:
  3911. logger.exception("dealer does not exist, error = %s" % e)
  3912. return JsonResponse({"result": 0, "description": u'经销商不存在', 'payload': {}})
  3913. except Exception, e:
  3914. logger.exception("set adShow error = %s" % e)
  3915. return JsonResponse({"result": 0, "description": u'系统错误', 'payload': {}})
  3916. @permission_required(ROLE.manager)
  3917. def getDealerDetailList(request):
  3918. # type: (WSGIRequest)->JsonResponse
  3919. """
  3920. 厂商获取经销商详情
  3921. :param request:
  3922. :return:
  3923. """
  3924. def count_devices(ownerId):
  3925. devNoList = [device['devNo'] for device in
  3926. Device.get_collection().find({'ownerId': ownerId, 'groupId': {'$ne': ''}}, {'devNo': 1, '_id': 0})]
  3927. allCount = len(devNoList)
  3928. devDict = Device.get_dev_by_nos(devNoList)
  3929. if not devDict:
  3930. return 0, 0, 0
  3931. onlineCount = 0
  3932. for devNo, dev in devDict.items():
  3933. if dev["online"]:
  3934. onlineCount += 1
  3935. offlineCount = allCount - onlineCount
  3936. return onlineCount, offlineCount, allCount
  3937. mid = str(request.user.id)
  3938. pageIndex = int(request.GET.get('pageIndex', 1))
  3939. pageSize = int(request.GET.get('pageSize', 10))
  3940. agentId = request.GET.get('agentId', None)
  3941. searchKey = request.GET.get('searchKey', None)
  3942. dealers = Dealer.search(searchKey)
  3943. agentMap = {str(agent.id): agent.username for agent in Agent.objects(managerId=mid)}
  3944. agentIds = agentMap.keys()
  3945. if agentId:
  3946. dealers = dealers.filter(agentId=agentId)
  3947. elif agentIds:
  3948. dealers = dealers.filter(agentId__in=agentIds)
  3949. total = dealers.count()
  3950. dealers_per_page = dealers.skip((pageIndex - 1) * pageSize).limit(pageSize)
  3951. dataList = []
  3952. for d in dealers_per_page:
  3953. report = Accounting.getOwnerIncome(str(d.id), now=datetime.datetime.now())
  3954. onlineCount, offlineCount, allCount = count_devices(str(d.id))
  3955. hasZJFirePlatform = True
  3956. ZJFirePlatform = {}
  3957. try:
  3958. obj = Company.objects.get(ownerId=str(d.id))
  3959. ZJFirePlatform = {
  3960. 'companyName': obj.name,
  3961. 'companyCode': obj.code,
  3962. 'companyAddress': obj.address,
  3963. 'contactsName': obj.contactName,
  3964. 'contactsTel': obj.telephone,
  3965. 'deviceManufacturer': obj.manufacturer
  3966. }
  3967. hasZJFirePlatform = True
  3968. except Exception, e:
  3969. pass
  3970. now = datetime.datetime.now()
  3971. today = now.strftime(Const.DATE_FMT)
  3972. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(d.id), 'date':today}, {'daily':1, 'activedDevRatio':1})
  3973. if rcds.count() == 0:
  3974. todayIncome = 0
  3975. todayRechargeIncome = 0
  3976. todayChargeCardIncome = 0
  3977. else:
  3978. info = rcds[0]
  3979. todayIncome = info.get('daily', {}).get('totalIncome', 0)
  3980. income = info.get('daily', {}).get('income', {})
  3981. todayRechargeIncome = income.get('recharge', 0)
  3982. todayChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('virtualChargeCard', 0))
  3983. monthDay = MONTH_DATE_KEY.format(year=now.year, month=now.month)
  3984. rcds = DealerMonthlyStat.get_collection().find({'dealerId':ObjectId(d.id), 'date':monthDay}, {'addedUserCount':1})
  3985. if rcds.count() == 0:
  3986. userCountAddedThisMonth = 0
  3987. else:
  3988. info = rcds[0]
  3989. userCountAddedThisMonth = rcds[0].get('addedUserCount', 0)
  3990. detail = d.to_dict()
  3991. dataList.append({
  3992. 'id': str(d.id),
  3993. 'name': d.nickname,
  3994. 'tel': d.username,
  3995. 'agentInfo': agentMap.get(detail['agentId'], ''),
  3996. 'dateTimeAdded': d.dateTimeAdded,
  3997. 'lineCoins': report['lineCoins'],
  3998. 'payIncome': todayIncome,
  3999. 'todayRechargeIncome': todayRechargeIncome,
  4000. 'todayChargeCardIncome': todayChargeCardIncome,
  4001. 'userCount':d.userCount,
  4002. 'userCountAddedThisMonth':userCountAddedThisMonth,
  4003. 'devTotalNum': allCount,
  4004. 'offlineTotal': offlineCount,
  4005. 'onlineTotal': onlineCount,
  4006. 'detail': json_dumps(detail),
  4007. 'ZJFirePlatform': ZJFirePlatform,
  4008. 'hasZJFirePlatform': hasZJFirePlatform,
  4009. 'disableDevice': True if "dealerDisableDevice" in d.features else False
  4010. })
  4011. return JsonResponse({
  4012. 'result': 1,
  4013. 'description': '',
  4014. 'payload': {
  4015. 'total': total,
  4016. 'dataList': dataList
  4017. }
  4018. })
  4019. @permission_required(ROLE.manager)
  4020. def getDealerListByAgent(request):
  4021. # type: (WSGIRequest)->JsonResponse
  4022. """
  4023. :param request:
  4024. :return:
  4025. """
  4026. agentIds = json.loads(request.body).get('agentIds', [])
  4027. agents = {str(_.id): _.nickname for _ in Agent.objects(id__in=agentIds)}
  4028. if not agents: return JsonResponse({'result': 1, 'payload': []})
  4029. dataList = [
  4030. {
  4031. 'dealerName': _.nickname,
  4032. 'dealerId': str(_.id),
  4033. 'agentId': str(_.agentId),
  4034. 'agentName': agents[str(_.agentId)]
  4035. }
  4036. for _ in Dealer.objects(agentId__in=agentIds)
  4037. ]
  4038. return JsonResponse({'result': 1, 'payload': {'dataList': dataList, 'total': len(dataList)}})
  4039. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取设备列表失败'))
  4040. @permission_required(ROLE.dealer, ROLE.subaccount)
  4041. def equipmentList(request):
  4042. # type: (WSGIRequest)->JsonResponse
  4043. def _get_port_status(portDict):
  4044. allPorts = portDict.get("allPorts", 0)
  4045. usedPorts = portDict.get("usedPorts", 0)
  4046. usePorts = portDict.get("usePorts", 0)
  4047. return allPorts, usedPorts, usePorts
  4048. dealerId = str(request.user.bossId)
  4049. pageIndex = int(request.GET.get('pageIndex', 1))
  4050. pageSize = int(request.GET.get('pageSize', 10))
  4051. equipmentGroupId = request.GET.get('equipmentGroupId')
  4052. online = request.GET.get('online')
  4053. searchKey = request.GET.get('searchKey', '')
  4054. sort = request.GET.get('sort', 'logicalCode')
  4055. partnerGroupList = Group.get_group_ids_of_partner(dealerId)
  4056. ownGroupList = Group.get_group_ids_of_dealer(dealerId)
  4057. groupIds = partnerGroupList + ownGroupList
  4058. if not equipmentGroupId:
  4059. selectedGroupIds = groupIds
  4060. else:
  4061. selectedGroupIds = [equipmentGroupId]
  4062. if not online:
  4063. onlineStates = [0, 1]
  4064. else:
  4065. onlineStates = [int(online)]
  4066. groupDict = Group.get_groups_by_group_ids(selectedGroupIds)
  4067. devNoList = Device.get_devNos_by_group(selectedGroupIds)
  4068. devs = Device.get_dev_by_nos(devNoList).values()
  4069. devDict, deviceCount = {}, 0
  4070. devCacheMap = Device.get_many_dev_control_cache(devNoList)
  4071. showPortStatus = bool(request.user.feature_boolean_map.get("showPortStatus", None))
  4072. for dev in devs: # type: DeviceDict
  4073. if dev.online not in onlineStates:
  4074. continue
  4075. group = groupDict.get(dev['groupId'])
  4076. if group is None:
  4077. continue
  4078. if any(map(lambda _: searchKey in _, (dev['devNo'],
  4079. dev['remarks'],
  4080. dev['logicalCode'],
  4081. group['groupName'],
  4082. group['address']))):
  4083. isFault = dev.get('isFault', False)
  4084. isDND = dev.is_DND_now
  4085. item = {
  4086. 'id': dev.devNo,
  4087. 'logicalCode': dev.logicalCode,
  4088. 'name': group['groupName'],
  4089. 'groupId': group['groupId'],
  4090. 'type': dev.devType['name'],
  4091. 'typeId': dev.devType['id'],
  4092. 'devType': dev.devType,
  4093. 'unit': dev.devType.get('unit', DeviceType.unit.default),
  4094. 'online': dev.online,
  4095. 'signal': dev.signal,
  4096. 'timeBased': dev.devType.get('timeBased', DeviceType.timeBased.default),
  4097. 'autoRefundEnable': dev.devType.get('autoRefundEnable', DeviceType.autoRefundEnable.default),
  4098. 'channelType': dev.channelType,
  4099. 'isManager': False if dev['groupId'] in partnerGroupList else True,
  4100. 'serviceState': dev.get('serviceState', Const.ServiceState.Normal.name),
  4101. 'remarks': dev.get('remarks', Device.remarks.default),
  4102. 'status': dev.status,
  4103. 'statusInfo': dev.statusInfo,
  4104. 'isFault': isFault,
  4105. 'isDND': isDND,
  4106. 'offTimeDate': datetime.datetime.fromtimestamp(int(str(dev.offTime)[0:10])).strftime('%Y-%m-%d %H:%M:%S') if dev.offTime is not None else '',
  4107. 'tag': group.get("tag", ""),
  4108. "deviceWarning": dev.is_warning
  4109. }
  4110. # 最近离线时间小于2017年的都为空
  4111. offTimeYear = int(item['offTimeDate'][0:4])
  4112. if offTimeYear < 2017:
  4113. item['offTimeDate'] = ''
  4114. if showPortStatus:
  4115. # 这个地方需要添加 具体的端口 使用情况 故障、工作、空闲等 使用情况从缓存中直接读取,如果不存在 则没有,不去具体查询设备
  4116. devCache = devCacheMap.get(device_control_cache_key(dev["devNo"]), {})
  4117. allPorts, usedPorts, usePorts = _get_port_status(devCache)
  4118. hasPort = showPortStatus and bool(allPorts)
  4119. item.update({"hasPort": hasPort})
  4120. if hasPort: item.update(
  4121. {"portStatus":
  4122. {
  4123. "all": allPorts,
  4124. "idle": usePorts,
  4125. "used": usedPorts,
  4126. }
  4127. }
  4128. )
  4129. else:
  4130. item.update({"hasPort": False})
  4131. if not dev.online and Device.utils_is_expired(dev):
  4132. item.update({'simExpireDate': dev.formatSimExpireDate, 'simStatus': dev.simStatus})
  4133. if dev['groupId'] in devDict:
  4134. devDict[dev['groupId']].append(item)
  4135. else:
  4136. devDict[dev['groupId']] = [item]
  4137. # 近7日平均使用率
  4138. if dev.devType.get('features', {}).get('7_days_average_utilization_rate', False) is True:
  4139. nowDateTime = datetime.datetime.now()
  4140. sevenDaysAgoDateTime = nowDateTime - datetime.timedelta(days=7)
  4141. consumeRecords = ConsumeRecord.objects(devNo=dev.devNo, dateTimeAdded__gte=sevenDaysAgoDateTime, dateTimeAdded__lte=nowDateTime)
  4142. sevenDaysAverage = round(((float(consumeRecords.count()) / 7) / 10) * 100, 2)
  4143. item.update({'sevenDaysAverage': sevenDaysAverage})
  4144. deviceCount += 1
  4145. showGroups = paginate(sorted(devDict.keys(), reverse=False), pageSize=pageSize, pageIndex=pageIndex)
  4146. devList = []
  4147. for keyGrp in showGroups:
  4148. devList.extend(devDict[keyGrp])
  4149. if sort == 'logicalCode':
  4150. tempList = natural_sort(array=devList, key='logicalCode', reverse=False)
  4151. elif sort == 'devType':
  4152. tempList = sorted(devList, key=lambda x: x['devType']['name'])
  4153. elif sort == 'remarks':
  4154. tempList = sorted(devList, key=lambda x: x['remarks'], reverse=True)
  4155. elif sort == "tag":
  4156. tempList = devList
  4157. else:
  4158. raise InvalidParameter(u'搜索条件不合法')
  4159. if sort == "tag":
  4160. devList = sorted(tempList, key=lambda x: x['tag'], reverse=True)
  4161. else:
  4162. devList = sorted(tempList, key=lambda x: x['groupId'])
  4163. return JsonResponse({
  4164. "result": 1,
  4165. "description": None,
  4166. 'payload': {
  4167. "total": deviceCount,
  4168. "groupCount": len(devDict.keys()),
  4169. "dataList": devList
  4170. }
  4171. })
  4172. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取库存列表失败'))
  4173. @permission_required(ROLE.dealer, ROLE.subaccount)
  4174. def equipmentListForStock(request):
  4175. # type: (WSGIRequest)->JsonResponse
  4176. ownerId = str(request.user.bossId)
  4177. equipmentGroupId = request.GET.get('equipmentGroupId', 'all')
  4178. online = request.GET.get('online', 'all')
  4179. searchKey = request.GET.get('searchKey', '')
  4180. groupIds, devTempList = Device.filter(dealerId=ownerId, searchKey=searchKey, online=online,
  4181. equipmentGroupId=equipmentGroupId)
  4182. devList = []
  4183. for dev in devTempList:
  4184. if not dev.has_key('quantity'):
  4185. continue
  4186. devList.append(dev)
  4187. return JsonResponse({
  4188. "result": 1,
  4189. "description": None,
  4190. 'payload': {
  4191. "total": len(groupIds),
  4192. "groupCount": len(devList),
  4193. "dataList": devList
  4194. }
  4195. })
  4196. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'解绑失败'))
  4197. @permission_required(ROLE.dealer, ROLE.subaccount)
  4198. @request_limit_by_user(operation='unbindDevice', limit=100, logger=logger)
  4199. def unbindDevice(request):
  4200. def unbindDeviceDefault(request):
  4201. # type: (WSGIRequest)->JsonResponse
  4202. """
  4203. 经销商解绑设备
  4204. ..modified 去掉对代理商串货的限制
  4205. :param request:
  4206. :return:
  4207. """
  4208. owner_id = str(request.user.bossId)
  4209. devNo = request.POST.get('value', None)
  4210. if devNo is None:
  4211. return JsonResponse({"result": 0, "description": u"缺少参数", 'payload': {}})
  4212. dev = Device.get_dev(devNo) # type: DeviceDict
  4213. devType = dev['devType']
  4214. groupId = dev['groupId']
  4215. if dev is None:
  4216. return JsonResponse({"result": 0, "description": u"该设备不存在,请刷新后再试", 'payload': {}})
  4217. if not dev.is_registered:
  4218. return JsonResponse({"result": 0, "description": u"该设备没有注册,不需要解绑", 'payload': {}})
  4219. if dev.ownerId != owner_id:
  4220. return JsonResponse({"result": 0, "description": u"不是您的设备,不能够解绑", 'payload': {}})
  4221. try:
  4222. Device.un_register(dev=dev, operator=request.user.human_id)
  4223. dealer = Dealer.objects.get(id=owner_id)
  4224. dealer.devCount -= 1
  4225. dealer.save()
  4226. except RentDeviceError as rde:
  4227. return JsonErrorResponse(rde.message)
  4228. except Exception as e:
  4229. logger.exception(
  4230. 'un register failure. error = %s, devNo = %s, ownerId = %s' % (e, devNo, str(request.user.bossId)))
  4231. return JsonResponse({"result": 0, "description": u"系统错误", 'payload': {}})
  4232. group = Group.get_group(groupId)
  4233. if group.get('swapFlag', False):
  4234. agentId = request.user.agentId
  4235. agent = Agent.objects(id=agentId).first()
  4236. if agent:
  4237. devNum = 0
  4238. if 'majorDeviceType' in devType and (u'直流' in devType['majorDeviceType'] or u'交流' in devType['majorDeviceType']):
  4239. devNum = -1
  4240. SwapGroup.update_swap_time_and_num(groupId, devNum)
  4241. SwapContract.update_swap_time_and_num(groupId, owner_id, agentId, agent.managerId, devNum)
  4242. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4243. current_user = request.user # type: UserSearchable
  4244. if not current_user.normal:
  4245. return JsonResponse({"result": 0, "description": u"账号异常,不能进行该操作", 'payload': {}})
  4246. return unbindDeviceDefault(request)
  4247. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'解绑失败'))
  4248. @permission_required(ROLE.dealer, ROLE.subaccount)
  4249. @request_limit_by_user(operation='unbindAllNode', limit=100, logger=logger)
  4250. def unbindAllNode(request):
  4251. # 获取主机的子节点
  4252. lc = request.POST.get('logicalCode', None)
  4253. master = Device.get_dev_by_l(lc) # type: DeviceDict
  4254. nodeList = master.deviceAdapter.get_node_list()
  4255. if not nodeList:
  4256. return JsonResponse({"result": 0, "description": u"该设备不存在,请刷新后再试", 'payload': {}})
  4257. owner_id = str(request.user.bossId)
  4258. # TODO 和刘崇确认 此处先简单修复 然后后续可能进行优化
  4259. # 进行检查 保证所有设备都是 该经销商的
  4260. errDevs = list()
  4261. for node in nodeList: # type: DeviceDict
  4262. if not node.is_registered:
  4263. continue
  4264. if node.ownerId != owner_id:
  4265. errDevs.append(node.logicalCode)
  4266. if errDevs:
  4267. return JsonErrorResponse(description=u"设备{} 不是您的设备 无法解绑".format(" ".join(errDevs)))
  4268. # 再解除经销商绑定
  4269. for node in nodeList:
  4270. if not node.is_registered:
  4271. continue
  4272. Device.un_register(dev=node, operator=request.user.human_id)
  4273. dealer = Dealer.objects.get(id=owner_id)
  4274. dealer.devCount -= 1
  4275. dealer.save()
  4276. return JsonOkResponse()
  4277. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除套餐失败'))
  4278. @permission_required(ROLE.dealer, ROLE.subaccount)
  4279. def delPackages(request):
  4280. # type: (WSGIRequest)->JsonResponse
  4281. curr_user = request.user # type: Union[Dealer, SubAccount]
  4282. if not curr_user.normal:
  4283. return JsonErrorResponse(description=u'账号异常,不能进行该操作')
  4284. devNo = request.POST.get('devNo', None)
  4285. ruleId = request.POST.get('ruleId', None)
  4286. if devNo is None or ruleId is None:
  4287. return JsonResponse({"result": 0, "description": u"缺少参数", 'payload': {}})
  4288. dev = Device.get_dev(devNo)
  4289. if dev is None:
  4290. return JsonResponse({"result": 0, "description": u"找不到设备", 'payload': {}})
  4291. try:
  4292. dev['washConfig'].pop(ruleId)
  4293. except Exception, e:
  4294. logger.exception('pop washconfig error=%s,ruleId=%s,devNo=%s' % (e, ruleId, devNo))
  4295. return JsonResponse({"result": 0, "description": u'该套餐已经被删除了,请刷新页面', 'payload': {}})
  4296. try:
  4297. Device.get_collection().update_one({'devNo': devNo}, {'$set': {'washConfig': dev['washConfig']}})
  4298. Device.invalid_device_cache(devNo)
  4299. except Exception, e:
  4300. logger.exception('update device washconfig error=%s,devNo=%s,washConfig=%s' % (e, devNo, dev['washConfig']))
  4301. return JsonResponse({"result": 0, "description": u'保存套餐出错,请稍候再试', 'payload': {}})
  4302. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4303. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取套餐失败'))
  4304. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  4305. def getPackages(request):
  4306. # type: (WSGIRequest)->JsonResponse
  4307. lc = request.GET.get('logicalCode', None)
  4308. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  4309. if dev is None:
  4310. return JsonErrorResponse(description=u"找不到设备")
  4311. maxCoins = dev.get('maxCoins', 4)
  4312. devNo = dev.devNo
  4313. # 设备没注册, 走脉冲测试
  4314. if not dev.ownerId:
  4315. devData = {
  4316. 'id': devNo,
  4317. 'maxCoins': maxCoins,
  4318. 'devNo': devNo,
  4319. 'type': u'脉冲',
  4320. 'typeCode': u'201',
  4321. 'groupName': u'测试',
  4322. 'groupNumber': 666
  4323. }
  4324. defaultWashconfig = {'1': {'coins': 1}, '2': {'coins': 2}, '3': {'coins': 3}, '4': {'coins': 4},
  4325. '5': {'coins': 5}}
  4326. ruleList = [
  4327. {
  4328. 'id': packageId,
  4329. 'name': u'测试',
  4330. 'coins': rule['coins'],
  4331. 'price': rule.get('price', rule['coins'])
  4332. } for packageId, rule in defaultWashconfig.items()
  4333. ]
  4334. return JsonResponse({"result": 1, "description": None, 'payload': {'devData': devData, 'ruleList': ruleList}})
  4335. group = Group.get_group(dev['groupId'])
  4336. if group is None:
  4337. return JsonErrorResponse(description=u'找不到设备')
  4338. if group['ownerId'] != str(request.user.bossId):
  4339. return JsonErrorResponse(description=u'找不到设备')
  4340. devData = {
  4341. 'id': devNo,
  4342. 'maxCoins': maxCoins,
  4343. 'isManager': True,
  4344. 'groupName': group['groupName'],
  4345. 'groupNumber': dev['groupNumber'],
  4346. 'devNo': devNo,
  4347. 'type': dev['devType']['name'],
  4348. 'typeCode': dev['devType']['code']
  4349. }
  4350. if "displaySwitchs" in dev["otherConf"]:
  4351. displaySwitchs = dev["otherConf"].get('displaySwitchs')
  4352. else:
  4353. displaySwitchs = {'displayCoinsSwitch': True,
  4354. 'displayTimeSwitch': True,
  4355. 'displayPriceSwitch': True,
  4356. "setPulseAble": False,
  4357. "setBasePriceAble": False}
  4358. if dev.channelType != DeviceChannelType.Channel_BT:
  4359. smartBox = ActionDeviceBuilder.create_action_device(dev)
  4360. try:
  4361. portDict = smartBox.dealer_get_port_status()
  4362. if portDict:
  4363. chargeIndex = {}
  4364. for index, info in portDict.items():
  4365. if "status" not in info:
  4366. continue
  4367. if info['status'] == Const.DEV_WORK_STATUS_IDLE:
  4368. chargeIndex[index] = 'idle'
  4369. elif info['status'] == Const.DEV_WORK_STATUS_WORKING:
  4370. chargeIndex[index] = 'busy'
  4371. elif info['status'] == Const.DEV_WORK_STATUS_FAULT:
  4372. chargeIndex[index] = 'fault'
  4373. elif info['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
  4374. chargeIndex[index] = 'ban'
  4375. elif info['status'] == Const.DEV_WORK_STATUS_CONNECTED:
  4376. chargeIndex[index] = 'connected'
  4377. elif info['status'] == Const.DEV_WORK_STATUS_FINISHED:
  4378. chargeIndex[index] = 'finished'
  4379. devData.update({'chargeIndex': chargeIndex})
  4380. except ServiceException, e:
  4381. return JsonErrorResponse(description=e.result.get('description'))
  4382. except Exception as e:
  4383. logger.exception(e)
  4384. return JsonErrorResponse(description=u'未知错误')
  4385. if dev["devType"]["code"] == Const.DEVICE_TYPE_CODE_HP_GATE:
  4386. if request.GET.get("isRemoteUpper", None):
  4387. ruleList = []
  4388. else:
  4389. tempList = sorted(dev["washConfig"].get("1", {}).items(), key=lambda x: x[0])
  4390. ruleList = [v for _, v in tempList]
  4391. chargeIndex = {}
  4392. if dev["otherConf"].get("controlEnter") in ("1", "2"):
  4393. chargeIndex["enter"] = "idle"
  4394. if dev["otherConf"].get("controlExit") in ("1", "2"):
  4395. chargeIndex["exit"] = "idle"
  4396. devData.update({'chargeIndex': chargeIndex})
  4397. if request.GET.get("isRemoteUpper", None):
  4398. ruleList = []
  4399. elif dev["devType"]["code"] in support_policy_weifule:
  4400. if dev.deviceAdapter.support_device_package:
  4401. payload = dev.deviceAdapter.dealer_show_package()
  4402. payload.update({"devData": devData})
  4403. return JsonOkResponse(payload=payload)
  4404. elif dev["devType"]["code"] in support_policy_device:
  4405. if dev.deviceAdapter.support_device_package:
  4406. payload = dev.deviceAdapter.dealer_show_package()
  4407. payload.update({"devData": devData})
  4408. return JsonOkResponse(payload=payload)
  4409. 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]:
  4410. if dev.deviceAdapter.support_device_package:
  4411. payload = dev.deviceAdapter.dealer_show_package()
  4412. payload.update({"devData": devData})
  4413. return JsonOkResponse(payload=payload)
  4414. else:
  4415. snRuleList = []
  4416. ruleList = []
  4417. for packageId, rule in dev['washConfig'].items():
  4418. item = {
  4419. 'id': packageId,
  4420. 'name': rule['name'],
  4421. 'coins': rule['coins'],
  4422. 'price': rule.get('price', rule['coins']),
  4423. 'time': rule.get('time', 20),
  4424. 'description': rule.get('description', ''),
  4425. 'imgList': rule.get('imgList', []),
  4426. 'unit': rule.get('unit', u'分钟'),
  4427. 'switch': rule.get('switch', True),
  4428. }
  4429. if rule.get('pulse'):
  4430. item.update({
  4431. 'pulse': rule.get('pulse'),
  4432. })
  4433. if rule.get('basePrice'):
  4434. item.update({
  4435. 'basePrice': rule.get('basePrice'),
  4436. })
  4437. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  4438. item.update({
  4439. 'billingMethod': rule['billingMethod'],
  4440. })
  4441. if 'sn' in rule:
  4442. item['sn'] = rule['sn']
  4443. ruleList.append(item)
  4444. ruleList = sorted(ruleList, key=lambda x: (x.get('sn'), x.get('id')))
  4445. payload = {"devData": devData, "ruleList": ruleList, 'displaySwitchs': displaySwitchs}
  4446. unit_price = dev.otherConf.get('unit_price', {})
  4447. if dev.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_WEIFULE2]:
  4448. try:
  4449. if not unit_price:
  4450. dev.deviceAdapter.set_dev_setting(dev.deviceAdapter.get_dev_setting())
  4451. unit_price = Device.get_dev_by_l(lc).otherConf.get('unit_price', {})
  4452. except:
  4453. pass
  4454. if unit_price:
  4455. payload.update({'unit_price': unit_price})
  4456. return JsonOkResponse(payload=payload)
  4457. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存套餐失败'))
  4458. @permission_required(ROLE.dealer, ROLE.subaccount)
  4459. def savePackages(request):
  4460. """
  4461. 保存套餐
  4462. :param request:
  4463. :return:
  4464. """
  4465. # 检测套餐单位一致性校验
  4466. def check_package_unit(typeCode, package):
  4467. # 电川汽车装有按金额启动,电量启动和充满自停的需求
  4468. if typeCode == Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING:
  4469. return True
  4470. if typeCode in skip_package_unit_verify_list:
  4471. return True
  4472. dic = map(lambda x: {'unit': x.get('unit') }, package)
  4473. res = reduce(lambda x, y: x if x == y else None, dic)
  4474. if res is None:
  4475. return False
  4476. else:
  4477. return True
  4478. # 检查套餐单位单位小数点后两位校验
  4479. def check_params_range(typeCode, package):
  4480. if typeCode in skip_package_range_verify_list:
  4481. return None
  4482. dic = map(lambda x: [x.get('time')], package)
  4483. res = reduce(lambda x, y: x + y, dic)
  4484. result = None
  4485. for item in res:
  4486. l = str(item).split(".")
  4487. if len(l) > 1 and len(l[1]) > 2:
  4488. result = (res.index(item) // 3) + 1
  4489. break
  4490. return result
  4491. # 套餐参数完整性校验
  4492. def check_params(typeCode, package):
  4493. if typeCode in skip_package_params_verify_list:
  4494. return True
  4495. lis = map(lambda x: [x.get('time'), x.get('price'), x.get('coins')], package)
  4496. res = reduce(lambda x, y: x + y, lis)
  4497. for i in res:
  4498. if i is None or float(i) < 0:
  4499. return False
  4500. return True
  4501. # 套餐和金币是否需要强制1:1
  4502. def check_price_equal_coin(_devDict, _package):
  4503. for _dev in _devDict.values():
  4504. # 非出租设备 不影响
  4505. if not _dev.isRent:
  4506. continue
  4507. for _rule in _package:
  4508. if RMB(_rule["price"]) != RMB(_rule["coins"]):
  4509. return False
  4510. return True
  4511. curr_user = request.user # type: Union[Dealer, SubAccount]
  4512. if not curr_user.normal:
  4513. return JsonErrorResponse(description=u'账号异常,不能进行该操作')
  4514. status, msg = ensure_all_fields_are_not_empty(
  4515. {k: v for k, v in request.POST.items() if k not in ('ruleId',)})
  4516. if not status:
  4517. return JsonErrorResponse(description=msg)
  4518. paras = json.loads(request.body) if request.body else {}
  4519. if not paras:
  4520. return JsonErrorResponse(description=u'提交数据为空')
  4521. if paras['logicalCode'].__class__.__name__ == 'list':
  4522. devNoList = [Device.get_devNo_by_logicalCode(lc) for lc in paras['logicalCode']]
  4523. else:
  4524. devNoList = [Device.get_devNo_by_logicalCode(paras['logicalCode'])]
  4525. devDict = Device.get_dev_by_nos(devNoList)
  4526. if not devDict:
  4527. return JsonErrorResponse(description=u'找不到设备')
  4528. typeCode = devDict.values()[0]['devType']['code']
  4529. if typeCode in support_policy_weifule:
  4530. dev = devDict.values()[0]
  4531. if dev.deviceAdapter.support_device_package:
  4532. try:
  4533. dev.deviceAdapter.format_device_package(**paras)
  4534. except ServiceException as e:
  4535. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  4536. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4537. elif typeCode in support_policy_device:
  4538. dev = devDict.values()[0]
  4539. if dev.deviceAdapter.support_device_package:
  4540. try:
  4541. dev.deviceAdapter.format_device_package(**paras)
  4542. except ServiceException as e:
  4543. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  4544. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4545. # 解析washConfig,如果需要下发设备,解析出来setConfig
  4546. serviceList = paras['serviceData']
  4547. displaySwitchs = paras.get('displaySwitchs', {'displayCoinsSwitch': True,
  4548. 'displayTimeSwitch': True,
  4549. 'displayPriceSwitch': True,
  4550. 'setPulseAble': False,
  4551. 'setBasePriceAble': False})
  4552. # 调整sn顺序
  4553. for item in serviceList:
  4554. item["sn"] = serviceList.index(item)
  4555. if not check_params(typeCode, serviceList):
  4556. return JsonErrorResponse(description=u'请完整的填写套餐中的所有参数')
  4557. if not check_package_unit(typeCode, serviceList):
  4558. return JsonErrorResponse(description=u'套餐用户获得参数单位配置需要一致')
  4559. f = check_params_range(typeCode, serviceList)
  4560. if f:
  4561. return JsonErrorResponse(description=u'第%s个套餐 用户获得参数应为小数点后两位' % f)
  4562. if not check_price_equal_coin(devDict, serviceList):
  4563. return JsonErrorResponse(description=u"套餐金币与价格必须相等!")
  4564. washConfig, setConfig = {}, {}
  4565. agent = Agent.objects.get(id=request.user.agentId)
  4566. existIds = []
  4567. for rule in serviceList:
  4568. if 'id' in rule:
  4569. existIds.append(rule['id'])
  4570. # 霍珀道闸 后付费模式 使用阶梯计费
  4571. if typeCode == Const.DEVICE_TYPE_CODE_HP_GATE:
  4572. rule = {str(index + 1): v for index, v in enumerate(serviceList)}
  4573. washConfig = {"1": rule}
  4574. 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]:
  4575. dev = devDict.values()[0]
  4576. if dev.deviceAdapter.support_device_package:
  4577. try:
  4578. washConfig, displaySwitchs = dev.deviceAdapter.format_device_package(**paras)
  4579. except ServiceException as e:
  4580. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  4581. else:
  4582. for rule in serviceList:
  4583. if rule.has_key('coins') and rule.has_key('price'):
  4584. if not (is_number(rule['coins']) and is_number(rule['price']) and is_number(
  4585. rule.get('time', 0))):
  4586. return JsonErrorResponse(description=u'金币数目或者时间或者价格必须是数字')
  4587. else:
  4588. rule['coins'], rule['price'] = 0, 0 # 对于那种先不需要付费的,这个就直接是0
  4589. if RMB(rule['price']) >= request.user.maxPackagePrice:
  4590. return JsonErrorResponse(description=u'套餐金额超限')
  4591. if len(rule['name']) > 20:
  4592. return JsonErrorResponse(description=u'套餐名字只能取1-20位')
  4593. if typeCode == Const.DEVICE_TYPE_CODE_WASHER:
  4594. name = rule['name']
  4595. if name not in [Const.WASHER_BOX_SET_DTS, Const.WASHER_BOX_SET_KSX, Const.WASHER_BOX_SET_BZX,
  4596. Const.WASHER_BOX_SET_DWX, Const.WASHER_BOX_SET_JRKS, Const.WASHER_BOX_SET_JRBZ,
  4597. Const.WASHER_BOX_JRDW, Const.WASHER_BOX_SET_TQJ]:
  4598. return JsonErrorResponse(description=u'套餐名称只能是:桶清洁、单脱水、快速洗、标准洗、大物洗、加热快速洗、加热标准洗、加热大物洗。')
  4599. coins = rule['coins']
  4600. useTime = rule['time']
  4601. if name == Const.WASHER_BOX_SET_DTS:
  4602. setConfig[Const.WASHER_BOX_DTS] = {'price': int(coins), 'time': int(useTime)}
  4603. elif name == Const.WASHER_BOX_SET_KSX:
  4604. setConfig[Const.WASHER_BOX_KS] = {'price': int(coins), 'time': int(useTime)}
  4605. elif name == Const.WASHER_BOX_SET_BZX:
  4606. setConfig[Const.WASHER_BOX_BZ] = {'price': int(coins), 'time': int(useTime)}
  4607. elif name == Const.WASHER_BOX_SET_DWX:
  4608. setConfig[Const.WASHER_BOX_DW] = {'price': int(coins), 'time': int(useTime)}
  4609. elif name == Const.WASHER_BOX_SET_JRKS:
  4610. setConfig[Const.WASHER_BOX_JRKS] = {'price': int(coins), 'time': int(useTime)}
  4611. elif name == Const.WASHER_BOX_SET_JRBZ:
  4612. setConfig[Const.WASHER_BOX_JRBZ] = {'price': int(coins), 'time': int(useTime)}
  4613. elif name == Const.WASHER_BOX_SET_JRDW:
  4614. setConfig[Const.WASHER_BOX_JRDW] = {'price': int(coins), 'time': int(useTime)}
  4615. elif (typeCode == Const.DEVICE_TYPE_CODE_WASHER_CW) and \
  4616. (rule['name'] not in [u'标准洗', u'快速洗', u'强力洗', u'单脱水', u'轻柔洗', u'漂洗并脱水', u'自洁', u'能效-全载', u'能效-半载',
  4617. u'整机自检', u'电脑版自检']):
  4618. return JsonErrorResponse(description=u'套餐名称只能是:标准洗,快速洗,强力洗,单脱水,轻柔洗,漂洗并脱水,自洁,能效-全载,能效-半载,整机自检,电脑版自检')
  4619. elif typeCode == Const.DEVICE_TYPE_CODE_WASHER_SIMAIER:
  4620. if rule['name'] not in [u'加强洗', u'标准洗', u'快速洗', u'单脱水']:
  4621. return JsonErrorResponse(description=u'套餐名称只能是:加强洗,标准洗,快速洗,单脱水')
  4622. elif typeCode == Const.DEVICE_TYPE_CODE_HUITENG:
  4623. if rule['name'] not in [u'单脱水', u'快速洗', u'标准洗', u'大物洗']:
  4624. return JsonErrorResponse(description=u'套餐名称只能是:单脱水,快速洗,标准洗,大物洗')
  4625. elif typeCode == Const.DEVICE_TYPE_CODE_CAR_CHARGING_CY:
  4626. price = rule.get("price")
  4627. coins = rule.get("coins")
  4628. unit = rule.get("unit")
  4629. time = rule.get("time")
  4630. if price != coins:
  4631. return JsonErrorResponse(description=u'请将金币和套餐值设置相同')
  4632. if unit != u"次":
  4633. return JsonErrorResponse(description=u'计费单位只能是:次')
  4634. if int(time) != 1:
  4635. return JsonErrorResponse(description=u"计费次数只能是:1")
  4636. elif typeCode in [Const.DEVICE_TYPE_CODE_WASHER_CY_HS,Const.DEVICE_TYPE_CODE_WASHER_CY_HS_YUCHUAN]:
  4637. if rule['name'] not in [u'大物洗', u'标准洗', u'快速洗', u'单脱水']:
  4638. return JsonErrorResponse(description=u'套餐名称只能是:大物洗,标准洗,快速洗,单脱水')
  4639. if rule['unit'] != "分钟":
  4640. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4641. if rule["name"] == u"单脱水" and (int(rule["time"]) > 9 or int(rule["time"]) < 5):
  4642. return JsonErrorResponse(description=u"单脱水时间范围为5-9分钟")
  4643. if rule["name"] == u"快速洗" and (int(rule["time"]) > 32 or int(rule["time"]) < 20):
  4644. return JsonErrorResponse(description=u"快速洗时间范围为20-32分钟")
  4645. if rule["name"] == u"标准洗" and (int(rule["time"]) > 43 or int(rule["time"]) < 35):
  4646. return JsonErrorResponse(description=u"标准洗时间范围为35-43分钟")
  4647. if rule["name"] == u"大物洗" and (int(rule["time"]) > 53 or int(rule["time"]) < 45):
  4648. return JsonErrorResponse(description=u"大物洗时间范围为45-53分钟")
  4649. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4650. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4651. elif typeCode in [Const.DEVICE_TYPE_CODE_WASHER_CY_HJ]:
  4652. if rule['name'] not in [u'大物洗', u'标准洗', u'快速洗', u'单脱水']:
  4653. return JsonErrorResponse(description=u'套餐名称只能是:大物洗,标准洗,快速洗,单脱水')
  4654. if rule['unit'] != "分钟":
  4655. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4656. if rule["name"] == u"单脱水" and (int(rule["time"]) > 15 or int(rule["time"]) < 5):
  4657. return JsonErrorResponse(description=u"单脱水时间范围为5-15分钟")
  4658. if rule["name"] == u"快速洗" and (int(rule["time"]) > 35 or int(rule["time"]) < 20):
  4659. return JsonErrorResponse(description=u"快速洗时间范围为20-35分钟")
  4660. if rule["name"] == u"标准洗" and (int(rule["time"]) > 50 or int(rule["time"]) < 35):
  4661. return JsonErrorResponse(description=u"标准洗时间范围为35-50分钟")
  4662. if rule["name"] == u"大物洗" and (int(rule["time"]) > 65 or int(rule["time"]) < 50):
  4663. return JsonErrorResponse(description=u"大物洗时间范围为50-65分钟")
  4664. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4665. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4666. elif typeCode in [Const.DEVICE_TYPE_CODE_WASHER_CY_HJ_1]:
  4667. if rule['name'] not in [u'大物洗', u'标准洗', u'快速洗', u'单脱水']:
  4668. return JsonErrorResponse(description=u'套餐名称只能是:大物洗,标准洗,快速洗,单脱水')
  4669. if rule['unit'] != "分钟":
  4670. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4671. if rule["name"] == u"单脱水" and (int(rule["time"]) > 15 or int(rule["time"]) < 5):
  4672. return JsonErrorResponse(description=u"单脱水时间范围为5-15分钟")
  4673. if rule["name"] == u"快速洗" and (int(rule["time"]) > 35 or int(rule["time"]) < 18):
  4674. return JsonErrorResponse(description=u"快速洗时间范围为18-35分钟")
  4675. if rule["name"] == u"标准洗" and (int(rule["time"]) > 45 or int(rule["time"]) < 30):
  4676. return JsonErrorResponse(description=u"标准洗时间范围为30-45分钟")
  4677. if rule["name"] == u"大物洗" and (int(rule["time"]) > 55 or int(rule["time"]) < 40):
  4678. return JsonErrorResponse(description=u"大物洗时间范围为40-55分钟")
  4679. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4680. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4681. elif typeCode == "1003053":
  4682. if rule['name'] not in [u'加时烘干', u'快速烘干', u'标准烘干', u'特别烘干']:
  4683. return JsonErrorResponse(description=u'套餐名称只能是:加时烘干,快速烘干,标准烘干,特别烘干')
  4684. if rule['unit'] != "分钟":
  4685. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4686. if rule["name"] == u"加时烘干" and (int(rule["time"]) > 20 or int(rule["time"]) < 5):
  4687. return JsonErrorResponse(description=u"加时烘干时间范围为5-20分钟")
  4688. if rule["name"] == u"快速烘干" and (int(rule["time"]) > 40 or int(rule["time"]) < 20):
  4689. return JsonErrorResponse(description=u"快速洗时间范围为20-40分钟")
  4690. if rule["name"] == u"标准烘干" and (int(rule["time"]) > 50 or int(rule["time"]) < 30):
  4691. return JsonErrorResponse(description=u"标准洗时间范围为30-50分钟")
  4692. if rule["name"] == u"特别烘干" and (int(rule["time"]) > 70 or int(rule["time"]) < 50):
  4693. return JsonErrorResponse(description=u"大物洗时间范围为50-70分钟")
  4694. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4695. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4696. if 'id' in rule:
  4697. ruleId = rule['id']
  4698. else:
  4699. ruleId = list(set(range(1, 71)) - set([int(ruleId) for ruleId in washConfig.keys()]) - set(existIds))[0]
  4700. # TODO 需要统一类型.这里为云南霍博单独做
  4701. dealer = request.user # type: Dealer
  4702. if ('coins_be_float' not in agent.features) and (not dealer.supports('coins_be_float')):
  4703. if int(float(rule['coins'])) != float(rule['coins']):
  4704. return JsonErrorResponse(description=u'金币只能是整数')
  4705. washConfig[str(ruleId)] = {
  4706. 'name': rule['name'],
  4707. 'coins': int(float(rule['coins'])),
  4708. 'price': float(rule['price']),
  4709. 'time': float(rule.get('time', 0)),
  4710. 'description': rule.get('description', ''),
  4711. 'imgList': rule.get('imgList', []),
  4712. 'unit': rule.get('unit', u'分钟'),
  4713. 'switch': rule.get('switch', True),
  4714. 'sn': rule.get('sn'),
  4715. }
  4716. else:
  4717. washConfig[str(ruleId)] = {
  4718. 'name': rule['name'],
  4719. 'coins': float(rule['coins']),
  4720. 'price': float(rule['price']),
  4721. 'time': float(rule.get('time', 0)),
  4722. 'description': rule.get('description', ''),
  4723. 'imgList': rule.get('imgList', []),
  4724. 'unit': rule.get('unit', u'分钟'),
  4725. 'switch': rule.get('switch', True),
  4726. 'sn': rule.get('sn'),
  4727. }
  4728. if rule.get('pulse'):
  4729. washConfig[str(ruleId)].update({
  4730. 'pulse': rule.get('pulse'),
  4731. })
  4732. if rule.get('basePrice'):
  4733. washConfig[str(ruleId)].update({
  4734. 'basePrice': rule.get('basePrice'),
  4735. })
  4736. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  4737. washConfig[str(ruleId)].update({
  4738. 'billingMethod': rule['billingMethod'],
  4739. })
  4740. if rule.get('autoStop') != None:
  4741. washConfig[str(ruleId)].update({
  4742. 'basePrice': rule.get('basePrice'),
  4743. })
  4744. if rule.get('autoRefund') != None:
  4745. washConfig[str(ruleId)].update({
  4746. 'basePrice': rule.get('basePrice'),
  4747. })
  4748. 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]:
  4749. if len(serviceList) != 4:
  4750. return JsonErrorResponse(description=u'请勿增加或删除套餐')
  4751. # 如果设备直接可以下发套餐信息到设备,直接到设备上修改。比如串口洗衣机、串口的充电设备等
  4752. for devNo, dev in devDict.items():
  4753. if dev['devType']['code'] == Const.DEVICE_TYPE_CODE_WASHER:
  4754. smartBox = dev.deviceAdapter # type: WasherBox
  4755. try:
  4756. curConfig = smartBox.get_wash_config()
  4757. except ServiceException, e:
  4758. logger.exception('get washconfig to device=%s error=%s' % (devNo, e))
  4759. return JsonErrorResponse(description=u'读取设备套餐信息遇到错误:%s,请稍候再试试哦' % (e.result.get('description')))
  4760. try:
  4761. curConfig.update(setConfig)
  4762. smartBox.set_wash_config(curConfig)
  4763. except ServiceException, e:
  4764. logger.exception('set washconfig to device=%s error=%s' % (devNo, e))
  4765. return JsonErrorResponse(description=u'保存套餐到设备遇到错误:%s,请稍候再试试哦' % (e.result.get('description')))
  4766. if dev['devType']['code'] == Const.DEVICE_TYPE_CODE_HUITENG:
  4767. smartBox = dev.deviceAdapter # type: washerHTBox
  4768. cmdFlagDict = {u'单脱水': {'coins': '01', 'time': '09', 'baseTime': 5},
  4769. u'快速洗': {'coins': '02', 'time': '08', 'baseTime': 20},
  4770. u'标准洗': {'coins': '03', 'time': '07', 'baseTime': 35},
  4771. u'大物洗': {'coins': '04', 'time': '06', 'baseTime': 45}}
  4772. oldConfig = dev['washConfig']
  4773. for ruleId, rule in oldConfig.items():
  4774. try:
  4775. newRule = washConfig.get(ruleId)
  4776. if newRule['coins'] != rule['coins']:
  4777. smartBox.set_normal_value(cmdFlagDict[newRule['name']]['coins'], newRule['coins'])
  4778. if newRule['time'] != rule['time']:
  4779. baseTime = cmdFlagDict[newRule['name']]['baseTime']
  4780. if newRule['time'] < baseTime:
  4781. return JsonErrorResponse(description=u'您设置的套餐%s时间%s分钟,不能低于基础时间%s分钟' % (
  4782. newRule['name'], newRule['time'], baseTime))
  4783. addTime = newRule['time'] - baseTime
  4784. smartBox.set_normal_value(cmdFlagDict[newRule['name']]['time'], addTime)
  4785. except ServiceException, e:
  4786. return JsonErrorResponse(description=u'保存套餐到设备遇到错误:%s,请重试哦' % (e.result.get('description')))
  4787. if dev['devType']['code'] in [Const.DEVICE_TYPE_CODE_WASHER_CY_HS, Const.DEVICE_TYPE_CODE_WASHER_CY_HS_YUCHUAN]:
  4788. box = dev.deviceAdapter
  4789. washPriceMap = {
  4790. u"单脱水": "priceDt",
  4791. u"快速洗": "priceKs",
  4792. u"标准洗": "priceBz",
  4793. u"大物洗": "priceDw"
  4794. }
  4795. washTimeMap = {
  4796. u"单脱水": "timeDt",
  4797. u"快速洗": "timeKs",
  4798. u"标准洗": "timeBz",
  4799. u"大物洗": "timeDw"
  4800. }
  4801. priceData = {}
  4802. timeData = {}
  4803. for _, c in washConfig.items():
  4804. try:
  4805. priceData[washPriceMap.get(c.get("name"))] = c.get("coins")
  4806. timeData[washTimeMap.get(c.get("name"))] = c.get("time")
  4807. except Exception as e:
  4808. break
  4809. else:
  4810. try:
  4811. box.set_config_82(priceData)
  4812. box.set_config_83(timeData)
  4813. except ServiceException, e:
  4814. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  4815. # 烘干机
  4816. if dev['devType']['code'] == Const.DEVICE_TYPE_CODE_WASHER_CY_HS_HONGGAN:
  4817. box = dev.deviceAdapter
  4818. hongganPriceMap = {
  4819. u"加时烘干": "priceDt",
  4820. u"快速烘干": "priceKs",
  4821. u"标准烘干": "priceBz",
  4822. u"特别烘干": "priceDw"
  4823. }
  4824. hongganTimeMap = {
  4825. u"加时烘干": "timeDt",
  4826. u"快速烘干": "timeKs",
  4827. u"标准烘干": "timeBz",
  4828. u"特别烘干": "timeDw"
  4829. }
  4830. priceData = {}
  4831. timeData = {}
  4832. for _, c in washConfig.items():
  4833. try:
  4834. priceData[hongganPriceMap.get(c.get("name"))] = c.get("coins")
  4835. timeData[hongganTimeMap.get(c.get("name"))] = c.get("time")
  4836. except Exception as e:
  4837. break
  4838. else:
  4839. try:
  4840. box.set_config_82(priceData)
  4841. box.set_config_83(timeData)
  4842. except ServiceException, e:
  4843. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  4844. try:
  4845. dev['washConfig'] = washConfig
  4846. otherConf = dev.get('otherConf', {})
  4847. otherConf['displaySwitchs'] = displaySwitchs
  4848. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'washConfig': dev['washConfig'], 'otherConf':otherConf}})
  4849. request.user.defaultWashConfig[dev['devType']['id']] = dev['washConfig'].values()
  4850. request.user.save()
  4851. Device.invalid_device_cache(devNo)
  4852. except ServiceException, e:
  4853. logger.exception('update device washconfig error=%s,devNo=%s,washConfig=%s'
  4854. % (e, devNo, dev['washConfig']))
  4855. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  4856. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4857. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'设置默认组失败'))
  4858. @permission_required(ROLE.dealer, ROLE.subaccount)
  4859. def setDefaultGroup(request):
  4860. ownerId = str(request.user.bossId)
  4861. groupId = request.POST.get('groupId', None)
  4862. if groupId is None:
  4863. return JsonErrorResponse(description=u"缺少参数")
  4864. try:
  4865. success, description, group = Group.update_group(group_id=groupId, isDefault=True)
  4866. return JsonOkResponse() if success else JsonErrorResponse(description=description)
  4867. except Exception, e:
  4868. logger.exception('update error=%s' % e)
  4869. return JsonResponse({'result': 0, 'description': u"系统繁忙,请稍后再试", 'payload': {}})
  4870. @permission_required(ROLE.dealer, ROLE.subaccount)
  4871. def logout(request):
  4872. agentId = request.user.agentId
  4873. auth.logout(request)
  4874. response = JsonResponse({'result': 1, 'payload': agentId})
  4875. # 删除不在使用的COOKIE
  4876. response.delete_cookie(key='hasagent')
  4877. return response
  4878. @permission_required(ROLE.dealer, ROLE.subaccount)
  4879. def wxconfig(request):
  4880. url = request.GET.get('href')
  4881. if not url:
  4882. return JsonResponse({'result': 0, 'description': u'参数错误', 'payload': {}})
  4883. value = get_wx_config(request.user, url)
  4884. logger.exception('wx config url = %s' % url)
  4885. return JsonResponse({'result': 1, 'description': None, 'payload': {'wxconfig': value}})
  4886. @require_GET
  4887. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取库存详情失败'))
  4888. @permission_required(ROLE.dealer, ROLE.subaccount)
  4889. def stockDetails(request):
  4890. logicalCode = request.GET.get('logicalCode')
  4891. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  4892. dev = Device.get_dev(devNo)
  4893. if not dev:
  4894. return JsonErrorResponse(description=u'找不到设备')
  4895. return JsonResponse({'result': 1, "description": None, "payload": {"quantity": dev['quantity']}})
  4896. @require_POST
  4897. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新库存失败,请重试'))
  4898. @permission_required(ROLE.dealer, ROLE.subaccount)
  4899. def updateStockQuantity(request):
  4900. payload = json.loads(request.body)
  4901. lc = payload.get('logicalCode')
  4902. quantity = int(payload.get('quantity', 0))
  4903. devNo = Device.get_devNo_by_logicalCode(lc)
  4904. dev = Device.get_dev(devNo)
  4905. if dev['quantity'] > quantity:
  4906. stockType = 'remove'
  4907. stockNum = dev['quantity'] - quantity
  4908. else:
  4909. stockType = 'add'
  4910. stockNum = quantity - dev['quantity']
  4911. result = Device.update_field(dev_no=devNo, update=True, quantity=quantity, consumptionQuantity=0)
  4912. if not result:
  4913. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  4914. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  4915. StockRecord.get_collection().insert(
  4916. {'logicCode': lc, 'imei': dev['devNo'], 'stockType': stockType, 'stockTime': stockTime, 'number': stockNum})
  4917. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  4918. @permission_required(ROLE.dealer, ROLE.subaccount)
  4919. def getStockRecord(request):
  4920. lc = request.GET.get('logicalCode')
  4921. if not lc:
  4922. return JsonResponse({'result': 0, 'description': u'未接收到设备编码,请刷新重试', 'payload': {}})
  4923. pageIndex = int(request.GET.get('pageIndex', 1))
  4924. pageSize = int(request.GET.get('pageSize', 10))
  4925. startTime = defaultTodayDate(request.GET.get('startTime', None)) + ' ' + '00:00:00'
  4926. endTime = defaultTodayDate(request.GET.get('endTime', None)) + ' ' + '23:59:59'
  4927. rcds = StockRecord.get_collection().find({'logicCode': lc, 'stockTime': {'$gte': startTime, '$lte': endTime}}).sort(
  4928. 'stockTime', -1)
  4929. add, cost = 0, 0
  4930. sIndex = (pageIndex - 1) * pageSize
  4931. eIndex = pageIndex * pageSize
  4932. ii = 0
  4933. dataList = []
  4934. for rcd in rcds:
  4935. name = ''
  4936. if rcd['stockType'] == 'add':
  4937. add += rcd['number']
  4938. name = u'增加库存 ' + rcd.get('more', '')
  4939. elif rcd['stockType'] == 'remove':
  4940. cost += rcd['number']
  4941. name = u'减少库存 ' + rcd.get('more', '')
  4942. elif rcd['stockType'] == 'consume':
  4943. cost += rcd['number']
  4944. name = u'用户购买 ' + rcd.get('more', '')
  4945. elif rcd['stockType'] == 'adFree':
  4946. cost += rcd['number']
  4947. name = u'吸粉发放 ' + rcd.get('more', '')
  4948. if sIndex <= ii < eIndex:
  4949. dataList.append({'name': name, 'time': rcd['stockTime'], 'number': rcd['number']})
  4950. ii += 1
  4951. devNo = Device.get_devNo_by_logicalCode(lc)
  4952. dev = Device.get_dev(devNo)
  4953. para = {'total': ii, 'add': add, 'cost': cost, 'quantity': dev['quantity'], 'dataList': dataList}
  4954. return JsonResponse({'result': 1, 'description': None, 'payload': para})
  4955. @permission_required(ROLE.dealer, ROLE.subaccount)
  4956. def toggleSwitches(request):
  4957. paraDict = json.loads(request.body) if request.body else {}
  4958. if not paraDict:
  4959. return JsonErrorResponse(description=u'接收数据为空,请重试')
  4960. ownerId = request.user.bossId # type: ObjectId
  4961. if paraDict.get("hasTempPackage", None) == True:
  4962. paraDict["displayTempPackage"] = True
  4963. success = Dealer.update_dealer(ownerId, **paraDict)
  4964. if not success:
  4965. return JsonErrorResponse(description=u'更新失败,请重试')
  4966. else:
  4967. return JsonOkResponse()
  4968. @permission_required(ROLE.dealer, ROLE.subaccount)
  4969. def clearDeviceStatistics(request):
  4970. lc = request.POST.get('logicalCode')
  4971. devNo = Device.get_devNo_by_logicalCode(lc)
  4972. dev = Device.get_dev(devNo)
  4973. if not dev:
  4974. return JsonErrorResponse(description=u'找不到设备')
  4975. if dev['ownerId'] != str(request.user.bossId):
  4976. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  4977. if dev.get('devType', {}).get('code', '') not in [Const.DEVICE_TYPE_CODE_WASHCAR_LSHB]:
  4978. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  4979. try:
  4980. smartBox = ActionDeviceBuilder.create_action_device(dev)
  4981. smartBox.clear_dev_feecount()
  4982. except ServiceException, e:
  4983. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  4984. return JsonResponse({'result': 1, 'description': u'', 'payload': {}})
  4985. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  4986. @permission_required(ROLE.dealer, ROLE.subaccount)
  4987. def getDeviceFunction(request):
  4988. payload = json.loads(request.body)
  4989. lc = payload.get("logicalCode")
  4990. if isinstance(lc, list) and len(lc):
  4991. lc = lc[0]
  4992. else:
  4993. raise JsonErrorResponse(description=u"无效的设备编号")
  4994. devNo = Device.get_devNo_by_logicalCode(lc)
  4995. dev = Device.get_dev(devNo)
  4996. if not dev:
  4997. return JsonResponse({'result': 0, 'description': u'未找到该设备', 'payload': {}})
  4998. try:
  4999. smartBox = ActionDeviceBuilder.create_action_device(dev)
  5000. setConf = smartBox.get_dev_setting()
  5001. if setConf is None:
  5002. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  5003. if len(payload.get("logicalCode")) > 1:
  5004. serviceCache.set('lastsettingConf_owner%s' % (str(request.user.id)), setConf, 600)
  5005. else:
  5006. caches['devmgr'].set('settingConf_%s' % (devNo,), setConf, 600)
  5007. return JsonResponse({'result': 1, 'description': u'', 'payload': setConf})
  5008. except ServiceException, e:
  5009. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  5010. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  5011. @permission_required(ROLE.dealer, ROLE.subaccount)
  5012. def getDeviceFunctionForIC(request):
  5013. payload = json.loads(request.body)
  5014. lc = payload.get("logicalCode")
  5015. if isinstance(lc, list) and len(lc):
  5016. lc = lc[0]
  5017. else:
  5018. raise JsonErrorResponse(description=u"无效的设备编号")
  5019. devNo = Device.get_devNo_by_logicalCode(lc)
  5020. dev = Device.get_dev(devNo)
  5021. if not dev:
  5022. return JsonResponse({'result': 0, 'description': u'未找到该设备', 'payload': {}})
  5023. try:
  5024. smartBox = ActionDeviceBuilder.create_action_device(dev)
  5025. setConf = smartBox.get_IC_card_password()
  5026. if setConf is None:
  5027. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  5028. caches['devmgr'].set('settingConf_%s' % (devNo,), setConf, 600)
  5029. return JsonResponse({'result': 1, 'description': u'', 'payload': setConf})
  5030. except ServiceException, e:
  5031. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  5032. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  5033. @permission_required(ROLE.dealer, ROLE.subaccount)
  5034. def setDeviceFunction(request):
  5035. # type: (WSGIRequest)->JsonResponse
  5036. payload = json.loads(request.body)
  5037. lc = payload.get("logicalCode")
  5038. if isinstance(lc, list) and len(lc):
  5039. lc = lc[0]
  5040. else:
  5041. raise JsonErrorResponse(description=u"无效的设备编号")
  5042. requestBody = RequestBodyDict({"POST": payload})
  5043. devNo = Device.get_devNo_by_logicalCode(lc)
  5044. dev = Device.get_dev(devNo)
  5045. if not dev:
  5046. return JsonErrorResponse(description=u'找不到设备')
  5047. if dev['ownerId'] != str(request.user.bossId):
  5048. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  5049. lastSetConf = caches['devmgr'].get('settingConf_%s' % (devNo,))
  5050. box = ActionDeviceBuilder.create_action_device(dev)
  5051. try:
  5052. box.set_device_function(requestBody, lastSetConf)
  5053. except ServiceException, e:
  5054. logger.exception('set info to device=%s error=%s' % (devNo, e))
  5055. return JsonResponse(
  5056. {'result': 0, 'description': u'设置参数遇到错误:%s' % (e.result.get('description', '')), 'payload': {}})
  5057. if lastSetConf is not None:
  5058. caches['devmgr'].set('settingConf_%s' % devNo, lastSetConf)
  5059. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  5060. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  5061. @permission_required(ROLE.dealer, ROLE.subaccount)
  5062. def setDeviceFunctionParam(request):
  5063. # type: (WSGIRequest)->JsonResponse
  5064. updateConf = json.loads(request.body)
  5065. logicalCodes = updateConf.pop('logicalCode')
  5066. # 替代品 先将 request 和 adapter的功能函数解耦 后续逐步修改
  5067. requestBody = RequestBodyDict({"POST": updateConf})
  5068. if len(logicalCodes) > 1:
  5069. setMode = updateConf.pop('modifyMode', None)
  5070. dev = Device.get_dev_by_l(logicalCodes[0])
  5071. dev_owner = dev.ownerId
  5072. dev_type_code = dev.devType.get('code')
  5073. for logicalCode in logicalCodes[1:]:
  5074. dev = Device.get_dev_by_l(logicalCode)
  5075. if dev_owner != dev.ownerId or dev_type_code != dev.devType.get('code'):
  5076. return JsonErrorResponse(description=u"设备经销商不同或者不同类型设备")
  5077. beforeConf = serviceCache.get('lastsettingConf_owner%s' % (str(request.user.id))) # type: Dict
  5078. if not beforeConf:
  5079. return JsonErrorResponse(description=u"查询当前配置信息失败")
  5080. if setMode == 'diff':
  5081. # 找出发生改变的参数项
  5082. for key, oldValue in beforeConf.iteritems():
  5083. if key in updateConf and str(updateConf[key]) == str(oldValue):
  5084. updateConf.pop(key)
  5085. if not updateConf:
  5086. return JsonErrorResponse(description=u"您没有修改任何参数")
  5087. payload = {'updateConf': updateConf, 'lastSetConf': None, 'logicalCodes': logicalCodes}
  5088. else:
  5089. payload = {'updateConf': updateConf, 'lastSetConf': beforeConf, 'logicalCodes': logicalCodes}
  5090. payload.update({
  5091. 'operationId': '{}_{}'.format(str(request.user.id), int(time.time()))
  5092. })
  5093. from taskmanager.mediator import task_caller
  5094. task_caller('batch_set_device_params', **payload)
  5095. serviceCache.set(payload['operationId'], payload, 600)
  5096. return JsonResponse({'result': 1, 'description': None, 'payload': {'operationId': payload['operationId']}})
  5097. else:
  5098. logicalCode = logicalCodes[0]
  5099. dealer = Dealer.objects(id=str(request.user.id)).first()
  5100. if dealer is None:
  5101. return JsonErrorResponse(description=u"设备的经销商不存在")
  5102. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  5103. dev = Device.get_dev(devNo)
  5104. if dev is None:
  5105. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  5106. if dev['ownerId'] != str(request.user.bossId):
  5107. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  5108. beforeConf = caches['devmgr'].get('settingConf_%s' % (devNo,))
  5109. if not beforeConf:
  5110. try:
  5111. beforeConf = dev.deviceAdapter.get_dev_setting()
  5112. if not beforeConf:
  5113. return JsonResponse({'result': 0, 'description': u'当前设备不支持该操作', 'payload': {}})
  5114. except Exception as e:
  5115. logger.exception(e)
  5116. return JsonResponse({'result': 0, 'description': u'查询设备当前配置信息失败', 'payload': {}})
  5117. operation = OperatorLog.record_dev_setting_changes_log(
  5118. dealer, 'record_someone_set_devSettings', dev['logicalCode'], dev['devType']['code'],
  5119. {
  5120. 'beforeCacheStr': json.dumps(beforeConf), 'afterCacheStr': json.dumps(updateConf)
  5121. }) # type: OperatorLog
  5122. try:
  5123. dev.deviceAdapter.set_device_function_param(requestBody, beforeConf)
  5124. operation.update(content__status='success')
  5125. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  5126. except ServiceException, e:
  5127. logger.info('error happened, error=%s' % (e,))
  5128. operation.update(content__status='fail', content_desc=e.result.get('description'))
  5129. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  5130. except InvalidParameter as e:
  5131. logger.exception(e)
  5132. operation.update(content__status='fail', content_desc=e.message)
  5133. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5134. except Exception, e:
  5135. operation.update(content__status='fail', content_desc=u'系统异常')
  5136. logger.exception('error happened, error=%s' % (e,))
  5137. return JsonResponse({'result': 0, 'description': u'系统异常,请检查输入参数,或者稍后重试', 'payload': {}})
  5138. @permission_required(ROLE.dealer, ROLE.subaccount)
  5139. def deviceParamsResult(request):
  5140. user = request.user
  5141. operationId = request.GET.get('operationId', None)
  5142. if not operationId:
  5143. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  5144. payload = serviceCache.get(operationId, {})
  5145. if not payload:
  5146. operations = OperatorLog.objects.filter(operatorId=str(user.id),
  5147. role=user.role,
  5148. content__operationId=operationId)
  5149. dataList = list(map(lambda operation: {'id': str(operation.id), 'logicalCode': operation.content['logicalCode'],
  5150. 'status': operation.content.get('status')}, operations))
  5151. else:
  5152. logicalCodes = payload.get('logicalCodes', [])
  5153. operations = OperatorLog.objects.filter(operatorId=str(user.id),
  5154. role=user.role,
  5155. content__logicalCode__in=logicalCodes,
  5156. content__operationId=operationId)
  5157. dataList = list(map(lambda operation: {'id': str(operation.id), 'logicalCode': operation.content['logicalCode'],
  5158. 'status': operation.content.get('status')}, operations))
  5159. if len(operations) != len(logicalCodes):
  5160. leftLogicalCodes = set(logicalCodes) - set(operations.values_list('logicalCode'))
  5161. for logicalCode in leftLogicalCodes:
  5162. dataList.append({'id': None, 'logicalCode': logicalCode, 'status': 'waiting'})
  5163. return JsonResponse({'result': 1, 'description': None, 'payload': {'dataList':dataList}})
  5164. @permission_required(ROLE.dealer, ROLE.subaccount)
  5165. def retryingSettingsDeviceParams(request):
  5166. dev_oper_id = request.GET.get('id')
  5167. operation = OperatorLog.objects.filter(id=dev_oper_id).first() # type: OperatorLog
  5168. logicalCode = operation.content['logicalCode']
  5169. dev = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  5170. if not dev:
  5171. return JsonResponse({'result': 0, 'description': u'该设备不存在', 'payload': {}})
  5172. if dev.ownerId != request.user.bossId:
  5173. return JsonResponse({'result': 0, 'description': u'您无权操作该设备', 'payload': {}})
  5174. try:
  5175. if operation.operatorName == 'record_someone_set_devSettings':
  5176. updateConf = json.loads(operation.content.get('updateConfStr'))
  5177. beforeCacheStr = json.loads(operation.content.get('beforeCacheStr'))
  5178. requestBody = RequestBodyDict({"POST": updateConf})
  5179. dev.deviceAdapter.set_device_function(requestBody, beforeCacheStr)
  5180. dev.deviceAdapter.set_device_function_param(requestBody, beforeCacheStr)
  5181. elif operation.operatorName == 'setServerSetting':
  5182. payload = json.loads(operation.content.get('after'))
  5183. dev.deviceAdapter.set_server_setting(payload)
  5184. except ServiceException, e:
  5185. logger.info('error happened, error=%s' % (e,))
  5186. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  5187. except InvalidParameter as e:
  5188. logger.exception(e)
  5189. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5190. else:
  5191. operation.update(content__status='success')
  5192. return JsonResponse({'result': 1, 'description': '重试成功', 'payload': {'status': 'success'}})
  5193. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取卡列表失败'))
  5194. @permission_required(ROLE.dealer, ROLE.subaccount)
  5195. def getUserCardList(request):
  5196. pageIndex = int(request.GET.get('pageIndex', 1))
  5197. pageSize = int(request.GET.get('pageSize', 10))
  5198. searchKey = str(request.GET.get('searchKey', ''))
  5199. userId = str(request.GET.get('userId', ''))
  5200. equipmentGroupId = str(request.GET.get('equipmentGroupId'))
  5201. frozen = request.GET.get("frozen", None)
  5202. dealerId = str(request.user.bossId)
  5203. queryDict = {
  5204. "dealerId": dealerId,
  5205. 'openId': userId or {'$exists': True}
  5206. }
  5207. if frozen:
  5208. queryDict.update({"frozen": bool(int(frozen))})
  5209. if searchKey:
  5210. queryDict.update(search_query(['cardName', 'phone', "cardNo"], searchKey).to_query(Card))
  5211. if equipmentGroupId:
  5212. queryDict.update({'groupId': equipmentGroupId})
  5213. cards = Card.objects.filter(__raw__=queryDict).skip((pageIndex - 1) * pageSize).limit(pageSize)
  5214. dataList = list()
  5215. for card in cards: # type: Card
  5216. dataList.append({
  5217. "cardName": card.cardName,
  5218. "phone": card.phone,
  5219. "groupId": card.groupId,
  5220. "groupName": card.group.groupName if card.group else "",
  5221. "cardId": str(card.id),
  5222. "bindStatus": card.isBinded,
  5223. "dealerId": card.dealerId,
  5224. "remarks": card.remarks,
  5225. "balance": card.balance,
  5226. "cardNo": card.cardNo,
  5227. "frozen": int(card.frozen)
  5228. })
  5229. payload = {
  5230. "total": get_paginate(dataList, pageSize=pageSize, pageIndex=pageIndex),
  5231. "dataList": dataList,
  5232. "agentId": request.user.agentId
  5233. }
  5234. return JsonResponse({"result": 1, "description": "", "payload": payload})
  5235. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取详情失败'))
  5236. @permission_required(ROLE.dealer, ROLE.subaccount)
  5237. def getUserCard(request):
  5238. cardId = request.GET.get("cardId", "")
  5239. try:
  5240. card = Card.objects.get(id=cardId)
  5241. except DoesNotExist:
  5242. return JsonErrorResponse(description=u"无效的卡")
  5243. except Exception as e:
  5244. logger.exception(e)
  5245. return JsonErrorResponse(description=u"获取卡详情失败,请刷新页面试试")
  5246. if card.dealerId != str(request.user.bossId):
  5247. return JsonErrorResponse(u"获取详情失败")
  5248. group = card.group
  5249. data = {
  5250. "cardId": cardId,
  5251. "cardNo": card.cardNo,
  5252. "cardName": card.cardName,
  5253. "groupId": card.groupId,
  5254. "dealerId": card.dealerId,
  5255. "groupName": group.groupName if group is not None else '',
  5256. "frozen": card.frozen,
  5257. "phone": card.phone,
  5258. "status": card.status,
  5259. "bindStatus": card.isBinded,
  5260. "balance": "{:.2f}".format(float(card.balance)),
  5261. "chargeBalance": "{:.2f}".format(float(card.chargeBalance)),
  5262. "bestowBalance": "{:.2f}".format(float(card.bestowBalance)),
  5263. "cardType": card.cardType
  5264. }
  5265. return JsonOkResponse(payload=data)
  5266. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"编辑卡失败"))
  5267. @permission_required(ROLE.dealer, ROLE.subaccount)
  5268. def editCard(request):
  5269. """
  5270. 经销商端 编辑卡片信息 可编辑内容 为 绑定设备组 卡名称 联系方式
  5271. :param request:
  5272. :return:
  5273. """
  5274. payload = json.loads(request.body)
  5275. cardId = payload.get("cardId")
  5276. cardName = payload.get("cardName")
  5277. phone = payload.get("phone")
  5278. groupId = payload.get("groupId")
  5279. try:
  5280. card = Card.objects.get(id=cardId)
  5281. except DoesNotExist:
  5282. return JsonErrorResponse(description=u"修改卡失败")
  5283. if phone and not PHONE_NUMBER_RE.match(phone):
  5284. return JsonErrorResponse(description=u"手机号码输入错误")
  5285. if cardName and not NAME_RE.match(cardName):
  5286. return JsonErrorResponse(description=u"请输入正确格式的名称(2-20位)")
  5287. if card.dealerId != str(request.user.bossId):
  5288. return JsonErrorResponse(description=u"不是您的卡片,无权修改")
  5289. group = Group.get_group(groupId)
  5290. if not group:
  5291. return JsonErrorResponse(description=u"请选择正确的设备组")
  5292. if group.get("ownerId") != str(request.user.bossId):
  5293. return JsonErrorResponse(description=u"请选择正确的设备组")
  5294. card.cardName = cardName
  5295. card.phone = phone
  5296. card.groupId = groupId
  5297. card.save()
  5298. return JsonOkResponse()
  5299. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"录卡失败"))
  5300. @permission_required(ROLE.dealer, ROLE.subaccount)
  5301. def saveEntityCard(request):
  5302. # type: (WSGIRequest)->JsonResponse
  5303. payload = json.loads(request.body)
  5304. cardNo = payload.get('cardNo', '')
  5305. phone = payload.get('phone', '')
  5306. cardName = payload.get('cardName', '')
  5307. groupId = payload.get("groupId", "")
  5308. dealerId = str(request.user.bossId)
  5309. # 卡号前置去0
  5310. if cardNo.isdigit():
  5311. cardNo = str(int(cardNo))
  5312. if not cardNo or not Card.check_card_no(cardNo):
  5313. return JsonErrorResponse(description=u"卡号不符合规则,请输入正确的卡号")
  5314. groupIds = Group.get_group_ids_of_dealer(dealerId)
  5315. if not groupId or groupId not in groupIds:
  5316. return JsonErrorResponse(description=u"请选择正确的设备组")
  5317. if phone and not PHONE_NUMBER_RE.match(phone):
  5318. return JsonErrorResponse(description=u"手机号码输入错误")
  5319. if cardName and not NAME_RE.match(cardName):
  5320. return JsonResponse({"result": 0, "description": u"请输入正确格式的名称(2-20位)"})
  5321. agentId = request.user.agentId
  5322. # 基于卡号找 代理商下的卡 或者平台下的卡
  5323. card = Card.objects.filter(Q(agentId=agentId) | Q(agentId=''), cardNo=cardNo).first()
  5324. if not card:
  5325. card = Card(
  5326. cardNo=cardNo,
  5327. dealerId=dealerId,
  5328. agentId=agentId,
  5329. cardName=cardName,
  5330. groupId=groupId,
  5331. phone=phone,
  5332. openId=Const.DEFAULT_CARD_OPENID
  5333. ).save()
  5334. return JsonResponse({"result": 1, "description": u"录入成功", "payload": {'cardId':str(card.id)}})
  5335. else:
  5336. if card.dealerId: # 有经销商注册
  5337. if card.dealerId == dealerId:
  5338. return JsonErrorResponse(description=u"{} 卡已经被您收录,请不要重复收录".format(cardNo))
  5339. else:
  5340. return JsonErrorResponse(description="{} 卡已被其他经销商录入,请确认卡号不要重复".format(cardNo))
  5341. else: # 此代理商平台下没有经销商注册该卡片
  5342. card.dealerId = dealerId
  5343. card.agentId = agentId
  5344. card.cardName = cardName
  5345. card.groupId = groupId
  5346. card.phone = phone
  5347. card.openId = Const.DEFAULT_CARD_OPENID
  5348. card.save()
  5349. return JsonResponse({"result": 1, "description": u"录入成功", "payload": {'cardId': str(card.id)}})
  5350. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"补卡失败"))
  5351. @permission_required(ROLE.dealer, ROLE.subaccount)
  5352. def swapCardNo(request):
  5353. """
  5354. 补卡 需要生成补卡记录,不重新创建新卡 如果新卡的卡号已经存在但是没有绑定用户并且内部没余额
  5355. :param request:
  5356. :return:
  5357. """
  5358. payload = json.loads(request.body)
  5359. cardNo = payload.get("cardNo", "")
  5360. cardId = payload.get("cardId")
  5361. dealerId = str(request.user.bossId)
  5362. # 卡号前置去0
  5363. if cardNo.isdigit():
  5364. cardNo = str(int(cardNo))
  5365. if not Card.check_card_no(cardNo):
  5366. return JsonErrorResponse(description=u"无效的卡号,卡号长度不能超过10位")
  5367. try:
  5368. oldCard = Card.objects.get(id=cardId)
  5369. except DoesNotExist:
  5370. return JsonErrorResponse(description=u"查询旧卡失败")
  5371. if oldCard.cardNo == cardNo:
  5372. return JsonErrorResponse(description=u"卡号一致无需修改")
  5373. if oldCard.dealerId != dealerId:
  5374. return JsonErrorResponse(description=u"无权编辑此卡")
  5375. checkStatus, checkMsg = Card.check_swap_card_no(cardNo, dealerId, oldCard.agentId)
  5376. if not checkStatus:
  5377. return JsonErrorResponse(description=checkMsg)
  5378. # 直接将卡号更新掉,然后新建一条换卡记录
  5379. oldCard.update(cardNo=cardNo)
  5380. SwapCardRecord.add_record(oldCard.cardNo, cardNo, oldCard.agentId, str(request.user.id))
  5381. return JsonOkResponse()
  5382. @record_operation_behavior()
  5383. @permission_required(ROLE.dealer, ROLE.subaccount)
  5384. def deleteInitCard(request):
  5385. cardId = json.loads(request.body).get("cardId")
  5386. card = Card.objects.filter(id=cardId, dealerId=str(request.user.bossId)).first()
  5387. if not card:
  5388. return JsonResponse({"result": 0, "description": u"未找到该实体卡", "payload": {}})
  5389. updated = card.clear_card()
  5390. if not updated:
  5391. return JsonErrorResponse(description=u'操作失败')
  5392. return JsonResponse({"result": 1, "description": u"删除成功", "payload": {}})
  5393. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取卡记录失败'))
  5394. @permission_required(ROLE.dealer, ROLE.subaccount)
  5395. def getUserCardRecord(request):
  5396. # type: (WSGIRequest)->JsonResponse
  5397. pageIndex = int(request.GET.get('pageIndex', 1))
  5398. pageSize = int(request.GET.get('pageSize', 10))
  5399. startTime = request.GET.get('startTime', 10)
  5400. endTime = request.GET.get('endTime', 10)
  5401. cardId = request.GET.get('cardId', None)
  5402. type = request.GET.get('type', None)
  5403. card = Card.objects.get(id=cardId)
  5404. if type == "chargeCard":
  5405. dataList = []
  5406. # TODO zjl 订单统一 不要这样搞得很别扭
  5407. viaMap = {
  5408. u"退币": "refund",
  5409. u"充值": "chargeCard"
  5410. }
  5411. for item in CardRechargeRecord.get_collection().find({
  5412. 'cardId': cardId,
  5413. 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5414. '$lte': to_datetime(endTime + " 23:59:59")}}).sort("dateTimeAdded", -1):
  5415. data = {
  5416. "cardId": str(item['_id']),
  5417. "cardNo": card.cardNo,
  5418. "via": viaMap.get(item.get("remarks"), "chargeCard"),
  5419. "amount": item['money'],
  5420. "coins": item.get('coins', item['money']),
  5421. "address": item['address'],
  5422. "groupName": item['groupName'],
  5423. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'),
  5424. "rechargeType": item.get("rechargeType")
  5425. }
  5426. if item.has_key('preBalance'):
  5427. data.update({'preBalance': item['preBalance']})
  5428. if item.has_key('balance'):
  5429. data.update({'balance': item['balance']})
  5430. if item.get("remarks", None):
  5431. data.update({'remarks': item['remarks']})
  5432. if item.get("logicalCode"):
  5433. data.update({"devType": Device.get_dev_by_logicalCode(item['logicalCode']).get("devType", dict()).get("name", "")})
  5434. data.update({"logicalCode": item['logicalCode']})
  5435. dataList.append(data)
  5436. elif type == "consume":
  5437. dataList = []
  5438. rcds = CardConsumeRecord.get_collection().find(
  5439. {'cardId': cardId, 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5440. '$lte': to_datetime(endTime + " 23:59:59")}}).sort(
  5441. "dateTimeAdded", -1)
  5442. for item in rcds:
  5443. newData = {
  5444. "cardId": str(item['_id']),
  5445. "cardNo": card.cardNo,
  5446. "via": "consume",
  5447. "devType": item['devType'],
  5448. "amount": item['money'],
  5449. "logicalCode": item['logicalCode'],
  5450. "address": item['address'],
  5451. "groupName": item['groupName'],
  5452. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S')
  5453. }
  5454. if item.has_key('balance'):
  5455. newData.update({'balance': item['balance']})
  5456. newData.update(item.get('servicedInfo', {}))
  5457. dataList.append(newData)
  5458. elif type == 'order':
  5459. dataList = []
  5460. for item in CardRechargeOrder.get_collection().find({
  5461. 'cardId': cardId,
  5462. 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5463. '$lte': to_datetime(endTime + " 23:59:59")}}).sort("dateTimeAdded", -1):
  5464. data = {
  5465. "via": "order",
  5466. "amount": item['money'],
  5467. "coins": item.get('coins', item['money']),
  5468. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'),
  5469. "status": u'等待用户刷卡充值' if item['status'] == 'finishedPay' else u'充值完成',
  5470. "desc": item['remarks'],
  5471. "rechargeType": item.get("rechargeType")
  5472. }
  5473. if item.has_key('preBalance'):
  5474. data.update({'preBalance': item['preBalance']})
  5475. if item.has_key('balance'):
  5476. data.update({'balance': item['balance']})
  5477. dataList.append(data)
  5478. elif type == 'cardConsume':
  5479. card = Card.objects.filter(id=cardId).first()
  5480. dataList = []
  5481. orders = ConsumeRecord.get_collection().find({
  5482. 'openId': str(card.openId),
  5483. 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5484. '$lte': to_datetime(endTime + " 23:59:59")}}).sort("dateTimeAdded", -1)
  5485. for item in orders:
  5486. data = {
  5487. "via": "consume",
  5488. "amount":item.get('coin', item['money']),
  5489. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'),
  5490. "orderNo":item.get('orderNo'),
  5491. "status": u'完成',
  5492. "desc": item['remarks']
  5493. }
  5494. dataList.append(data)
  5495. else:
  5496. return JsonResponse({"result": 0, "description": u"查询类型错误", "payload": {}})
  5497. return JsonResponse(
  5498. {
  5499. "result": 1,
  5500. "description": "",
  5501. "payload": {
  5502. "total": len(dataList),
  5503. "dataList": dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  5504. }
  5505. })
  5506. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  5507. @permission_required(ROLE.dealer, ROLE.subaccount)
  5508. def getDeviceFunctionByKey(request):
  5509. # type: (WSGIRequest)->JsonResponse
  5510. try:
  5511. payload = json.loads(request.body)
  5512. key = payload.get('key', None)
  5513. # 兼容真谷多
  5514. port = payload.get("portIndex", None)
  5515. if port is not None:
  5516. key = port
  5517. logicalCode = payload.get('logicalCode', None)
  5518. if isinstance(logicalCode, list) and len(logicalCode):
  5519. logicalCode = logicalCode[0]
  5520. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  5521. dev = Device.get_dev(devNo)
  5522. lastSetConf = caches['devmgr'].get('settingConf_%s' % (devNo,))
  5523. if not lastSetConf:
  5524. lastSetConf = {}
  5525. box = ActionDeviceBuilder.create_action_device(dev)
  5526. payload = box.get_device_function_by_key(key)
  5527. if payload is not None:
  5528. if lastSetConf is None:
  5529. lastSetConf = payload
  5530. else:
  5531. lastSetConf.update(payload)
  5532. caches['devmgr'].set('settingConf_%s' % (devNo,), lastSetConf, 600)
  5533. return JsonResponse({"result": 1, "description": "", "payload": payload})
  5534. except ServiceException, e:
  5535. return JsonResponse({"result": 0, "description": e.result.get('description', ''), "payload": {}})
  5536. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'设置错误'))
  5537. @permission_required(ROLE.dealer, ROLE.subaccount)
  5538. def setDeviceFunctionByKey(request):
  5539. # type: (WSGIRequest)->JsonResponse
  5540. payload = json.loads(request.body)
  5541. logicalCode = payload.get('logicalCode', None)
  5542. if isinstance(logicalCode, list) and len(logicalCode):
  5543. logicalCode = logicalCode[0]
  5544. else:
  5545. return JsonErrorResponse(description=u"错误的二维码编号")
  5546. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  5547. dev = Device.get_dev(devNo)
  5548. keyName = payload.get('key', None)
  5549. if keyName is None:
  5550. return JsonResponse({"result": 0, "description": u'没有按下任何控制键', "payload": {}})
  5551. try:
  5552. box = ActionDeviceBuilder.create_action_device(dev)
  5553. box.press_down_key(keyName)
  5554. return JsonResponse({"result": 1, "description": '', "payload": {}})
  5555. except ServiceException, e:
  5556. logger.exception('cannot setDeviceFunctionByKey, error=%s' % (e.result.get('description', '').encode('utf-8'),))
  5557. return JsonResponse({"result": 0, "description": e.result.get('description', ''), "payload": {}})
  5558. @error_tolerate(nil=DefaultJsonErrorResponse)
  5559. @permission_required(ROLE.dealer, ROLE.subaccount)
  5560. def wechatEntry(request):
  5561. # type: (WSGIRequest)->JsonResponse
  5562. """
  5563. 必须每次都进行鉴权
  5564. :param request:
  5565. :return:
  5566. """
  5567. current_user = request.user # type: Dealer
  5568. if not check_role(current_user, ROLE.dealer):
  5569. return ErrorResponseRedirect(error = u'权限错误')
  5570. entryType = request.GET.get('type')
  5571. if entryType not in ['simCard', 'apiQuota', 'disableAdQuota']:
  5572. return ErrorResponseRedirect(error = u'参数错误(10001)')
  5573. if entryType == 'simCard': # 流量卡充值
  5574. my_agent = Agent.get_inhouse_prime_agent()
  5575. app = get_app(my_agent, APP_TYPE.WECHAT_ENV_PAY, role = ROLE.dealer)
  5576. elif entryType == 'apiQuota': # api设备配额数量充值
  5577. my_agent = Agent.get_inhouse_prime_agent()
  5578. app = get_app(my_agent, APP_TYPE.WECHAT_ENV_PAY, role=ROLE.dealer)
  5579. elif entryType == 'disableAdQuota': # api设备配额数量充值
  5580. my_agent = Agent.get_inhouse_prime_agent()
  5581. app = get_app(my_agent, APP_TYPE.WECHAT_ENV_PAY, role=ROLE.dealer)
  5582. else:
  5583. return ErrorResponseRedirect(error=u'参数错误(10002)')
  5584. if isinstance(app, WechatPayApp):
  5585. auth_bridge = WechatAuthBridge(app) # type: WechatAuthBridge
  5586. else:
  5587. return ErrorResponseRedirect(error=u'参数错误(10003)')
  5588. auth_code = request.GET.get(auth_bridge.auth_code_key, None)
  5589. if auth_code:
  5590. openId = auth_bridge.authorize(auth_code)
  5591. if openId is not None:
  5592. redirect = base64.b64decode(request.GET.get('payload'))
  5593. redirect = add_query(redirect, {
  5594. 'openId': openId
  5595. })
  5596. return FrontEndResponseRedirect(redirect)
  5597. else:
  5598. return ErrorResponseRedirect(error=u'系统繁忙,请重试')
  5599. else:
  5600. redirect_url = concat_server_end_url(uri='/dealer/wechat/entry?type={}'.format(entryType))
  5601. return ExternalResponseRedirect(
  5602. auth_bridge.generate_auth_url_base_scope(
  5603. redirect_uri=redirect_url,
  5604. payload=base64.b64encode(request.GET.get('redirect'))))
  5605. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'冻结卡失败'))
  5606. @permission_required(ROLE.dealer, ROLE.subaccount)
  5607. def freezeCard(request):
  5608. # type: (WSGIRequest)->JsonResponse
  5609. payload = json.loads(request.body)
  5610. frozen = payload.get('frozen')
  5611. cardId = payload.get('id', '')
  5612. try:
  5613. card = Card.objects.get(id=cardId)
  5614. card.frozen = frozen
  5615. card.status = 'active'
  5616. card.save()
  5617. except Exception, e:
  5618. logger.exception(e.message)
  5619. return JsonResponse({"result": 0, "description": u'系统错误', "payload": {}})
  5620. return JsonResponse({"result": 1, "description": '', "payload": {}})
  5621. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误'))
  5622. @permission_required(ROLE.dealer, ROLE.subaccount)
  5623. def getWalletWithdrawInfo(request):
  5624. dealer = request.user # type: Dealer
  5625. if not is_dealer(dealer):
  5626. return ErrorResponseRedirect(error = u'子账号无提现权限')
  5627. source_key = request.GET.get('sourceId')
  5628. income_type = request.GET.get('sourceType')
  5629. phone = str(dealer.monitorPhone) if dealer.monitorPhone else str(dealer.username)
  5630. result = {
  5631. "result": 1,
  5632. "description": None,
  5633. 'payload': {
  5634. 'payOpenId': 'placeholder',
  5635. 'phone': phone,
  5636. 'balance': dealer.sub_balance(income_type, source_key),
  5637. 'withdrawFeeRatio': dealer.withdrawFeeRatio,
  5638. 'support': dealer.withdraw_support(source_key)
  5639. }
  5640. }
  5641. return JsonResponse(result)
  5642. @require_POST
  5643. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5644. @permission_required(ROLE.dealer, ROLE.subaccount)
  5645. def getFeatureList(request):
  5646. # type: (WSGIRequest)->JsonResponse
  5647. """
  5648. :param request:
  5649. :return:
  5650. """
  5651. currentUser = request.user # type: Dealer
  5652. payload = json.loads(request.body)
  5653. queryList = payload.get('list', [])
  5654. resultFeatures = currentUser.query_feature_by_list(queryList)
  5655. if 'blackListManage' in currentUser.features:
  5656. resultFeatures.update({'blackListManage': True})
  5657. return JsonOkResponse(payload=resultFeatures)
  5658. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5659. @permission_required(ROLE.dealer, ROLE.subaccount)
  5660. def getOnsaleTypeList(request):
  5661. # type: (WSGIRequest)->JsonResponse
  5662. dataList = []
  5663. for typeName, info in OnSale.onsaleTypeDict.items():
  5664. dataList.append(
  5665. {
  5666. 'typeName': typeName,
  5667. 'desc': info['desc'],
  5668. 'img': info['img']
  5669. }
  5670. )
  5671. return JsonResponse({'result': 1, 'description': '', 'payload': {'total': len(dataList), 'dataList': dataList}})
  5672. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5673. @permission_required(ROLE.dealer, ROLE.subaccount)
  5674. def getOnsaleList(request):
  5675. # type: (WSGIRequest)->JsonResponse
  5676. """
  5677. 列出所有 经销商的活动尚未删除的
  5678. :param request:
  5679. :return:
  5680. """
  5681. pageIndex = int(request.GET.get('pageIndex', 1))
  5682. pageSize = int(request.GET.get('pageSize', 10))
  5683. searchKey = request.GET.get('searchKey', None)
  5684. dealerId = str(request.user.bossId)
  5685. onsales = OnSale.objects.filter(dealerId=dealerId, name__startswith=searchKey).order_by("-id")
  5686. dataList = [_obj.to_dict() for _obj in onsales[(pageIndex - 1) * pageSize: pageIndex * pageSize]]
  5687. return JsonOkResponse(payload={"total": len(dataList), "dataList": dataList})
  5688. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5689. @permission_required(ROLE.dealer, ROLE.subaccount)
  5690. def createOnsale(request):
  5691. # type: (WSGIRequest)->JsonResponse
  5692. dealerId = str(request.user.bossId)
  5693. payload = json.loads(request.body) if request.body else {}
  5694. if not payload:
  5695. return JsonErrorResponse(description=u'传入数据为空')
  5696. payload['startTime'] = to_datetime(payload['startTime'] + ' 00:00:00')
  5697. payload['endTime'] = to_datetime(payload['endTime'] + ' 23:59:59')
  5698. onsale = OnSale(**payload)
  5699. name = onsale.name
  5700. # 检查活动的名称
  5701. count = OnSale.objects.filter(dealerId=dealerId, name=name).count()
  5702. if count > 0:
  5703. return JsonResponse({'result': 0, 'description': u'活动名称重复,优惠活动的名称必须唯一', 'payload': {}})
  5704. # 检查下该经销商是否符合资格配置该活动
  5705. if onsale.onsaleType == u"京东新人1分购":
  5706. dealer = Dealer.objects.get(id=dealerId)
  5707. if not dealer.isJosEnable():
  5708. return JsonResponse({"result": 0, "description": u"抱歉,您暂时无法配置此项活动,详情请咨询平台方"})
  5709. # 检查活动的设备类型是否匹配
  5710. onsaleType = onsale.onsaleType
  5711. expression = OnSale.onsaleTypeDict[onsaleType]['expression']
  5712. onsale.onClickUrl = OnSale.onsaleTypeDict[onsaleType]['onClickUrl']
  5713. onsale.showType = OnSale.onsaleTypeDict[onsaleType]['showType']
  5714. if expression:
  5715. for lc in onsale.logicalCodeList:
  5716. dev = Device.get_dev_by_logicalCode(lc)
  5717. if dev is None:
  5718. continue
  5719. if not eval(expression):
  5720. return JsonResponse({'result': 0, 'description': u'编码为:%s的设备类型不符合本次活动的要求,请去掉该设备哦' % lc, 'payload': {}})
  5721. onsale.dealerId = str(request.user.bossId)
  5722. onsale.save()
  5723. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  5724. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5725. @permission_required(ROLE.dealer, ROLE.subaccount)
  5726. def deleteOnsale(request):
  5727. # type: (WSGIRequest)->JsonResponse
  5728. payload = json.loads(request.body)
  5729. onsaleId = payload.get('id')
  5730. if not onsaleId:
  5731. return JsonErrorResponse(description=u'数据不完整,请刷新')
  5732. obj = OnSale.objects.get(id=onsaleId)
  5733. obj.delete()
  5734. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  5735. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,删除失败,请您重试'))
  5736. @permission_required(ROLE.dealer, ROLE.subaccount)
  5737. def editOnsale(request):
  5738. # type: (WSGIRequest)->JsonResponse
  5739. payload = json.loads(request.body) if request.body else {}
  5740. if not payload:
  5741. return JsonErrorResponse(description=u'发送的编辑数据为空')
  5742. payload['startTime'] = to_datetime(payload['startTime'] + ' 00:00:00')
  5743. payload['endTime'] = to_datetime(payload['endTime'] + ' 23:59:59')
  5744. obj = OnSale.objects.get(id=payload['id'])
  5745. obj.update(**payload)
  5746. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  5747. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5748. @permission_required(ROLE.dealer, ROLE.subaccount)
  5749. def getOnsaleRecord(request):
  5750. # type: (WSGIRequest)->JsonResponse
  5751. pageIndex = int(request.GET.get('pageIndex', 1))
  5752. pageSize = int(request.GET.get('pageSize', 10))
  5753. startTimeStr = request.GET.get('startTime', None)
  5754. if not startTimeStr:
  5755. return JsonErrorResponse(description=u'数据为空,请重试')
  5756. startTime = to_datetime(startTimeStr + ' 00:00:00')
  5757. endTimeStr = request.GET.get('endTime', 10)
  5758. endTime = to_datetime(endTimeStr + ' 23:59:59')
  5759. onsaleId = request.GET.get('onsaleId', None)
  5760. rcds = OnSaleRecord.objects.filter(onsaleId=onsaleId, addedTime__gte=startTime, addedTime__lte=endTime)
  5761. dataList = []
  5762. countDict = {}
  5763. for rcd in rcds:
  5764. data = {'clickTime': rcd.addedTime.strftime(Const.DATETIME_FMT)}
  5765. desc = u'用户:%s,' % rcd.nickName
  5766. if rcd.onsaleDetail.has_key('coins'):
  5767. desc += u' 领取%s个金币' % rcd.onsaleDetail['coins']
  5768. if rcd.onsaleDetail.has_key('duration'):
  5769. desc += u' 启动免费体验%s分钟' % rcd.onsaleDetail['duration']
  5770. if rcd.onsaleDetail.has_key('phoneNumber'):
  5771. desc += u' 手机号码:%s' % rcd.onsaleDetail['phoneNumber']
  5772. data['description'] = desc
  5773. data.update(rcd.onsaleDetail)
  5774. for k, v in rcd.onsaleDetail.items():
  5775. countKey = '%sTotal' % k
  5776. if countDict.has_key(countKey):
  5777. countDict[countKey] += v
  5778. else:
  5779. countDict[countKey] = v
  5780. dataList.append(data)
  5781. return JsonResponse(
  5782. {
  5783. 'result': 1,
  5784. 'description': '',
  5785. 'payload':
  5786. {
  5787. 'total': len(dataList),
  5788. 'dataList': dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize],
  5789. 'countDict': countDict
  5790. }
  5791. })
  5792. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'创意文件存储失败,请重新试试'))
  5793. @permission_required(ROLE.dealer, ROLE.subaccount)
  5794. def uploadCreative(request):
  5795. # type: (WSGIRequest)->JsonResponse
  5796. files = request.FILES.getlist('file')
  5797. if not len(files):
  5798. return JsonResponse({'result': 0, 'description': u'未找到上传的创意文件,请重新试试', 'payload': {}})
  5799. uploader = AliOssFileUploader(inputFile=request.FILES.getlist('file')[0], uploadType='creative')
  5800. logger.info('[uploadItemPic] %s is being used' % (repr(uploader),))
  5801. try:
  5802. outputUrl = uploader.upload()
  5803. return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl})
  5804. except InvalidFileSize, e:
  5805. logger.info(
  5806. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  5807. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5808. except InvalidFileName, e:
  5809. logger.info(
  5810. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  5811. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5812. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'状态更新错误,请刷新页面重新试试'))
  5813. @permission_required(ROLE.dealer, ROLE.subaccount)
  5814. def toggleOnsale(request):
  5815. # type: (WSGIRequest)->JsonResponse
  5816. payload = json.loads(request.body)
  5817. status = payload.get('status')
  5818. onsaleId = payload.get('id')
  5819. onsale = OnSale.objects.get(id=onsaleId)
  5820. onsale.status = status
  5821. onsale.save()
  5822. return JsonResponse({'result': 1, 'description': '', 'payload': ''})
  5823. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取价格失败,请刷新页面重新试试'))
  5824. @permission_required(ROLE.dealer, ROLE.subaccount)
  5825. def getPricePerHour(request):
  5826. # type: (WSGIRequest)->JsonResponse
  5827. lc = request.GET.get('logicalCode')
  5828. dev = Device.objects.get(logicalCode=lc)
  5829. return JsonResponse({'result': 1, 'description': '', 'payload': dev.otherConf.get('pricePerHour', 2.0)})
  5830. @permission_required(ROLE.dealer, ROLE.subaccount)
  5831. def setBatchDevsSwitch(request):
  5832. # type: (WSGIRequest)->JsonResponse
  5833. data = json.loads(request.body) if request.body else {}
  5834. if not data:
  5835. return JsonErrorResponse(u'数据为空,请重试')
  5836. lcs = data['logicalCodes']
  5837. isFault = data['isFault']
  5838. objs = Device.objects.filter(devNo__in=lcs)
  5839. for obj in objs:
  5840. dev = Device.get_dev(obj.devNo)
  5841. obj.isFault = isFault
  5842. try:
  5843. box = ActionDeviceBuilder.create_action_device(dev)
  5844. box.set_dev_fault(isFault)
  5845. obj.save()
  5846. Device.invalid_device_cache(obj.devNo)
  5847. except Exception as e:
  5848. logger.exception(e)
  5849. continue
  5850. return JsonResponse({"result": 1, "description": "", "payload": {}})
  5851. # 批量设置退费保护时间
  5852. @permission_required(ROLE.dealer, ROLE.subaccount)
  5853. def setBatchRefundProtectionTime(request):
  5854. # type: (WSGIRequest)->JsonResponse
  5855. data = json.loads(request.body) if request.body else {}
  5856. if not data:
  5857. return JsonErrorResponse(u'数据为空,请重试')
  5858. lcs = data['logicalCodes']
  5859. refundProtectionTime = data['refundProtectionTime']
  5860. try:
  5861. Device.objects.filter(devNo__in=lcs).update(refundProtectionTime=refundProtectionTime).select_for_update()
  5862. except Exception as e:
  5863. logger.exception(e)
  5864. @permission_required(ROLE.dealer, ROLE.subaccount)
  5865. def getCardTicketTypeList(request):
  5866. # type: (WSGIRequest)->JsonResponse
  5867. objs = VirtualCard.objects.filter(ownerId=str(request.user.bossId))
  5868. dataList = []
  5869. for obj in objs:
  5870. # if '*' in obj.groupIDs:
  5871. # groupIds = Group.get_group_ids_of_dealer(str(request.user.id))
  5872. # else:
  5873. # groupIds = obj.groupIds
  5874. data = {
  5875. 'cardName': obj.cardName,
  5876. 'price': obj.price,
  5877. 'groupIds': obj.groupIds,
  5878. 'periodDays': obj.periodDays,
  5879. 'expiredTime': obj.expiredTime.strftime('%Y-%m-%d'),
  5880. 'dayQuota': obj.dayQuota,
  5881. 'quota': obj.quota,
  5882. 'userLimit': obj.userLimit,
  5883. 'userDesc': obj.userDesc,
  5884. 'dealerDesc': obj.dealerDesc
  5885. }
  5886. dataList.append(data)
  5887. return JsonResponse({"result": 1, "description": '', "payload": {'datalist': dataList}})
  5888. @error_tolerate(nil=JsonErrorResponse(u"获取虚拟卡列表失败"))
  5889. @permission_required(ROLE.dealer, ROLE.subaccount)
  5890. def getCardTicketList(request):
  5891. """
  5892. 经销商 优惠卡卷列表
  5893. 可通过卡名称搜索
  5894. 可通过 售卡状态 卡使用地址进行筛选
  5895. :param request:
  5896. :return:
  5897. """
  5898. pageIndex = int(request.GET.get('pageIndex', 1))
  5899. pageSize = int(request.GET.get('pageSize', 10))
  5900. status = request.GET.get("status") # 卡状态
  5901. groupId = request.GET.get("groupId") # 地址ID
  5902. searchKey = request.GET.get("searchKey") # 卡名称
  5903. # 没有传递状态 则是全部的可用状态
  5904. statusList = [int(status)] if status else [0, 1]
  5905. filters = {"ownerId": str(request.user.bossId), "status__in": statusList}
  5906. # 传递了地址的情况 则全选地址的 和单独选择的都要算上
  5907. if groupId:
  5908. filters.update({"groupIds__in": ["*", groupId]})
  5909. objs = VirtualCard.objects.filter(**filters)
  5910. if searchKey:
  5911. objs = objs.search(searchKey, ["cardName"])
  5912. total = objs.count()
  5913. dataList = []
  5914. for obj in objs.skip((pageIndex - 1) * pageSize).limit(pageSize):
  5915. dataList.append(obj.to_dict())
  5916. return JsonResponse({"result": 1, "description": '', "payload": {'total': total, 'pageSize': pageSize, 'dataList': dataList}})
  5917. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'添加失败,请重新试试'))
  5918. @permission_required(ROLE.dealer, ROLE.subaccount)
  5919. def addTicketCard(request):
  5920. def sort_quota(qArray): # type:(list) -> list
  5921. # 首先检查单位是否重复 对于重复的单位叠加处理
  5922. qDict = defaultdict(int)
  5923. for _item in qArray:
  5924. _count, _unit = _item["count"], _item["unit"]
  5925. qDict[_unit] += int(_count)
  5926. if len(qDict) != len(qArray):
  5927. raise ServiceException({"result": 2, "description": u"额度设置错误,额度单位重复"})
  5928. return sorted(qArray, key=lambda x: x["unit"])
  5929. if not request.body:
  5930. return JsonErrorResponse(description=u'传入数据为空')
  5931. payload = json.loads(request.body)
  5932. cardId = payload.get("cardId")
  5933. cardName = payload["cardName"]
  5934. userDesc = payload["userDesc"]
  5935. userLimit = int(payload["userLimit"])
  5936. periodDays = float(payload["periodDays"])
  5937. try:
  5938. expiredTime = to_datetime(payload['expiredTime'] + ' 23:59:59')
  5939. except Exception as e:
  5940. expiredTime = to_datetime(payload['expiredTime'])
  5941. devTypeList = payload["devTypeList"]
  5942. groups = ['*'] if payload['groups'] == '*' else [grp['groupId'] for grp in payload['groups']]
  5943. price = RMB(payload["price"])
  5944. power = int(payload["power"])
  5945. try:
  5946. dayQuota = sort_quota(payload["dayQuota"])
  5947. quota = sort_quota(payload["quota"])
  5948. except ServiceException as e:
  5949. return JsonErrorResponse(description=e.result["description"])
  5950. if cardId:
  5951. try:
  5952. card = VirtualCard.objects.get(id=cardId)
  5953. except DoesNotExist:
  5954. return JsonErrorResponse(description=u"编辑虚拟卡卷失败")
  5955. if card.ownerId != str(request.user.bossId):
  5956. return JsonErrorResponse(description=u"保存失败,请重新尝试")
  5957. else:
  5958. card = VirtualCard()
  5959. card.update(
  5960. cardName=cardName, userDesc=userDesc, userLimit=userLimit, periodDays=periodDays,
  5961. expiredTime=expiredTime, devTypeList=devTypeList, groupIds=groups, price=price,
  5962. power=power, dayQuota=dayQuota, quota=quota, ownerId=str(request.user.bossId),
  5963. upsert=True
  5964. )
  5965. return JsonOkResponse()
  5966. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除失败,请重新试试'))
  5967. @permission_required(ROLE.dealer, ROLE.subaccount)
  5968. def deleteCardTicket(request):
  5969. # type: (WSGIRequest)->JsonResponse
  5970. if not request.body: return JsonErrorResponse(description=u'传入数据为空')
  5971. payload = json.loads(request.body)
  5972. cardId = payload['id']
  5973. try:
  5974. VirtualCard.get_collection().update({'_id': ObjectId(cardId)}, {'$set': {'status':-1}})
  5975. return JsonResponse({"result": 1, "description": "", "payload": {}})
  5976. except Exception as e:
  5977. logger.exception('update error=%s' % e)
  5978. return JsonResponse({"result": 0, "description": u"删除失败,请您稍后重试", "payload": {}})
  5979. @permission_required(ROLE.dealer, ROLE.subaccount)
  5980. def switchCardTicket(request):
  5981. # type: (WSGIRequest)->JsonResponse
  5982. if not request.body: return JsonErrorResponse(description=u'传入数据为空')
  5983. payload = json.loads(request.body)
  5984. cardId = payload['id']
  5985. try:
  5986. vCard = VirtualCard.objects.get(id=cardId)
  5987. vCard.status = 1 if vCard.status == 0 else 0
  5988. vCard.save()
  5989. return JsonResponse({"result": 1, "description": "", "payload": {}})
  5990. except Exception as e:
  5991. logger.exception('switchCardTicket error=%s' % e)
  5992. return JsonResponse({"result": 0, "description": u"切换虚拟卡的状态失败,请您刷新页面后重试", "payload": {}})
  5993. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除失败,请重新试试'))
  5994. @permission_required(ROLE.dealer, ROLE.subaccount)
  5995. def delUserVirtualCard(request):
  5996. payload = json.loads(request.body)
  5997. cardId = payload.get("cardId")
  5998. if not cardId:
  5999. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6000. try:
  6001. vCard = UserVirtualCard.objects.get(id=cardId)
  6002. except DoesNotExist:
  6003. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6004. if vCard.dealerId != str(request.user.id):
  6005. return JsonErrorResponse(u"不是您的虚拟卡,无权删除")
  6006. record = AdjustUserVirtualCardRecord(
  6007. cardId=cardId,
  6008. cardNo=vCard.cardNo,
  6009. beforeAdjust=vCard.expiredTime,
  6010. operator=str(request.user.id),
  6011. dealerId=str(request.user.bossId),
  6012. adjustType=TYPE_ADJUST_USER_VIRTUAL_CARD.DELETE,
  6013. oldQuota=vCard.quota,
  6014. adjustQuota=[{"count": 0, "unit": vCard.quota[0].get("unit")}]
  6015. )
  6016. vCard.delete()
  6017. record.save()
  6018. return JsonOkResponse(description=u"删除成功")
  6019. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'调整失败,请重新试试'))
  6020. @permission_required(ROLE.dealer, ROLE.subaccount)
  6021. def adjustUserVirtualCardTime(request):
  6022. payload = json.loads(request.body)
  6023. cardId = payload.get("cardId", "")
  6024. days = int(payload.get("days", 0))
  6025. if not days:
  6026. return JsonErrorResponse(description=u"您调整的时间没有变化")
  6027. if not cardId:
  6028. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6029. try:
  6030. vCard = UserVirtualCard.objects.get(id=cardId)
  6031. except DoesNotExist:
  6032. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6033. if vCard.dealerId != str(request.user.id):
  6034. return JsonErrorResponse(u"不是您的虚拟卡,无权修改")
  6035. record = AdjustUserVirtualCardRecord(
  6036. cardId=cardId,
  6037. cardNo=vCard.cardNo,
  6038. beforeAdjust=vCard.expiredTime,
  6039. operator=str(request.user.id),
  6040. dealerId=str(request.user.bossId),
  6041. adjustType=TYPE_ADJUST_USER_VIRTUAL_CARD.ADJUST_DAYS,
  6042. adjustDays=days,
  6043. oldQuota=vCard.quota,
  6044. adjustQuota=[{"count": 0, "unit": vCard.quota[0].get("unit")}]
  6045. )
  6046. vCard.expiredTime = vCard.expiredTime + datetime.timedelta(days=days)
  6047. vCard.save()
  6048. record.save()
  6049. return JsonOkResponse(description=u"操作成功,虚拟卡{}过期调整过期时间{}天".format(str(vCard.id), days))
  6050. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'调整失败,请重新试试'))
  6051. @permission_required(ROLE.dealer, ROLE.subaccount)
  6052. def adjustUserVirtualCardQuota(request):
  6053. """
  6054. 调整虚拟卡额度
  6055. :param request:
  6056. :return:
  6057. """
  6058. payload = json.loads(request.body)
  6059. cardId = payload.get("cardId", "")
  6060. quota = payload.get("quota")
  6061. dayQuota = payload.get("dayQuota")
  6062. if not cardId:
  6063. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6064. if not all([quota, dayQuota]):
  6065. return JsonErrorResponse(description="参数不全")
  6066. try:
  6067. vCard = UserVirtualCard.objects.get(id=cardId)
  6068. except DoesNotExist:
  6069. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6070. vCard.quota = quota
  6071. vCard.dayQuota = dayQuota
  6072. for _item in vCard.quota:
  6073. _item["count"] = float(_item["count"])
  6074. for _item in vCard.dayQuota:
  6075. _item["count"] = float(_item["count"])
  6076. vCard.save()
  6077. return JsonOkResponse(description=u"操作成功,虚拟卡{}调整额度成功")
  6078. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"调整失败,请重新试试"))
  6079. @permission_required(ROLE.dealer, ROLE.subaccount)
  6080. def adjustUserVirtualState(request):
  6081. """
  6082. 修改虚拟卡 的状态 主要是冻结/非冻结 霍珀需求
  6083. 这个操作状态就不放入调整记录了
  6084. :param request:
  6085. :return:
  6086. """
  6087. payload = json.loads(request.body)
  6088. cardId = payload.get("id", "")
  6089. if not cardId:
  6090. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6091. try:
  6092. vCard = UserVirtualCard.objects.get(id=cardId)
  6093. except DoesNotExist:
  6094. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6095. if vCard.status in ["normal", "warning"]:
  6096. vCard.status = "frozen"
  6097. else:
  6098. vCard.status = "normal"
  6099. vCard.save()
  6100. return JsonOkResponse(description=u"操作成功")
  6101. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'读取失败,请重新试试'))
  6102. @permission_required(ROLE.dealer, ROLE.subaccount)
  6103. def userVirtualCardAdjustRecord(request):
  6104. pageIndex = int(request.GET.get("pageIndex", 1))
  6105. pageSize = int(request.GET.get("pageSize", 10))
  6106. searchKey = request.GET.get("searchKey")
  6107. _type = request.GET.get("type")
  6108. startTime = request.GET.get("startTime")
  6109. endTime = request.GET.get("endTime")
  6110. matchFilters = {"dealerId": str(request.user.bossId)}
  6111. if _type:
  6112. if _type not in Const.TYPE_ADJUST_USER_VIRTUAL_CARD.choices():
  6113. return JsonErrorResponse(description=u"筛选种类错误,无此相关记录")
  6114. else:
  6115. matchFilters.update({"adjustType": _type})
  6116. if startTime:
  6117. startDataTime = to_datetime(startTime + ' 00:00:00', "%Y-%m-%d %H:%M:%S")
  6118. now = datetime.datetime.now()
  6119. if not endTime:
  6120. endDateTime = now + datetime.timedelta(days=1)
  6121. else:
  6122. endDateTime = to_datetime(endTime, "%Y-%m-%d")
  6123. if endDateTime > now:
  6124. endDateTime = now
  6125. endDateTime = endDateTime + datetime.timedelta(days=1)
  6126. if startDataTime >= endDateTime:
  6127. endDateTime = startDataTime + datetime.timedelta(days=1)
  6128. matchFilters.update(
  6129. {
  6130. "dateTimeAdded": {
  6131. "$gte": startDataTime,
  6132. "$lte": endDateTime
  6133. }
  6134. }
  6135. )
  6136. if searchKey:
  6137. matchFilters.update({
  6138. "cardNo": searchKey
  6139. })
  6140. records = AdjustUserVirtualCardRecord.get_collection().find(
  6141. matchFilters
  6142. ).sort(
  6143. [("dateTimeAdded", -1)]
  6144. ).skip(
  6145. pageSize * (pageIndex - 1)
  6146. ).limit(
  6147. pageSize
  6148. )
  6149. data = []
  6150. for record in records:
  6151. oldQuota = record.get("oldQuota")[0]
  6152. adjustQuota = record.get("adjustQuota")[0]
  6153. newQuota = {
  6154. "count" :oldQuota.get("count") + adjustQuota.get("count"),
  6155. "unit": oldQuota.get("unit")
  6156. }
  6157. dealerId = record.get("operator")
  6158. dealer = Dealer.get_dealer(dealerId)
  6159. operator = dealer.get("nickname") or dealer.get("username")
  6160. data.append(
  6161. {
  6162. "cardId": record.get("cardId"),
  6163. "cardNo": record.get("cardNo"),
  6164. "beforeAdjustExpired": record.get("beforeAdjust").strftime("%Y-%m-%d %H:%M:%S"),
  6165. "afterAdjustExpired": (record.get("beforeAdjust") + datetime.timedelta(days=record.get("adjustDays"))).strftime("%Y-%m-%d %H:%M:%S"),
  6166. "beforeAdjustQuota": "{} {}".format(oldQuota.get("count"), oldQuota.get("unit")),
  6167. "afterAdjustQuota": "{} {}".format(newQuota.get("count"), oldQuota.get("unit")),
  6168. "operator": operator,
  6169. "adjustType": record.get("adjustType"),
  6170. "adjustDate": record.get("dateTimeAdded")
  6171. }
  6172. )
  6173. return JsonOkResponse(payload={"total": 10000, "dataList": data})
  6174. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'读取失败,请重新试试'))
  6175. @permission_required(ROLE.dealer, ROLE.subaccount)
  6176. def getUserCardTicketList(request):
  6177. """
  6178. 经销商获取 已经发售的虚拟卡
  6179. 可以通过卡号搜索
  6180. 可以通过根据发卡地址来筛选 groupId
  6181. 可以通过卡类型筛选 dealerCardTypeId
  6182. 可以通过卡的状态来筛选 status 0(没过期 ) 1(过期)
  6183. :param request:
  6184. :return:
  6185. """
  6186. pageIndex = int(request.GET.get('pageIndex', 1))
  6187. pageSize = int(request.GET.get('pageSize', 10))
  6188. searchKey = request.GET.get('searchKey', '')
  6189. dealerCardTypeId = request.GET.get("dealerCardTypeId")
  6190. status = request.GET.get("status")
  6191. groupId = request.GET.get("groupId")
  6192. userId = str(request.GET.get('userId', ''))
  6193. isEmptyCard = int(request.GET.get('isEmptyCard', 0))
  6194. if isEmptyCard:
  6195. objs = VirtualCardBuilder.find_dealer_virtual_card(str(request.user.id)).order_by('-id')
  6196. else:
  6197. filters = {
  6198. "dealerId": str(request.user.bossId)
  6199. }
  6200. # 添加筛选条件
  6201. if userId:
  6202. filters.update({"openIds__contains": userId})
  6203. if groupId:
  6204. filters.update({"groupIds__in": ["*", groupId]})
  6205. if dealerCardTypeId:
  6206. filters.update({"cardTypeId": dealerCardTypeId})
  6207. if status:
  6208. nowTime = datetime.datetime.now()
  6209. status = int(status)
  6210. filters.update({"expiredTime__gt": nowTime}) if status else filters.update({"expiredTime__lt": nowTime})
  6211. objs = UserVirtualCard.objects.filter(**filters).order_by('-startTime')
  6212. if searchKey:
  6213. objs = objs.search(searchKey)
  6214. total = objs.count()
  6215. dataList = []
  6216. for obj in objs.skip((pageIndex - 1) * pageSize).limit(pageSize):
  6217. data = obj.to_dict()
  6218. data.update(obj.quotaInfo)
  6219. dataList.append(data)
  6220. return JsonResponse({"result": 1, "description": '', "payload": {'total': total, 'dataList': dataList}})
  6221. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"读取失败,请重新试试"))
  6222. @permission_required(ROLE.dealer, ROLE.subaccount)
  6223. def getUserCardTicketDetail(request):
  6224. """
  6225. 获取用户的
  6226. :param request:
  6227. :return:
  6228. """
  6229. cardId = request.GET.get("cardId", "")
  6230. try:
  6231. vCard = UserVirtualCard.objects.get(id=cardId)
  6232. except DoesNotExist:
  6233. return JsonErrorResponse(description=u"查询错误,请刷新页面重试")
  6234. data = vCard.to_detail()
  6235. data.update({"frozenState": not vCard.status in ["normal", "warning"]})
  6236. return JsonOkResponse(payload=data)
  6237. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"备注失败,请重新试试"))
  6238. @permission_required(ROLE.dealer, ROLE.subaccount)
  6239. def remarkUserVirtual(request):
  6240. """
  6241. 霍珀需求 经销商为已发卡卷添加备注
  6242. :param request:
  6243. :return:
  6244. """
  6245. payload = json.loads(request.body)
  6246. cardId = payload.get("cardId")
  6247. remark = payload.get("remark")
  6248. dealerId = str(request.user.bossId)
  6249. try:
  6250. vCard = UserVirtualCard.objects.get(id=cardId)
  6251. except DoesNotExist:
  6252. return JsonErrorResponse(description=u"虚拟卡备注失败,请刷新页面试试")
  6253. if vCard.dealerId != dealerId:
  6254. return JsonErrorResponse(description=u"不是您的虚拟卡您无权修改")
  6255. vCard.update(remark=remark)
  6256. return JsonOkResponse()
  6257. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'读取失败,请重新试试'))
  6258. @permission_required(ROLE.dealer, ROLE.subaccount)
  6259. def getElcPriceModList(request):
  6260. dealerId = str(request.user.bossId)
  6261. objs = ElecPriceTemplate.objects.filter(ownerId=dealerId)
  6262. resultList = [{'id': str(obj.id), 'name': obj.name, 'price': obj.priceList} for obj in objs]
  6263. return JsonResponse({"result": 1, "description": '', "payload": resultList})
  6264. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存失败,请重新试试'))
  6265. @permission_required(ROLE.dealer, ROLE.subaccount)
  6266. def saveElcPriceMod(request):
  6267. dealerId = str(request.user.bossId)
  6268. payload = json.loads(request.body)
  6269. priceList = payload['price']
  6270. logicalCode = payload['logicalCode']
  6271. newName = payload.get('name', None)
  6272. dev = Device.get_dev_by_logicalCode(logicalCode)
  6273. group = Group.get_group(dev['groupId'])
  6274. if newName is None:
  6275. newName = group['groupName'] + datetime.datetime.now().strftime('%Y%m%d%H%M%S')
  6276. newObj = ElecPriceTemplate(ownerId=dealerId,
  6277. name=newName,
  6278. priceList=priceList)
  6279. newObj.save()
  6280. return JsonResponse({"result": 1, "description": '', "payload": None})
  6281. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存失败,请重新试试'))
  6282. @permission_required(ROLE.dealer, ROLE.subaccount)
  6283. def saveDeviceElcPrice(request):
  6284. """
  6285. 这个是 用心汽车桩专用的 保存汽车的电价设置
  6286. """
  6287. payload = json.loads(request.body)
  6288. priceList = payload['price']
  6289. logicalCode = payload['logicalCode']
  6290. from apps.web.core.device_define.yongxin import DefaultParams
  6291. if len(priceList) != DefaultParams.DEFAULT_ELEC_PRICE_INTERVAL_NUM:
  6292. return JsonErrorResponse(description=u"电价参数设置错误,请重新试试")
  6293. if filter(lambda x: int(x * 100) > DefaultParams.DEFAULT_MAX_ELEC_PRICE, priceList):
  6294. return JsonErrorResponse(description=u"电价最大为2.55元")
  6295. device = Device.objects.get(logicalCode=logicalCode)
  6296. device.otherConf['priceList'] = priceList
  6297. device.save()
  6298. Device.invalid_device_cache(device.devNo)
  6299. return JsonOkResponse()
  6300. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除电价失败,请重新试试'))
  6301. @permission_required(ROLE.dealer, ROLE.subaccount)
  6302. def deleteElcPriceMod(request):
  6303. payload = json.loads(request.body)
  6304. ids = [ObjectId(_) for _ in payload['id']]
  6305. ElecPriceTemplate.get_collection().remove({'_id': {'$in': ids}})
  6306. return JsonResponse({"result": 1, "description": '', "payload": None})
  6307. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'上传的商品图片存储失败,请重新试试'))
  6308. @permission_required(ROLE.dealer, ROLE.subaccount)
  6309. def uploadItemPic(request):
  6310. # type: (WSGIRequest)->JsonResponse
  6311. files = request.FILES.getlist('file')
  6312. if not len(files):
  6313. return JsonResponse({'result': 0, 'description': u'未找到上传的商品图片,请重新试试', 'payload': {}})
  6314. uploader = AliOssFileUploader(inputFile=request.FILES.getlist('file')[0], uploadType='item')
  6315. logger.info('[uploadItemPic] %s is being used' % (repr(uploader),))
  6316. try:
  6317. outputUrl = uploader.upload()
  6318. return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl})
  6319. except InvalidFileSize, e:
  6320. logger.info(
  6321. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  6322. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  6323. except InvalidFileName, e:
  6324. logger.info(
  6325. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  6326. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  6327. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'编辑商品类型失败,请重新试试'))
  6328. @permission_required(ROLE.dealer, ROLE.subaccount)
  6329. def addEditItemType(request):
  6330. payload = json.loads(request.body)
  6331. ownerId = str(request.user.bossId)
  6332. itemId = payload.get('id', None)
  6333. title = payload.get('name', None)
  6334. desc = payload.get('description', None)
  6335. picUrl = payload.get('img', "")
  6336. price = 100 * payload.get('price')
  6337. try:
  6338. if itemId is not None:
  6339. obj = ItemType.objects.get(id=itemId)
  6340. obj.title, obj.desc, obj.picUrl, obj.price = title, desc, picUrl, price
  6341. obj.save()
  6342. else:
  6343. newObj = ItemType(ownerId=ownerId, title=title, desc=desc, picUrl=picUrl, price=price)
  6344. newObj.save()
  6345. itemId = str(newObj.id)
  6346. except DoesNotExist:
  6347. newObj = ItemType(ownerId=ownerId, title=title, desc=desc, picUrl=picUrl, price=price)
  6348. newObj.save()
  6349. itemId = str(newObj.id)
  6350. except Exception as e:
  6351. logger.exception(e)
  6352. return JsonErrorResponse(description=u'未知错误')
  6353. return JsonResponse({"result": 1, "description": '', "payload": {"id": itemId}})
  6354. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除商品类型失败,请重新试试'))
  6355. @permission_required(ROLE.dealer, ROLE.subaccount)
  6356. def deleteItemType(request):
  6357. payload = json.loads(request.body)
  6358. ids = payload.get('ids', [])
  6359. itemIds = [ObjectId(obj) for obj in ids]
  6360. try:
  6361. ItemType.get_collection().remove({'_id': {'$in': itemIds}})
  6362. except Exception as e:
  6363. logger.exception(e)
  6364. return JsonErrorResponse(description=u'未知错误')
  6365. return JsonResponse({"result": 1, "description": '', "payload": None})
  6366. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取商品类型失败,请重新试试'))
  6367. @permission_required(ROLE.dealer, ROLE.subaccount)
  6368. def getItemTypes(request):
  6369. ownerId = str(request.user.bossId)
  6370. itemTypeId = request.GET.get('itemTypeId', '')
  6371. if itemTypeId:
  6372. objs = ItemType.objects.filter(ownerId=ownerId, id=itemTypeId)
  6373. else:
  6374. objs = ItemType.objects.filter(ownerId=ownerId)
  6375. dataList = [{'id': str(obj.id),
  6376. 'name': obj.title,
  6377. 'description': obj.desc,
  6378. 'img': obj.picUrl,
  6379. 'price': float(obj.price) / 100.0} for obj in objs
  6380. ]
  6381. return JsonResponse({"result": 1, "description": '', "payload": {'dataList': dataList}})
  6382. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'编辑格子失败'))
  6383. @permission_required(ROLE.dealer, ROLE.subaccount)
  6384. def addEditCell(request):
  6385. payload = json.loads(request.body)
  6386. logicalCode = payload.get('logicalCode')
  6387. cellId = payload.get('id', None)
  6388. cellNo = payload.get('cellNo')
  6389. boardNo = int(payload.get('boardNo'))
  6390. lockNo = int(payload.get('lockNo'))
  6391. itemTitle = payload.get('itemTitle', '')
  6392. itemDesc = payload.get('itemDesc', '')
  6393. itemPicUrl = payload.get('itemPicUrl', '')
  6394. itemPrice = payload.get('itemPrice') * 100
  6395. try:
  6396. if cellId is not None:
  6397. obj = Cell.objects.get(id=cellId)
  6398. obj.cellNo, obj.boardNo, obj.lockNo, obj.itemTitle, obj.itemDesc, obj.itemPicUrl, obj.itemPrice = cellNo, boardNo, lockNo, itemTitle, itemDesc, itemPicUrl, itemPrice
  6399. obj.save()
  6400. else:
  6401. newObj = Cell(logicalCode=logicalCode, cellNo=cellNo, boardNo=boardNo, lockNo=lockNo, itemTitle=itemTitle,
  6402. itemDesc=itemDesc, itemPicUrl=itemPicUrl, itemPrice=itemPrice)
  6403. newObj.save()
  6404. cellId = str(newObj.id)
  6405. except DoesNotExist, e:
  6406. newObj = Cell(logicalCode=logicalCode, cellNo=cellNo, boardNo=boardNo, lockNo=lockNo, itemTitle=itemTitle,
  6407. itemDesc=itemDesc, itemPicUrl=itemPicUrl, itemPrice=itemPrice)
  6408. newObj.save()
  6409. cellId = str(newObj.id)
  6410. except Exception, e:
  6411. return JsonErrorResponse(description=u'未知错误')
  6412. # 重新挂上washConfig套餐信息
  6413. cells = Cell.objects.filter(logicalCode=logicalCode)
  6414. washConfig = {}
  6415. for cell in cells:
  6416. washConfig[str(cell.id)] = {
  6417. 'name': cell.cellNo,
  6418. 'coins': float(cell.itemPrice / 100.0),
  6419. 'price': float(cell.itemPrice / 100.0),
  6420. 'time': 1,
  6421. 'description': cell.itemTitle,
  6422. 'imgList': [cell.itemPicUrl],
  6423. 'unit': u'次'
  6424. }
  6425. dev = Device.get_dev_by_logicalCode(logicalCode)
  6426. dev['washConfig'] = washConfig
  6427. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'washConfig': dev['washConfig']}})
  6428. Device.invalid_device_cache(dev['devNo'])
  6429. return JsonResponse({"result": 1, "description": '', "payload": {"id": cellId}})
  6430. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6431. @permission_required(ROLE.dealer, ROLE.subaccount)
  6432. def deleteCell(request):
  6433. payload = json.loads(request.body)
  6434. logicalCode = payload.get('logicalCode')
  6435. cellIds = payload.get('ids')
  6436. Cell.objects(id__in=cellIds).delete()
  6437. # 重新挂上washConfig套餐信息
  6438. cells = Cell.objects.filter(logicalCode=logicalCode)
  6439. washConfig = {}
  6440. for cell in cells:
  6441. washConfig[str(cell.id)] = {
  6442. 'name': cell.cellNo,
  6443. 'coins': float(cell.itemPrice / 100.0),
  6444. 'price': float(cell.itemPrice / 100.0),
  6445. 'time': 1,
  6446. 'description': cell.itemTitle,
  6447. 'imgList': [],
  6448. 'unit': u'次'
  6449. }
  6450. dev = Device.get_dev_by_logicalCode(logicalCode)
  6451. dev['washConfig'] = washConfig
  6452. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'washConfig': dev['washConfig']}})
  6453. Device.invalid_device_cache(dev['devNo'])
  6454. return JsonResponse({"result": 1, "description": '', "payload": None})
  6455. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'查询格子失败'))
  6456. @permission_required(ROLE.dealer, ROLE.subaccount)
  6457. def getDeviceCells(request):
  6458. logicalCode = request.GET.get('logicalCode')
  6459. pageIndex = int(request.GET.get('pageIndex', 1))
  6460. pageSize = int(request.GET.get('pageSize', 30))
  6461. objs = Cell.objects.filter(logicalCode=logicalCode)
  6462. dev = Device.get_dev_by_logicalCode(logicalCode)
  6463. box = ActionDeviceBuilder.create_action_device(dev)
  6464. lockStatusDict = box.get_all_lock_status()
  6465. dataList = []
  6466. quantity, consumptionQuantity = 0, 0
  6467. for obj in objs:
  6468. dataList.append(
  6469. {
  6470. 'id': str(obj.id), 'cellNo': obj.cellNo, 'boardNo': obj.boardNo,
  6471. 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle,
  6472. 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl,
  6473. 'itemPrice': round(obj.itemPrice / 100.0, 2),
  6474. 'lockStatus': lockStatusDict.get(obj.cellNo, 'close'),
  6475. 'quantity': 1 if obj.itemStatus == 'full' else 0
  6476. }
  6477. )
  6478. if obj.itemStatus == 'full':
  6479. quantity += 1
  6480. else:
  6481. consumptionQuantity += 1
  6482. dev['quantity'] = quantity
  6483. dev['consumptionQuantity'] = consumptionQuantity
  6484. Device.update_field(
  6485. dev_no=dev['devNo'],
  6486. update=True,
  6487. quantity=quantity,
  6488. consumptionQuantity=consumptionQuantity)
  6489. return JsonResponse({'result': 1, 'description': '',
  6490. 'payload': {'dataList': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]}})
  6491. def openManyCells(dev, strIds):
  6492. ids = [ObjectId(id) for id in strIds]
  6493. cellDict = {}
  6494. cells = Cell.objects.filter(id__in=ids)
  6495. for cell in cells:
  6496. if cellDict.has_key(str(cell.boardNo)):
  6497. cellDict[str(cell.boardNo)].append(cell.lockNo)
  6498. else:
  6499. cellDict[str(cell.boardNo)] = [cell.lockNo]
  6500. box = ActionDeviceBuilder.create_action_device(dev)
  6501. for boardNo, lockNos in cellDict.items():
  6502. try:
  6503. box.open_many_locks(boardNo, lockNos)
  6504. except Exception as e:
  6505. logger.exception(e)
  6506. return JsonResponse({"result": 0, "description": u'打开格子失败', "payload": None})
  6507. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6508. @permission_required(ROLE.dealer, ROLE.subaccount)
  6509. def addGoodsToDeviceCell(request):
  6510. payload = json.loads(request.body)
  6511. logicalCode = payload['logicalCode']
  6512. dev = Device.get_dev_by_logicalCode(logicalCode)
  6513. openManyCells(dev, payload['ids'])
  6514. ids = [ObjectId(strId) for strId in payload['ids']]
  6515. cells = Cell.objects.filter(id__in=ids)
  6516. for cell in cells:
  6517. cell.itemStatus = 'full'
  6518. try:
  6519. cell.save()
  6520. # 增加一条补货记录
  6521. newStock = StockRecord(
  6522. logicCode=dev['logicalCode'],
  6523. imei=dev['devNo'],
  6524. stockType='add',
  6525. stockTime=datetime.datetime.now().strftime(Const.DATETIME_FMT),
  6526. number=1,
  6527. more="%s:%s" % (cell.cellNo, cell.itemTitle)
  6528. )
  6529. newStock.save()
  6530. except Exception, e:
  6531. continue
  6532. Cell.update_dev_quantity_from_cell(dev)
  6533. return JsonResponse({"result": 1, "description": '', "payload": None})
  6534. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6535. @permission_required(ROLE.dealer, ROLE.subaccount)
  6536. def unlockCell(request):
  6537. payload = json.loads(request.body)
  6538. logicalCode = payload.get('logicalCode')
  6539. ids = payload.get('id')
  6540. dev = Device.get_dev_by_logicalCode(logicalCode)
  6541. openManyCells(dev, ids)
  6542. return JsonResponse({"result": 1, "description": '', "payload": None})
  6543. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6544. @permission_required(ROLE.dealer, ROLE.subaccount)
  6545. def getDeviceCellsFromDB(request):
  6546. logicalCode = request.GET.get('logicalCode')
  6547. pageIndex = int(request.GET.get('pageIndex', 1))
  6548. pageSize = int(request.GET.get('pageSize', 30))
  6549. objs = Cell.objects.filter(logicalCode=logicalCode)
  6550. dataList = []
  6551. quantity, consumptionQuantity = 0, 0
  6552. for obj in objs:
  6553. dataList.append(
  6554. {'id': str(obj.id), 'cellNo': obj.cellNo, 'boardNo': obj.boardNo,
  6555. 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle,
  6556. 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl,
  6557. 'itemPrice': round(obj.itemPrice / 100.0, 2),
  6558. # 'lockStatus':lockStatusDict.get(obj.cellNo,'close'),
  6559. 'quantity': 1 if obj.itemStatus == 'full' else 0}
  6560. )
  6561. if obj.itemStatus == 'full':
  6562. quantity += 1
  6563. else:
  6564. consumptionQuantity += 1
  6565. # TODO 为啥这两个参数只打内存,不更新到数据库
  6566. Device.get_and_update_device_cache(
  6567. dev_no=Device.get_dev_by_logicalCode(logicalCode)['devNo'],
  6568. quantity=quantity,
  6569. consumptionQuantity=consumptionQuantity)
  6570. return JsonResponse({'result': 1, 'description': '',
  6571. 'payload': {'dataList': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]}})
  6572. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取列表失败'))
  6573. @permission_required(ROLE.dealer, ROLE.subaccount)
  6574. def getOfflineTaskList(request):
  6575. # type: (WSGIRequest)->JsonResponse
  6576. current_user = request.user # type: Dealer
  6577. page_index = int(request.GET.get('pageIndex', 1))
  6578. page_size = int(request.GET.get('pageSize', 10))
  6579. search_key = request.GET.get('searchKey', None)
  6580. tasks = OfflineTask.objects(ownerId=current_user.id,
  6581. role=current_user.role).search(search_key).order_by('-dateTimeAdded')
  6582. total = tasks.count()
  6583. return JsonOkResponse(
  6584. payload={
  6585. 'dataList': [t.to_dict() for t in tasks.paginate(pageSize=page_size, pageIndex=page_index)],
  6586. 'total': total
  6587. })
  6588. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6589. @permission_required(ROLE.dealer, ROLE.subaccount)
  6590. def exportBusinessStats(request):
  6591. """
  6592. 经销商的手机 导出报表
  6593. :param request:
  6594. :return:
  6595. """
  6596. dealer = request.user # type: Dealer
  6597. request_get = request.GET.copy()
  6598. if 'kind' not in request_get:
  6599. request_get['kind'] = 'income'
  6600. if 'time' in request_get and (('startTime' not in request_get) or ('endTime' not in request_get)):
  6601. # 将月份转换成开始时间为1号,结束时间为当月最后一天,因为需要一个前闭后闭区间,所以最后一天日期减一天
  6602. request_get['startTime'] = datetime.datetime.strptime(request_get.pop('time')[0], "%Y-%m")
  6603. request_get['endTime'] = request_get['startTime'] + relativedelta(months=1) - datetime.timedelta(days=1)
  6604. request_get['startTime'] = request_get['startTime'].strftime(Const.DATE_FMT)
  6605. request_get['endTime'] = request_get['endTime'].strftime(Const.DATE_FMT)
  6606. query = prepare_query(request_get) # type: Query
  6607. def get_offline_task_name(task_type, user, **kwargs):
  6608. # type: (basestring, Dealer, Dict)->basestring
  6609. type_desc_map = {
  6610. 'income': u'收益',
  6611. 'consume': u'消费',
  6612. 'monthly_bill': u'月度'
  6613. }
  6614. tmp_list = [task_type, type_desc_map.get(kwargs['kind']), user.username]
  6615. if 'logicalCode' in kwargs:
  6616. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  6617. if 'groupId' in kwargs:
  6618. address = Group.get_group(kwargs['groupId']).get('address', '')
  6619. tmp_list.append(u'地址_%s' % (address,))
  6620. if 'source' in kwargs:
  6621. kind = kwargs.get('kind')
  6622. if kind == 'income':
  6623. source_translation = DEALER_INCOME_SOURCE_TRANSLATION.get(kwargs['source'])
  6624. elif kind == 'consume':
  6625. source_translation = DEALER_CONSUMPTION_AGG_KIND_TRANSLATION.get(kwargs['source'])
  6626. else:
  6627. source_translation = None
  6628. if source_translation:
  6629. tmp_list.append(source_translation)
  6630. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  6631. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  6632. return '-'.join(tmp_list).replace("/", "_")
  6633. # 此处生成的是 报表文件的名称
  6634. offline_task_name = get_offline_task_name(
  6635. task_type=OfflineTaskType.BUSINESS_REPORT,
  6636. user=dealer,
  6637. **query.raw)
  6638. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  6639. process_func_name='generate_business_stats_report_by_dealer',
  6640. task_type=OfflineTaskType.BUSINESS_REPORT,
  6641. userid=str(dealer.id),
  6642. role=ROLE.dealer)
  6643. queryAttrs = query.attrs
  6644. queryAttrs['dateTimeAdded__lte'] = dt_to_timestamp(queryAttrs['dateTimeAdded__lte'])
  6645. queryAttrs['dateTimeAdded__gte'] = dt_to_timestamp(queryAttrs['dateTimeAdded__gte'])
  6646. queryAttrs['dealerId'] = str(dealer.id)
  6647. task_caller(func_name=offline_task.process_func_name,
  6648. offline_task_id=str(offline_task.id),
  6649. filePath=file_path,
  6650. queryAttrs=queryAttrs)
  6651. return JsonOkResponse(payload=str(offline_task.id))
  6652. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6653. @permission_required(ROLE.dealer, ROLE.subaccount)
  6654. def exportAllTicketList(request):
  6655. """
  6656. 经销商的下的所以虚拟卡
  6657. :param request:
  6658. :return:
  6659. """
  6660. dealer = request.user # type: Dealer
  6661. timeStr = arrow.now().format('YYYY-MM-DD_HH:mm:ss')
  6662. offline_task_name = '已发虚拟卡_{}_{}_{}'.format(dealer.username, timeStr, random.randint(100000, 999999))
  6663. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  6664. process_func_name='export_vcard_info_excel_from_db',
  6665. task_type=OfflineTaskType.BUSINESS_REPORT,
  6666. userid=str(dealer.id),
  6667. role=ROLE.dealer)
  6668. queryDict = {}
  6669. queryDict['dealerId'] = str(dealer.id)
  6670. task_caller(func_name=offline_task.process_func_name,
  6671. offline_task_id=str(offline_task.id),
  6672. filepath=file_path,
  6673. queryDict=queryDict)
  6674. return JsonOkResponse(payload=str(offline_task.id))
  6675. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取收益列表失败"))
  6676. @permission_required(ROLE.dealer)
  6677. def getGroupUserAccountInfo(request):
  6678. """
  6679. 经销商下所有地址的用户充值,消费,余额情况
  6680. """
  6681. dealer = request.user # type: Dealer
  6682. def get_offline_task_name(task_type, user, **kwargs):
  6683. # type: (basestring, Dealer, Dict)->basestring
  6684. tmp_list = [task_type, user.username]
  6685. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  6686. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  6687. if 'groupId' in kwargs and kwargs['groupId']:
  6688. address = Group.get_group(kwargs['groupId']).get('address', '')
  6689. tmp_list.append(u'地址_%s' % (address,))
  6690. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  6691. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  6692. return '-'.join(tmp_list).replace("/", "_")
  6693. query_dict = {
  6694. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  6695. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  6696. 'ownerId': str(dealer.id)
  6697. }
  6698. offline_task_name = get_offline_task_name(
  6699. task_type=u'地址用户充值消费情况统计报表',
  6700. user=dealer,
  6701. **query_dict)
  6702. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  6703. process_func_name='export_group_user_account_excel_form_db',
  6704. task_type=OfflineTaskType.BUSINESS_REPORT,
  6705. userid=str(dealer.id),
  6706. role=ROLE.dealer)
  6707. task_caller(func_name=offline_task.process_func_name,
  6708. offline_task_id=str(offline_task.id),
  6709. filepath=file_path,
  6710. queryDict=query_dict)
  6711. return JsonResponse({
  6712. 'result': 1,
  6713. 'description': u"请前往离线任务查看任务处理情况",
  6714. 'payload': str(offline_task.id)})
  6715. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6716. @permission_required(ROLE.dealer, ROLE.subaccount)
  6717. def getOfflineTaskStatus(request):
  6718. # type: (WSGIRequest)->JsonResponse
  6719. """
  6720. :param request:
  6721. :return:
  6722. """
  6723. task_id = request.GET.get('id')
  6724. if not task_id:
  6725. return JsonErrorResponse(description=u'查询ID为空')
  6726. task = OfflineTask.objects(id=str(task_id)).get() # type: OfflineTask
  6727. return JsonOkResponse(payload=task.status)
  6728. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6729. @permission_required(ROLE.dealer, ROLE.subaccount)
  6730. def getSubAccountList(request):
  6731. pageIndex = int(request.GET.get('pageIndex', 1))
  6732. pageSize = int(request.GET.get('pageSize', 10))
  6733. subaccounts = SubAccount.objects.filter(bossId=str(request.user.bossId))
  6734. total = subaccounts.count()
  6735. dataList = []
  6736. for obj in subaccounts.skip((pageIndex - 1) * pageSize).limit(pageSize):
  6737. if obj.bossId == str(obj.id):
  6738. continue
  6739. dataList.append({
  6740. 'username': obj.username,
  6741. 'permissionList': obj.permissionList,
  6742. 'nickname': obj.nickname,
  6743. 'id': str(obj.id)
  6744. })
  6745. return JsonOkResponse(payload={'agentId': request.user.agentId, 'dataList': dataList, 'total': total})
  6746. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6747. @permission_required(ROLE.dealer, ROLE.subaccount)
  6748. def addEditSubAccount(request):
  6749. bossId = request.user.bossId
  6750. payload = json.loads(request.body)
  6751. strId = payload.get('id', None)
  6752. if strId is None:
  6753. username = payload['username']
  6754. code = payload['code']
  6755. status, desc = dealerRegisterSMSProvider.verify(username, code)
  6756. if not status:
  6757. return JsonErrorResponse(desc)
  6758. count = SubAccount.objects.filter(username=username, bossId=str(bossId)).count()
  6759. if count > 0:
  6760. return JsonResponse({"result": 0, "description": u'该手机号已经是子账号了,不允许重复配置该手机号为子账号', "payload": None})
  6761. password = payload['password']
  6762. if (not password) or len(password) < 6:
  6763. return JsonResponse({"result": 0, "description": u'必须输入密码,密码长度不能小于6', "payload": None})
  6764. nickname = payload['nickname']
  6765. if not nickname:
  6766. return JsonResponse({"result": 0, "description": u'必须配置昵称', "payload": None})
  6767. newObj = SubAccount(
  6768. username=username,
  6769. nickname=nickname,
  6770. password=make_password(password),
  6771. permissionList=payload.get('permissionList', []),
  6772. agentId=request.user.agentId,
  6773. bossId=bossId
  6774. )
  6775. newObj.save()
  6776. return JsonOkResponse(payload={'id': str(newObj.id)})
  6777. else:
  6778. username = payload['username']
  6779. try:
  6780. obj = SubAccount.objects.get(id=strId)
  6781. except DoesNotExist:
  6782. return JsonResponse({"result": 0, "description": u'并未找到该子账号,可能已经被删除了', "payload": None})
  6783. password = payload['password']
  6784. if (not password) or len(password) < 6:
  6785. return JsonResponse({"result": 0, "description": u'必须输入密码,密码长度不能小于6', "payload": None})
  6786. nickname = payload['nickname']
  6787. if not nickname:
  6788. return JsonResponse({"result": 0, "description": u'必须配置昵称', "payload": None})
  6789. obj.username = username
  6790. obj.nickname = nickname
  6791. obj.permissionList = payload.get('permissionList', [])
  6792. obj.save()
  6793. obj.set_password(password)
  6794. return JsonOkResponse(payload={'id': str(obj.id)})
  6795. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6796. @permission_required(ROLE.dealer, ROLE.subaccount)
  6797. def deleteSubAccount(request):
  6798. payload = json.loads(request.body)
  6799. idsTemp = payload.get('ids', [])
  6800. ids = [ObjectId(_) for _ in idsTemp]
  6801. SubAccount.objects.filter(id__in=ids).delete()
  6802. return JsonResponse({"result": 1, "description": '', "payload": None})
  6803. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6804. @permission_required(ROLE.dealer, ROLE.subaccount)
  6805. def getAccountPermission(request):
  6806. # 授权经销商用户
  6807. if check_role(request.user, ROLE.dealer):
  6808. permissions = hasattr(request, 'permissions') and getattr(request, 'permissions') # type: dict
  6809. if permissions:
  6810. permissions.update({'role': 'dealerWorker'})
  6811. return JsonOkResponse(payload=permissions)
  6812. # 获取经销商或者子账号所属经销商权限
  6813. mainMenu, homepageData = request.user.myBoss.query_home_page_layout()
  6814. # 调整子账号权限
  6815. if check_role(request.user, ROLE.subaccount):
  6816. for pm in request.user.permissionList:
  6817. if pm in ['today_income', 'today_pay_income', 'today_ad_income', 'offline_coins']:
  6818. homepageData[pm] = True
  6819. else:
  6820. mainMenu[pm] = True
  6821. leftHomepage = list(set(Const.HOME_PAGE_DATA_LIST.keys()) - set(request.user.permissionList))
  6822. for pm in leftHomepage:
  6823. homepageData[pm] = False
  6824. leftMainmenu = list(set(Const.MAIN_MENU_LIST.keys()) - set(request.user.permissionList))
  6825. for pm in leftMainmenu:
  6826. mainMenu[pm] = False
  6827. return JsonOkResponse(payload={'role': request.user.role, 'homepageData': homepageData, 'mainMenu': mainMenu})
  6828. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6829. @permission_required(ROLE.dealer)
  6830. def getAccountPermissionById(request):
  6831. strId = request.GET.get('id', None)
  6832. subList = SubAccount.objects.get(id=strId).permissionList
  6833. mainMenu, homepageData = request.user.query_home_page_layout()
  6834. for menu, value in mainMenu.iteritems():
  6835. if not value:
  6836. continue
  6837. if menu in subList:
  6838. mainMenu[menu] = True
  6839. else:
  6840. mainMenu[menu] = False
  6841. mainMenu['sim_card'] = False # sim卡充值不允许给子账号操作
  6842. for menu, value in homepageData.iteritems():
  6843. if not value:
  6844. continue
  6845. if menu in subList:
  6846. homepageData[menu] = True
  6847. else:
  6848. homepageData[menu] = False
  6849. return JsonOkResponse(payload={'homepageData': homepageData, 'mainMenu': mainMenu})
  6850. @permission_required(ROLE.dealer)
  6851. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6852. def subAccountRegisterCode(request):
  6853. # type: (WSGIRequest)->JsonResponse
  6854. payload = json.loads(request.body)
  6855. phoneNumber = payload.get('username', None)
  6856. agent = Agent.get_agent(request.user.agentId)
  6857. productName = agent['productName']
  6858. if not phoneNumber:
  6859. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  6860. if len(SubAccount.objects.filter(username=phoneNumber, bossId=str(request.user.id))):
  6861. return JsonResponse({'result': 0, 'description': u'该手机号已经是您的子账号了'})
  6862. status, msg = dealerRegisterSMSProvider.get(phoneNumber=phoneNumber,
  6863. productName=productName,
  6864. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  6865. if not status:
  6866. return JsonResponse({'result': 0, 'description': msg})
  6867. else:
  6868. return JsonResponse({'result': 1, 'description': ''})
  6869. @permission_required(ROLE.dealer)
  6870. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6871. def saveAccountPermission(request):
  6872. payload = json.loads(request.body)
  6873. subId = payload.get('id')
  6874. homepageData = payload.get('homepageData', [])
  6875. mainMenu = payload.get('mainMenu', [])
  6876. obj = SubAccount.objects.get(id=subId)
  6877. perList = []
  6878. for k, v in homepageData.items():
  6879. if v:
  6880. perList.append(k)
  6881. for k, v in mainMenu.items():
  6882. if v:
  6883. perList.append(k)
  6884. obj.permissionList = perList
  6885. obj.save()
  6886. return JsonResponse({'result': 1, 'description': ''})
  6887. @permission_required(ROLE.dealer)
  6888. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6889. def getAlarmList(request):
  6890. # type: (WSGIRequest)->JsonResponse
  6891. pageIndex = int(request.GET.get('pageIndex', 1))
  6892. pageSize = int(request.GET.get('pageSize', 10))
  6893. queryset = FaultRecord.objects(dealerId=str(request.user.id), status=FAULT_RECORD_STATUS.INIT).order_by('-createdTime')
  6894. records = queryset.paginate(pageIndex=pageIndex, pageSize=pageSize) # type: Iterable[FaultRecord]
  6895. total = queryset.count()
  6896. return JsonOkResponse(payload={'dataList': [ _.to_dict() for _ in records ], 'total': total})
  6897. @permission_required(ROLE.dealer)
  6898. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6899. def handleAlarm(request):
  6900. # type: (WSGIRequest)->JsonResponse
  6901. payload = json.loads(request.body)
  6902. id_ = payload.get('id')
  6903. if id_ is None:
  6904. return JsonErrorResponse(description=u'id未传入')
  6905. status = payload.get('status')
  6906. if status is None:
  6907. return JsonErrorResponse(description=u'处理状态未传入')
  6908. dealedDetail = payload.get("dealedDetail", "")
  6909. if type(id_) == list:
  6910. id_list = id_
  6911. else:
  6912. id_list = [id_]
  6913. for item_id in id_list:
  6914. alarm = FaultRecord.objects(id=item_id).get() # type: FaultRecord
  6915. alarm.set_status(status=status, dealedDetail=dealedDetail)
  6916. if status == "handled":
  6917. task_caller(
  6918. "send_to_xf_fault_handle",
  6919. devNo=alarm.imei,
  6920. faultId=str(alarm.id)
  6921. )
  6922. handler_event_to_zhejiang(id_list[0])
  6923. dev = Device.get_dev(alarm.imei)
  6924. box = ActionDeviceBuilder.create_action_device(dev)
  6925. if box.isHaveFaultHandle:
  6926. try:
  6927. box.faultHandle(alarm=alarm)
  6928. except:
  6929. pass
  6930. return JsonOkResponse()
  6931. @permission_required(ROLE.dealer)
  6932. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6933. def checkAlarm(request):
  6934. # type: (WSGIRequest)->JsonResponse
  6935. id_ = request.GET.get('id')
  6936. if id_ is None:
  6937. return JsonErrorResponse(description=u'id未传入')
  6938. alarm = FaultRecord.objects(id=id_).get() # type: FaultRecord
  6939. dev = Device.get_dev(alarm.imei)
  6940. box = ActionDeviceBuilder.create_action_device(dev)
  6941. try:
  6942. desc = box.check_alarm(alarm)
  6943. except ServiceException , e:
  6944. return JsonResponse({"result": 0, "description": e.result.get('description'), 'payload': {}})
  6945. except Exception, e:
  6946. return JsonResponse({"result": 0, "description": u'系统异常,检查告警失败', 'payload': {}})
  6947. return JsonResponse({"result": 1, "description": desc, 'payload': {}})
  6948. @permission_required(ROLE.dealer)
  6949. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误,请稍后再试'))
  6950. def withdrawEntry(request):
  6951. # type: (WSGIRequest)->JsonResponse
  6952. user = request.user # type: Dealer
  6953. if not check_role(user, ROLE.dealer):
  6954. return ErrorResponseRedirect(error = u'权限错误')
  6955. # 检查是否有非法订单,如果有,不允许提现直接返回错误
  6956. if RechargeRecord.have_illegal_order(str(user.id), user.maxPackagePrice):
  6957. return ErrorResponseRedirect(error = u'系统检测到部分存疑订单,暂时不能提现。请联系平台客服确认')
  6958. source_key = request.GET.get('sourceId')
  6959. if not WithdrawGateway.is_ledger(source_key):
  6960. return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10003)')
  6961. source_type = request.GET.get('sourceType')
  6962. assert source_type in DEALER_INCOME_TYPE.choices(), 'invalid dealer income type'
  6963. if source_key not in user.balance_dict(source_type):
  6964. return ErrorResponseRedirect(error = u'提现参数错误,请刷新后重试')
  6965. is_ledger, agent, withdraw_gateway_list = Agent.withdraw_gateway_list(source_key)
  6966. if not is_ledger:
  6967. return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10005)')
  6968. wechat_withdraw_gateway = withdraw_gateway_list['wechat'] # type: WithdrawGateway
  6969. if wechat_withdraw_gateway.support_withdraw and not wechat_withdraw_gateway.manual_withdraw:
  6970. code = request.GET.get('code', None)
  6971. if not code:
  6972. redirect = request.GET.get('redirect')
  6973. return ExternalResponseRedirect(
  6974. WechatAuthBridge(wechat_withdraw_gateway.app).generate_auth_url_base_scope(
  6975. concat_server_end_url(
  6976. uri = '/dealer/withdraw/entry?sourceType={source_type}&sourceId={source_key}'.format(
  6977. source_type = source_type,
  6978. source_key = source_key
  6979. )), payload = base64.b64encode(redirect)))
  6980. else:
  6981. auth_bridge = WechatAuthBridge(wechat_withdraw_gateway.app)
  6982. openId = auth_bridge.authorize(code)
  6983. if openId is not None:
  6984. redirect = base64.b64decode(request.GET.get('payload'))
  6985. redirect = add_query(redirect, {
  6986. 'sourceType': source_type,
  6987. 'sourceId': source_key,
  6988. 'openId': openId
  6989. })
  6990. return FrontEndResponseRedirect(redirect)
  6991. else:
  6992. return ErrorResponseRedirect(error = u'微信授权失败,请刷新后重试')
  6993. else:
  6994. redirect = request.GET.get('redirect')
  6995. redirect = add_query(redirect, {
  6996. 'sourceType': source_type,
  6997. 'sourceId': source_key,
  6998. 'openId': ''
  6999. })
  7000. return FrontEndResponseRedirect(redirect)
  7001. @permission_required(ROLE.dealer)
  7002. def ActivateUser(request):
  7003. """
  7004. 安骑的 用户缴纳金额后 经销商激活
  7005. 需要查询对应的 推荐人,如果存在推荐人,将其金币数量增加固定数量
  7006. """
  7007. user = request.user
  7008. payload = json.loads(request.body)
  7009. _id = payload.get("id", "") # 存有用户激活信息的ID
  7010. status = payload.get("status", "")
  7011. remarks = payload.get("remarks", "")
  7012. groupIds = Group.get_group_ids_of_dealer(str(user.id)) # 获取该经销商下的所有的groupId
  7013. customer = MyUser.objects.get(id=_id)
  7014. if int(status) == 2: # 2表示用户信息激活状态为成功
  7015. MyUser.set_active_info(
  7016. {"isMember": True,
  7017. "status": status,
  7018. "remarks": remarks},
  7019. openId=customer.openId,
  7020. agentId=customer.agentId,
  7021. groupId__in=groupIds
  7022. )
  7023. # TODO zjl 这一部分任务查询时间任过长,没有索引, 是否考虑设置异步任务触发
  7024. recommender = MyUser.get_active_info(openId=customer.openId, agentId=customer.agentId, groupId__in=groupIds).get("recommender") # 推荐人
  7025. if recommender:
  7026. groupList = Group.get_groups_of_dealer(user.id)
  7027. recommender = MyUser.objects.get(phoneNumber=recommender)
  7028. if recommender.groupId not in groupList: # 添加对于当前的recommender的验证 要是同一个经销商下的
  7029. logger.info("uninvalid recommender dealer=%s, recommender=%s" % (user.nickname, recommender.nickname))
  7030. else:
  7031. coins = 10 # TODO zjl 添加推荐人金币 金币设置值
  7032. update = recommender.incr_balance(VirtualCoin(coins))
  7033. if not update:
  7034. logger.info("recommender %s get coins faild." % recommender.nickname)
  7035. else:
  7036. # 添加一条充值记录
  7037. orderNo = str(uuid.uuid1())
  7038. try:
  7039. newRcd = RechargeRecord(orderNo=orderNo,
  7040. coins=coins,
  7041. money=0.00,
  7042. openId=recommender.openId,
  7043. wxOrderNo=u'活动赠币',
  7044. nickname=recommender.nickname,
  7045. result='success',
  7046. via='sendcoin',
  7047. operator=str(user.id))
  7048. newRcd.save()
  7049. except Exception as e:
  7050. logger.exception('update record for feedback coins error=%s,orderNo=%s' % (e, orderNo))
  7051. return JsonOkResponse(u"会员录入成功,可以正常使用换电柜")
  7052. elif int(status) == 3: # 3表示用户信息激活状态为失败
  7053. MyUser.set_active_info(
  7054. {"isMember": False,
  7055. "status": status,
  7056. "remarks": remarks,
  7057. "auditTime": datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S")},
  7058. openId=customer.openId,
  7059. agentId=customer.agentId,
  7060. groupId__in=groupIds
  7061. )
  7062. return JsonOkResponse(u"已拒绝该用户")
  7063. else:
  7064. logger.error("uninvalid status : %s" % status)
  7065. return JsonErrorResponse(u"无效的审核状态")
  7066. @permission_required(ROLE.dealer)
  7067. def delUserActiveInfo(request):
  7068. user = request.user
  7069. payload = json.loads(request.body)
  7070. ids = payload.get("ids", "")
  7071. # 删除该经销商下的该用户的激活信息
  7072. customers = MyUser.objects.filter(id__in=ids)
  7073. groupIds = Group.get_group_ids_of_dealer(str(user.id))
  7074. for customer in customers:
  7075. MyUser.del_active_info(
  7076. openId=customer.openId,
  7077. agentId=customer.agentId,
  7078. groupId__in=groupIds
  7079. )
  7080. return JsonOkResponse()
  7081. @permission_required(ROLE.dealer)
  7082. def getUserIdentifyList(request):
  7083. """
  7084. 获取临时用户 待激活用户
  7085. """
  7086. pageIndex = int(request.GET.get("pageIndex", 1))
  7087. pageSize = int(request.GET.get("pageSize", 10))
  7088. searchKey = request.GET.get("searchKey")
  7089. status = request.GET.get("status")
  7090. if status in ("", "null"):
  7091. statusList = [0, 1, 2, 3]
  7092. else:
  7093. statusList = [int(status)]
  7094. groupList = Group.get_group_ids_of_dealer(request.user.id)
  7095. query = {
  7096. "groupId": {"$in": groupList},
  7097. "extra.active.status": {"$in": statusList}
  7098. }
  7099. if searchKey:
  7100. query.update(search_query(['nickname', 'phoneNumber'], searchKey).to_query(MyUser))
  7101. results = MyUser.get_collection().find(
  7102. query,
  7103. {
  7104. "nickname": 1,
  7105. "openId": 1,
  7106. "phoneNumber": 1,
  7107. "avatar": 1,
  7108. "extra.active": 1
  7109. }
  7110. ).skip(
  7111. (pageIndex - 1) * pageSize
  7112. ).limit(
  7113. pageSize
  7114. )
  7115. tempUsers = []
  7116. for user in results:
  7117. userDict = dict()
  7118. userDict["id"] = str(user["_id"])
  7119. # userDict["phoneNumber"] = user["phoneNumber"]
  7120. userDict["userNickname"] = user.get("nickname", "")
  7121. userDict["avatarUrl"] = user.get("avatar", "")
  7122. userDict.update(
  7123. user["extra"]["active"]
  7124. )
  7125. tempUsers.append(userDict)
  7126. data = {
  7127. "page": pageIndex,
  7128. # "total": 2 * pageSize if len(tempUsers) >= pageSize else pageSize,
  7129. "total": 10000,
  7130. "pageSize": pageSize,
  7131. "offset": 0,
  7132. "dataList": tempUsers
  7133. }
  7134. return JsonResponse({'result': 1, 'description': "", 'payload': data})
  7135. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'鉴权失败,请重新登录'))
  7136. @permission_required(ROLE.dealer, ROLE.subaccount)
  7137. def info(request):
  7138. user = request.user
  7139. payload = {
  7140. 'roles':['admin'],
  7141. 'introduction':user.description,
  7142. 'avatar':user.wechatAuthUserInfo.get('avatar'),
  7143. 'name':user.phone
  7144. }
  7145. return JsonResponse({'result': 1, 'description': '', 'payload':payload})
  7146. def getDashboard(request):
  7147. dealerId = str(request.user.id)
  7148. groupIds = Group.get_group_ids_of_dealer(dealerId)
  7149. devList = Device.get_devices_by_group(groupIds).values()
  7150. devCount = len(devList)
  7151. todayTime = datetime.datetime.now()
  7152. yesterdayTime = todayTime - datetime.timedelta(days=1)
  7153. today = todayTime.strftime(Const.DATE_FMT)
  7154. yesterDay = yesterdayTime.strftime(Const.DATE_FMT)
  7155. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':today}, {'daily':1, 'activedDevRatio':1})
  7156. if rcds.count() == 0:
  7157. todayIncome = 0
  7158. todayRechargeIncome = 0
  7159. todayChargeCardIncome = 0
  7160. todayOrder = 0
  7161. else:
  7162. info = rcds[0]
  7163. todayIncome = info.get('daily', {}).get('totalIncome', 0)
  7164. income = info.get('daily', {}).get('income', {})
  7165. todayRechargeIncome = income.get('recharge', 0)
  7166. todayChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('chargeVirtualCard', 0))
  7167. todayOrder = info.get('daily', {}).get('totalIncomeCount', 0)
  7168. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':yesterDay}, {'daily':1, 'activedDevRatio':1})
  7169. if rcds.count() == 0:
  7170. yesterdayIncome = 0
  7171. yesterdayOrder = 0
  7172. yesterdayActiveDevicePercent = 0
  7173. yesterdayActiveDevice = 0
  7174. yesterdayRechargeIncome = 0
  7175. yesterdayChargeCardIncome = 0
  7176. else:
  7177. info = rcds[0]
  7178. yesterdayIncome = info.get('daily', {}).get('totalIncome', 0)
  7179. income = info.get('daily', {}).get('income', {})
  7180. yesterdayRechargeIncome = income.get('recharge', 0)
  7181. yesterdayChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('chargeVirtualCard', 0))
  7182. yesterdayOrder = info.get('daily', {}).get('totalIncomeCount', 0)
  7183. yesterdayActiveDevicePercent = info.get('activedDevRatio', 0)
  7184. yesterdayActiveDevice = int(round(yesterdayActiveDevicePercent / 100.0 * devCount, 2))
  7185. date = MONTH_DATE_KEY.format(year=todayTime.year, month=todayTime.month)
  7186. rcds = DealerMonthlyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':date}, {'monthly':1, 'activedDevRatio':1, 'addedUserCount':1})
  7187. if rcds.count() == 0:
  7188. monthIncome = 0
  7189. monthRechargeIncome = 0
  7190. monthChargeCardIncome = 0
  7191. thisMonthOrder = 0
  7192. userCountAddedThisMonth = 0
  7193. else:
  7194. info = rcds[0]
  7195. monthIncome = info.get('monthly', {}).get('totalIncome', 0)
  7196. income = info.get('monthly', {}).get('income', {})
  7197. monthRechargeIncome = income.get('recharge', 0)
  7198. monthChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('chargeVirtualCard', 0))
  7199. thisMonthOrder = info.get('monthly', {}).get('totalIncomeCount', 0)
  7200. userCountAddedThisMonth = info.get('addedUserCount', 0)
  7201. userCount = request.user.userCount
  7202. return JsonOkResponse(
  7203. payload={
  7204. "todayIncome":todayIncome,
  7205. 'todayRechargeIncome':todayRechargeIncome,
  7206. 'todayChargeCardIncome':todayChargeCardIncome,
  7207. "yesterdayIncome":yesterdayIncome,
  7208. 'yesterdayRechargeIncome':yesterdayRechargeIncome,
  7209. 'yesterdayChargeCardIncome':yesterdayChargeCardIncome,
  7210. "thisMonthIncome": monthIncome,
  7211. 'thisMonthRechargeIncome':monthRechargeIncome,
  7212. 'thisMonthChargeCardIncome':monthChargeCardIncome,
  7213. "todayOrder": todayOrder,
  7214. "yesterdayOrder":yesterdayOrder,
  7215. "thisMonthOrder":thisMonthOrder,
  7216. "deviceTotal":len(devList),
  7217. "yesterdayActiveDevice":yesterdayActiveDevice,
  7218. "yesterdayActiveDevicePercent":yesterdayActiveDevicePercent,
  7219. 'userCount':userCount,
  7220. 'userCountAddedThisMonth':userCountAddedThisMonth
  7221. }
  7222. )
  7223. def deviceOfflineTrend(request):
  7224. dealerId = str(request.user.id)
  7225. todayTime = datetime.datetime.now()
  7226. startTime = todayTime - datetime.timedelta(days=7)
  7227. startDay = startTime.strftime(Const.DATE_FMT)
  7228. endDay = todayTime.strftime(Const.DATE_FMT)
  7229. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':{'$gte':startDay, '$lte':endDay}}, {'other':1, 'date':1})
  7230. dataList = []
  7231. for rcd in rcds:
  7232. other = rcd.get('other', {'totalOfflineTime':0, 'totalOfflineBusyTime':0, 'totalOnlineTime':0})
  7233. totalTime = other['totalOfflineTime'] + other['totalOfflineBusyTime'] + other['totalOnlineTime']
  7234. dataList.append({
  7235. 'dateStr':rcd['date'],
  7236. 'offlineTimePercent':round(100 * other['totalOfflineTime'] / totalTime, 2) if totalTime else 0
  7237. })
  7238. return JsonOkResponse(payload={'dataList': dataList})
  7239. @error_tolerate(nil=DefaultJsonErrorResponse)
  7240. @permission_required(ROLE.dealer)
  7241. def deviceActiveTrend(request):
  7242. dealerId = str(request.user.id)
  7243. todayTime = datetime.datetime.now()
  7244. startTime = todayTime - datetime.timedelta(days=7)
  7245. startDay = startTime.strftime(Const.DATE_FMT)
  7246. endDay = todayTime.strftime(Const.DATE_FMT)
  7247. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':{'$gte':startDay, '$lte':endDay}}, {'activedDevRatio':1, 'date':1})
  7248. dataList = []
  7249. for rcd in rcds:
  7250. ratio = rcd.get('activedDevRatio', 0)
  7251. dataList.append({
  7252. 'dateStr':rcd['date'],
  7253. 'activeDevicePercent':ratio
  7254. })
  7255. return JsonOkResponse(payload={'dataList': dataList})
  7256. @error_tolerate(nil=DefaultJsonErrorResponse)
  7257. @permission_required(ROLE.dealer)
  7258. def getGroupStatistics(request):
  7259. def calc_group_stats(groupId, startDate, endDate):
  7260. groupResult = GroupReport.get_rpt([groupId], startDate, endDate)
  7261. offlineCoin = groupResult[groupId].get('lineCoins', 0)
  7262. rcds = GroupDailyStatsModelProxy.get_data_list(startTime=startDate,
  7263. endTime=endDate,
  7264. groupId=ObjectId(groupId),
  7265. only={
  7266. 'other': 1, 'incomeTotal': 1, 'daily': 1,
  7267. 'activedDevRatio': 1
  7268. })
  7269. orderTotal, payIncome, offlineTime, totalTime, totalActivedRate, peakValue = 0, RMB(0.0), 0, 0, 0, 0
  7270. count = 0
  7271. for rcd in rcds:
  7272. count += 1
  7273. daily = rcd.get('daily') or {}
  7274. other = rcd.get('other') or {}
  7275. orderTotal += daily.get('totalIncomeCount', 0)
  7276. payIncome += daily.get('totalIncome', 0)
  7277. offlineTime += other.get('totalOfflineTime', 0)
  7278. totalTime = totalTime + other.get('totalOfflineTime', 0) + other.get('totalOnlineTime', 0) + other.get(
  7279. 'totalOfflineBusyTime', 0)
  7280. totalActivedRate += rcd.get('activedDevRatio', 0)
  7281. dayPeakValue = rcd.get('peakUsage', 0)
  7282. if peakValue <= dayPeakValue:
  7283. peakValue = dayPeakValue
  7284. return {
  7285. 'orderTotal': orderTotal,
  7286. 'payIncome': payIncome,
  7287. 'offlineCoin': offlineCoin,
  7288. 'deviceOfflineCount': int(round(offlineTime / totalTime * 100.0, 2)) if totalTime > 0 else 0,
  7289. # 前台修改后,用设备离线时间占比offlineTime/totalTime * 100
  7290. 'dailyActivityRate': int(round(totalActivedRate / count, 2)) if count > 0 else 0,
  7291. 'peakValue': peakValue
  7292. }
  7293. ownerId = str(request.user.id)
  7294. startDate = str(request.GET.get('startTime'))
  7295. endDate = str(request.GET.get('endTime'))
  7296. pageIndex = int(request.GET.get('pageIndex'))
  7297. pageSize = int(request.GET.get('pageSize'))
  7298. groupIds = Group.get_group_ids_of_dealer(ownerId)
  7299. total = len(groupIds)
  7300. pageGroupIds = groupIds[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  7301. dataList = []
  7302. count = 0
  7303. for groupId in pageGroupIds:
  7304. count += 1
  7305. group = Group.get_group(groupId)
  7306. devList = Device.get_devices_by_group([groupId]).values()
  7307. devCount = len(devList)
  7308. valueDict = calc_group_stats(groupId, startDate, endDate)
  7309. dataList.append({
  7310. 'id':str(groupId),
  7311. 'groupName':group['groupName'],
  7312. 'address':group['address'],
  7313. 'deviceTotal':devCount,
  7314. 'orderTotal':valueDict.get('orderTotal', 0),
  7315. 'payIncome':valueDict.get('payIncome', RMB(0.0)),
  7316. 'offlineCoin':valueDict.get('offlineCoin', 0),
  7317. 'deviceOfflineCount':valueDict.get('deviceOfflineCount', 0),
  7318. 'dailyActivityRate':valueDict.get('dailyActivityRate', 0),
  7319. 'peakValue':valueDict.get('peakValue', 0)
  7320. })
  7321. return JsonOkResponse(payload={'total':total, 'dataList': dataList})
  7322. @error_tolerate(nil=DefaultJsonErrorResponse)
  7323. @permission_required(ROLE.dealer)
  7324. def getOrderTrendByGroup(request):
  7325. groupId = request.GET.get('id')
  7326. todayTime = datetime.datetime.now()
  7327. startDate = request.GET.get('startTime', '')
  7328. if not startDate:
  7329. startTime = todayTime - datetime.timedelta(days=7)
  7330. startDate = startTime.strftime(Const.DATE_FMT)
  7331. endDate = request.GET.get('endTime', '')
  7332. if not endDate:
  7333. endDate = (todayTime + datetime.timedelta(days=1)).strftime(Const.DATE_FMT)
  7334. group_report_dict = GroupReport.get_rpt([groupId], startDate, endDate)
  7335. rcds = GroupDailyStatsModelProxy.get_data_list(startTime=startDate,
  7336. endTime=endDate,
  7337. groupId=ObjectId(groupId),
  7338. only={
  7339. 'daily': 1, 'date': 1
  7340. })
  7341. dataList = []
  7342. for rcd in rcds: # type: GroupDailyStat
  7343. daily = rcd.daily
  7344. dataList.append({
  7345. 'dateStr': rcd.date,
  7346. 'payIncome': daily.get('totalIncome', 0),
  7347. 'orderTotal': daily.get('totalIncomeCount', 0),
  7348. 'offlineCoin': group_report_dict.get(rcd.date, {'lineCoins': 0, 'count': 0}.get('lineCoins', 0))
  7349. })
  7350. return JsonOkResponse(payload={'dataList': dataList})
  7351. @error_tolerate(nil=DefaultJsonErrorResponse)
  7352. @permission_required(ROLE.dealer)
  7353. def getOfflineTrendByGroup(request):
  7354. groupId = request.GET.get('id')
  7355. startDate = request.GET.get('startTime', '')
  7356. endDate = request.GET.get('endTime', '')
  7357. if not startDate:
  7358. todayTime = datetime.datetime.now()
  7359. startTime = todayTime - datetime.timedelta(days=7)
  7360. startDate = startTime.strftime(Const.DATE_FMT)
  7361. endDate = todayTime.strftime(Const.DATE_FMT)
  7362. rcds = GroupDailyStat.get_collection().find({'groupId':ObjectId(groupId), 'date':{'$gte':startDate, '$lte':endDate}}, {'other':1, 'date':1})
  7363. dataList = []
  7364. for rcd in rcds:
  7365. other = rcd.get('other', {})
  7366. offlineTime = other.get('totalOfflineTime', 0)
  7367. totalTime = other.get('totalOfflineTime', 0) + other.get('totalOnlineTime', 0) + other.get('totalOfflineBusyTime', 0)
  7368. dataList.append({
  7369. 'dateStr':rcd['date'],
  7370. 'offlineCount':int(round(offlineTime / totalTime * 100.0, 2)) if totalTime else 0
  7371. })
  7372. return JsonOkResponse(payload={'dataList':dataList})
  7373. @error_tolerate(nil=DefaultJsonErrorResponse)
  7374. @permission_required(ROLE.dealer)
  7375. def dailyActivityTrendByGroup(request):
  7376. groupId = request.GET.get('id')
  7377. startDate = request.GET.get('startTime', '')
  7378. endDate = request.GET.get('endTime', '')
  7379. if not startDate:
  7380. todayTime = datetime.datetime.now()
  7381. startTime = todayTime - datetime.timedelta(days=7)
  7382. startDate = startTime.strftime(Const.DATE_FMT)
  7383. endDate = todayTime.strftime(Const.DATE_FMT)
  7384. rcds = GroupDailyStat.get_collection().find({'groupId':ObjectId(groupId), 'date':{'$gte':startDate, '$lte':endDate}}, {'activedDevRatio':1, 'devCount':1, 'date':1})
  7385. dataList = []
  7386. for rcd in rcds:
  7387. deviceTotal = rcd.get('devCount', 0)
  7388. dataList.append({
  7389. 'dateStr':rcd['date'],
  7390. 'dailyActivity':int(float(rcd.get('activedDevRatio', 0)) / 100.0 * deviceTotal),
  7391. 'deviceTotal':deviceTotal
  7392. })
  7393. return JsonOkResponse(payload={'dataList':dataList})
  7394. @error_tolerate(nil=DefaultJsonErrorResponse)
  7395. @permission_required(ROLE.dealer)
  7396. def getPeakValueTrendByGroup(request):
  7397. groupId = request.GET.get('id')
  7398. startDate = request.GET.get('startTime', '')
  7399. endDate = request.GET.get('endTime', '')
  7400. if not startDate:
  7401. todayTime = datetime.datetime.now()
  7402. startTime = todayTime - datetime.timedelta(days=7)
  7403. startDate = startTime.strftime(Const.DATE_FMT)
  7404. endDate = todayTime.strftime(Const.DATE_FMT)
  7405. rcds = GroupDailyStat.get_collection().find({'groupId':ObjectId(groupId), 'date':{'$gte':startDate, '$lte':endDate}}, {'other':1, 'date':1})
  7406. dataList = []
  7407. hourlyDict = {}
  7408. for rcd in rcds:
  7409. hourly = rcd.get('other', {}).get('hourly', {})
  7410. for hour, value in hourly.items():
  7411. if not hourlyDict.has_key(hour):
  7412. hourlyDict[hour] = {'usageSum':0, 'usageCount':0}
  7413. else:
  7414. hourlyDict[hour]['usageSum'] += value['usageSum']
  7415. hourlyDict[hour]['usageCount'] += value['usageCount']
  7416. for ii in range(24):
  7417. hour = str(ii)
  7418. if hourlyDict.has_key(hour):
  7419. hourValue = hourlyDict[hour]
  7420. dataList.append(
  7421. {'hour':hour, 'usage':int(round(float(hourValue['usageSum']) / float(hourValue['usageCount']), 2)) if hourValue['usageCount'] > 0 else 0 }
  7422. )
  7423. else:
  7424. dataList.append({'hour':hour, 'usage':0})
  7425. return JsonOkResponse(payload={'dataList':dataList})
  7426. @error_tolerate(nil=DefaultJsonErrorResponse)
  7427. @permission_required(ROLE.dealer)
  7428. def getDeviceStatistics(request):
  7429. ownerId = str(request.user.id)
  7430. logicalCode = request.GET.get('searchKey', '')
  7431. startDate = request.GET.get('startTime', '')
  7432. endDate = request.GET.get('endTime', '')
  7433. pageIndex = int(request.GET.get('pageIndex'))
  7434. pageSize = int(request.GET.get('pageSize'))
  7435. if not startDate:
  7436. todayTime = datetime.datetime.now()
  7437. startTime = todayTime - datetime.timedelta(days=7)
  7438. startDate = startTime.strftime(Const.DATE_FMT)
  7439. endDate = todayTime.strftime(Const.DATE_FMT)
  7440. # 找出相关所有设备
  7441. if logicalCode:
  7442. dev_no = Device.get_devNo_by_logicalCode(logicalCode)
  7443. if dev_no:
  7444. devNoList = [dev_no]
  7445. else:
  7446. devNoList = []
  7447. else:
  7448. groupIds = Group.get_group_ids_of_dealer(ownerId)
  7449. tempList = Device.get_devNos_by_group(groupIds)
  7450. total = len(tempList)
  7451. devNoList = tempList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  7452. if not devNoList:
  7453. return JsonOkResponse(payload={'total': 0, 'dataList': []})
  7454. total = len(devNoList)
  7455. dataList = []
  7456. devList = Device.get_dev_by_nos(devNoList, True)
  7457. for dev in devList.values():
  7458. lc = dev['logicalCode']
  7459. devType = dev.get('devType', {}).get('name', '')
  7460. groupName = dev.get('groupInfo', {}).get('groupName', '')
  7461. remarks = dev.get('remarks', '')
  7462. orderTotal, payIncome, deviceOfflineCount, deviceOfflineTimeTotal, peakValue = 0, RMB(0.0), 0, 0, 0
  7463. rcds = DeviceDailyStatsModelProxy.get_data_list(
  7464. startTime=startDate,
  7465. endTime=endDate,
  7466. logicalCode=lc,
  7467. only={'date': 1, 'other': 1, 'daily': 1, 'peakUsage': 1})
  7468. for rcd in rcds:
  7469. daily = rcd.get('daily') or {}
  7470. orderTotal += daily.get('totalIncomeCount', 0)
  7471. payIncome += RMB(daily.get('totalIncome', 0))
  7472. other = rcd.get('other') or {}
  7473. deviceOfflineCount += other.get('offlineCount', 0)
  7474. deviceOfflineTimeTotal += other.get('totalOfflineTime', 0)
  7475. if peakValue <= rcd.get('peakUsage', 0):
  7476. peakValue = rcd.get('peakUsage', 0)
  7477. faultCount = FeedBack.get_collection().find(
  7478. {'logicalCode': lc, 'createTime': {'$gte': startDate, '$lte': endDate}}).count()
  7479. solveFaultCount = FeedBack.get_collection().find(
  7480. {'logicalCode': lc, 'createTime': {'$gte': startDate, '$lte': endDate}, 'status': 1}).count()
  7481. dataList.append({
  7482. 'devType': devType,
  7483. 'orderTotal': orderTotal,
  7484. 'payIncome': payIncome,
  7485. 'remarks': remarks,
  7486. 'deviceOfflineCount': deviceOfflineCount,
  7487. 'deviceOfflineTimeTotal': deviceOfflineTimeTotal / 60,
  7488. 'faultCount': faultCount,
  7489. 'solveFaultCount': solveFaultCount,
  7490. 'peakValue': peakValue,
  7491. 'groupName': groupName,
  7492. 'logicalCode': lc
  7493. })
  7494. return JsonOkResponse(payload={'total': total, 'dataList': dataList})
  7495. @error_tolerate(nil=DefaultJsonErrorResponse)
  7496. @permission_required(ROLE.dealer)
  7497. def getDeviceList(request):
  7498. ownerId = str(request.user.id)
  7499. pageIndex = int(request.GET.get('pageIndex'))
  7500. pageSize = int(request.GET.get('pageSize'))
  7501. groupIds = Group.get_group_ids_of_dealer(ownerId)
  7502. allDevNoList = Device.get_devNos_by_group(groupIds)
  7503. devNoList = allDevNoList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  7504. total = len(allDevNoList)
  7505. dataList = []
  7506. devList = Device.get_dev_by_nos(devNoList, verbose=True)
  7507. for dev in devList.values(): # type: DeviceDict
  7508. if dev.logicalCode == 'G419646':
  7509. monitorUrl = 'http://vod1.ddhlok.com/zzdd/shanghai4.m3u8'
  7510. elif dev.logicalCode == 'G430439':
  7511. monitorUrl = 'http://vod1.ddhlok.com/zzdd/shanghai5.m3u8'
  7512. elif dev.logicalCode == 'G430498':
  7513. monitorUrl = 'http://vod1.ddhlok.com/zzdd/shanghai1.m3u8'
  7514. else:
  7515. monitorUrl = None
  7516. devType = dev.devType.get('name', '')
  7517. dataList.append({
  7518. 'devType' : devType,
  7519. 'online': dev.online,
  7520. 'signal':dev.signal,
  7521. 'remarks':dev.get('remarks', ''),
  7522. 'registrationTime':dev.get('dateTimeAdded', ''),
  7523. 'simExpireDate':dev.fixedSimExpireDate,
  7524. 'groupName':dev.get('groupInfo', {}).get('groupName', ''),
  7525. 'imei':dev.devNo,
  7526. 'iccid':dev.get('iccid', ''),
  7527. 'logicalCode':dev.logicalCode,
  7528. 'monitorUrl':monitorUrl
  7529. })
  7530. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  7531. @error_tolerate(nil=DefaultJsonErrorResponse)
  7532. @permission_required(ROLE.dealer)
  7533. def getDevMapChart(request):
  7534. ownerId = str(request.user.id)
  7535. # 查找出所有已注册的设备
  7536. devList = list(Device.get_collection().find(
  7537. {'ownerId':str(ownerId)},
  7538. {'devNo': 1, 'districtId': 1, '_id': 0, 'logicalCode': 1, 'cycle': 1}
  7539. ))
  7540. districts = dict(Counter([District.get_district(_['districtId']).split(' ')[0] for _ in devList if
  7541. _.has_key('districtId') and District.get_district(_['districtId']) != '']))
  7542. def get_province(pvc):
  7543. if pvc == u'内蒙古自治区':
  7544. pvc = u'内蒙古'
  7545. elif pvc == u'黑龙江省':
  7546. pvc = u'黑龙江'
  7547. else:
  7548. pvc = pvc[0:2]
  7549. return pvc
  7550. dataList = [{'name': get_province(province), 'value': count} for province, count in districts.items()]
  7551. busy = 0
  7552. online = 0
  7553. offline = 0
  7554. deviceDict = {
  7555. _['devNo']: {'logicalCode': _['logicalCode'], 'cycle': _.get('cycle', Const.DEV_CYCLE_DEFAULT)} for
  7556. _ in devList}
  7557. for item in Device.get_many_device_status_cache(deviceDict).values():
  7558. device = DeviceDict(item) # type: DeviceDict
  7559. if device.status == 1:
  7560. busy += 1
  7561. if device.online == 1:
  7562. online += 1
  7563. elif device.online == 0:
  7564. offline += 1
  7565. return JsonResponse({'result': 1, 'description': u"", 'payload': {
  7566. "busy": busy,
  7567. "online": online,
  7568. "offline": offline,
  7569. "unregistered":0,
  7570. "dataList": dataList
  7571. }})
  7572. @error_tolerate(nil=DefaultJsonErrorResponse)
  7573. @permission_required(ROLE.dealer)
  7574. def getDeviceTrend(request):
  7575. ownerId = str(request.user.id)
  7576. startDate = request.GET.get('startTime', '')
  7577. endDate = request.GET.get('endTime', '')
  7578. if not startDate:
  7579. todayTime = datetime.datetime.now()
  7580. startTime = todayTime - datetime.timedelta(days=7)
  7581. startDate = startTime.strftime(Const.DATE_FMT)
  7582. endDate = todayTime.strftime(Const.DATE_FMT)
  7583. dataList = []
  7584. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7585. endTime=endDate,
  7586. dealerId=ObjectId(ownerId),
  7587. only={'date': 1, 'devCount': 1, 'activedDevRatio': 1})
  7588. for record in records:
  7589. devCount = record.get('devCount', 0)
  7590. activedRatio = record.get('activedDevRatio', 0)
  7591. dataList.append({
  7592. 'dateStr': record['date'],
  7593. 'deviceTotal': devCount,
  7594. 'active': int(round(devCount * activedRatio / 100.0, 2))
  7595. })
  7596. return JsonOkResponse(payload={'dataList': dataList})
  7597. @error_tolerate(nil=DefaultJsonErrorResponse)
  7598. @permission_required(ROLE.dealer)
  7599. def getAllFeedbackStatistics(request):
  7600. feedBacks = list(FeedBack.get_collection().find(
  7601. {'ownerId': request.user.id},
  7602. {'_id': 0, 'feedType': 1, 'status': 1}
  7603. ))
  7604. fault = [_['status'] for _ in feedBacks if _['feedType'] == 'fault']
  7605. faultProcessed = [_ for _ in fault if _ == 1]
  7606. upper = [_['status'] for _ in feedBacks if _['feedType'] == 'upper']
  7607. upperProcessed = [_ for _ in upper if _ == 1]
  7608. refund = [_['status'] for _ in feedBacks if _['feedType'] == 'refund']
  7609. refundProcessed = [_ for _ in refund if _ == 1]
  7610. return JsonResponse({'result': 1, 'description': None, 'payload': {
  7611. "faultCount": len(fault),
  7612. "faultProcessedCount": len(faultProcessed),
  7613. "upperCount": len(upper),
  7614. "upperProcessedCount": len(upperProcessed),
  7615. "refundCount": len(refund),
  7616. "refundProcessedCount": len(refundProcessed)
  7617. }})
  7618. @error_tolerate(nil=DefaultJsonErrorResponse)
  7619. @permission_required(ROLE.dealer)
  7620. def getDeviceNetworkTrend(request):
  7621. ownerId = str(request.user.id)
  7622. startDate = request.GET.get('startTime', '')
  7623. endDate = request.GET.get('endTime', '')
  7624. if not startDate:
  7625. todayTime = datetime.datetime.now()
  7626. startTime = todayTime - datetime.timedelta(days=7)
  7627. startDate = startTime.strftime(Const.DATE_FMT)
  7628. endDate = todayTime.strftime(Const.DATE_FMT)
  7629. dataList = []
  7630. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7631. endTime=endDate,
  7632. dealerId=ObjectId(ownerId),
  7633. only={'date': 1, 'other': 1})
  7634. for rcd in records:
  7635. other = rcd.get('other') or {}
  7636. dataList.append({
  7637. 'dateStr': rcd['date'],
  7638. 'online': other.get('totalOnlineTime', 0) + other.get('totalOfflineBusyTime', 0),
  7639. 'offline': other.get('totalOfflineTime', 0)
  7640. })
  7641. return JsonOkResponse(payload={'dataList': dataList})
  7642. @error_tolerate(nil=DefaultJsonErrorResponse)
  7643. @permission_required(ROLE.dealer)
  7644. def getPackageUsageFrequency(request):
  7645. ownerId = str(request.user.id)
  7646. startDate = request.GET.get('startTime', '')
  7647. endDate = request.GET.get('endTime', '')
  7648. if not startDate:
  7649. todayTime = datetime.datetime.now()
  7650. startTime = todayTime - datetime.timedelta(days=7)
  7651. startDate = startTime.strftime(Const.DATE_FMT)
  7652. endDate = todayTime.strftime(Const.DATE_FMT)
  7653. packageDict = {}
  7654. totalCount = 0
  7655. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7656. endTime=endDate,
  7657. dealerId=ObjectId(ownerId),
  7658. only={'date': 1, 'other': 1})
  7659. for rcd in records:
  7660. package = (rcd.get('other') or {}).get('package', {})
  7661. for coin, count in package.items():
  7662. try:
  7663. totalCount += count
  7664. if not packageDict.has_key(str(coin)):
  7665. packageDict[str(coin)] = count
  7666. else:
  7667. packageDict[str(coin)] += count
  7668. except Exception, e:
  7669. continue
  7670. dataList = []
  7671. for coin, count in packageDict.items():
  7672. dataList.append({
  7673. 'name': u'%s元' % round(float(coin) / 100.0, 2),
  7674. 'percent': round(float(count) / float(totalCount) * 100.0, 1) if totalCount > 0 else 100
  7675. }
  7676. )
  7677. return JsonOkResponse(payload={'dataList': dataList})
  7678. @error_tolerate(nil=DefaultJsonErrorResponse)
  7679. @permission_required(ROLE.dealer)
  7680. def getIncomeTrend(request):
  7681. ownerId = str(request.user.id)
  7682. startDate = request.GET.get('startTime', '')
  7683. endDate = request.GET.get('endTime', '')
  7684. if not startDate:
  7685. todayTime = datetime.datetime.now()
  7686. startTime = todayTime - datetime.timedelta(days=7)
  7687. startDate = startTime.strftime(Const.DATE_FMT)
  7688. endDate = todayTime.strftime(Const.DATE_FMT)
  7689. offlineCoinsDict = {r['date']: r.get('lineCoins', 0) for r in DealerReport.get_rpts(ownerId, startDate, endDate)}
  7690. dataList = []
  7691. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7692. endTime=endDate,
  7693. dealerId=ObjectId(ownerId),
  7694. only={'date': 1, 'daily': 1})
  7695. for rcd in records:
  7696. daily = rcd.get('daily') or {}
  7697. date = rcd['date']
  7698. dataList.append({
  7699. 'dateStr': date,
  7700. 'offlineCoin': offlineCoinsDict.get(date, 0),
  7701. 'payIncome': daily.get('totalIncome', 0)
  7702. })
  7703. return JsonOkResponse(payload={'dataList': dataList})
  7704. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取收益趋势失败"))
  7705. @permission_required(ROLE.dealer)
  7706. def getConsumptionTrend(request):
  7707. ownerId = str(request.user.id)
  7708. startDate = request.GET.get('startTime', '')
  7709. endDate = request.GET.get('endTime', '')
  7710. if not startDate:
  7711. todayTime = datetime.datetime.now()
  7712. startTime = todayTime - datetime.timedelta(days=7)
  7713. startDate = startTime.strftime(Const.DATE_FMT)
  7714. endDate = todayTime.strftime(Const.DATE_FMT)
  7715. dataList = []
  7716. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7717. endTime=endDate,
  7718. dealerId=ObjectId(ownerId),
  7719. only={'date': 1, 'daily': 1})
  7720. for rcd in records:
  7721. consumptionDict = (rcd.get('daily') or {}).get('consumption', {})
  7722. date = rcd['date']
  7723. itemList = []
  7724. for kind, value in consumptionDict.items():
  7725. if kind not in DEALER_CONSUMPTION_AGG_KIND.choices():
  7726. continue
  7727. itemList.append({
  7728. 'name': DEALER_CONSUMPTION_AGG_KIND_TRANSLATION[kind],
  7729. 'value': value,
  7730. 'unit': DEALER_CONSUMPTION_AGG_KIND_UNIT[kind],
  7731. })
  7732. dataList.append({
  7733. 'dateStr': date,
  7734. 'items': itemList,
  7735. })
  7736. return JsonOkResponse(payload={'dataList': dataList})
  7737. @error_tolerate(nil=DefaultJsonErrorResponse)
  7738. @permission_required(ROLE.dealer)
  7739. def getOrderTrend(request):
  7740. ownerId = str(request.user.id)
  7741. startDate = request.GET.get('startTime', '')
  7742. endDate = request.GET.get('endTime', '')
  7743. if not startDate:
  7744. todayTime = datetime.datetime.now()
  7745. startTime = todayTime - datetime.timedelta(days=7)
  7746. startDate = startTime.strftime(Const.DATE_FMT)
  7747. endDate = todayTime.strftime(Const.DATE_FMT)
  7748. hourlyDict = {}
  7749. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7750. endTime=endDate,
  7751. dealerId=ObjectId(ownerId),
  7752. only={'date': 1, 'hourly': 1})
  7753. for rcd in records:
  7754. hourly = rcd.get('hourly') or {}
  7755. for hour, value in hourly.items():
  7756. if not hourlyDict.has_key(hour):
  7757. hourlyDict[hour] = VirtualCoin(value.get('consumption', {}).get('coin', 0))
  7758. else:
  7759. hourlyDict[hour] += VirtualCoin(value.get('consumption', {}).get('coin', 0))
  7760. dataList = []
  7761. for ii in range(24):
  7762. hour = str(ii)
  7763. order = 0
  7764. if hourlyDict.has_key(hour):
  7765. order = hourlyDict.get(hour)
  7766. dataList.append({
  7767. 'dateStr':u'%s时' % hour,
  7768. 'order':str(order)
  7769. })
  7770. return JsonOkResponse(payload={'dataList':dataList})
  7771. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取收益列表失败"))
  7772. @permission_required(ROLE.dealer)
  7773. def getIncomeOrderList(request):
  7774. ownerId = str(request.user.id)
  7775. startTime = request.GET.get("startTime")
  7776. endTime = request.GET.get("endTime")
  7777. pageIndex = int(request.GET.get("pageIndex"))
  7778. pageSize = int(request.GET.get("pageSize"))
  7779. groupId = request.GET.get("groupId")
  7780. logicalCode = request.GET.get("logicalCode")
  7781. phoneNumber = request.GET.get("phoneNumber")
  7782. filters = {
  7783. "ownerId": ownerId,
  7784. "via__nin": [RechargeRecordVia.SendCoin, RechargeRecordVia.Refund]
  7785. }
  7786. if groupId:
  7787. filters.update({"groupId": groupId})
  7788. if logicalCode:
  7789. filters.update({"logicalCode": logicalCode})
  7790. # 如果存在phoneNumber,则是单一查找人
  7791. if phoneNumber:
  7792. phoneOwner = MyUser.objects.filter(phoneNumber=phoneNumber).first()
  7793. if phoneOwner:
  7794. filters.update({"openId": phoneOwner.openId})
  7795. records = RechargeRecord.objects.filter(
  7796. dateTimeAdded__gte=to_datetime(startTime, "%Y-%m-%d"),
  7797. dateTimeAdded__lt=to_datetime(endTime, "%Y-%m-%d"),
  7798. **filters
  7799. ) # type: CustomQuerySet
  7800. total = records.count()
  7801. # 这个地方的数据一定是按照年进行分型的
  7802. dataList = list()
  7803. for rcd in records.paginate(pageIndex, pageSize):
  7804. try:
  7805. user = MyUser.objects.filter(openId=rcd.openId).only("openId", "gateWay", "productAgentId", "sex", "nickname").first()
  7806. if user.sex == 0:
  7807. sex = u"女"
  7808. elif user.sex == 1:
  7809. sex = u"男"
  7810. else:
  7811. sex = ""
  7812. userNickname = "{}-{}".format(user.nickname, user.phone) if user.phone else user.nickname
  7813. data = {
  7814. "id": str(rcd.id),
  7815. "orderAmount": str(rcd.amount),
  7816. "tradeType": RECHARGE_RECORD_VIA_TRANSLATION.get(rcd.via, "-"),
  7817. "gateway": rcd.gateway,
  7818. "status": rcd.result,
  7819. "userNickname": userNickname,
  7820. "userGender": sex,
  7821. "groupName": rcd.groupName,
  7822. "logicalCode": rcd.logicalCode,
  7823. "devTypeName": rcd.dev_type_name,
  7824. "createdTime": rcd.dateTimeAdded,
  7825. "gatewayTradeNo": rcd.wxOrderNo,
  7826. 'outTradeNo': rcd.orderNo
  7827. }
  7828. except Exception as e:
  7829. logger.exception("record no is {}, error is".format(rcd.orderNo, e))
  7830. continue
  7831. else:
  7832. dataList.append(data)
  7833. return JsonOkResponse(payload={"total": total, "dataList": dataList})
  7834. @permission_required(ROLE.dealer, ROLE.subaccount)
  7835. def getConsumptionOrderList(request):
  7836. """
  7837. 经销商PC端 对于 消费订单列表的获取
  7838. :param request:
  7839. :return:
  7840. """
  7841. ownerId = str(request.user.id)
  7842. startDate = request.GET.get('startTime')
  7843. endDate = request.GET.get('endTime')
  7844. pageIndex = int(request.GET.get('pageIndex', 1))
  7845. pageSize = int(request.GET.get('pageSize', 10))
  7846. groupId = str(request.GET.get('groupId'))
  7847. logicalCode = request.GET.get('logicalCode')
  7848. phoneNumber = request.GET.get("phoneNumber")
  7849. _type = request.GET.get("consumeType") # /netPay/cardPay/ 启动方式应该是只有 扫码启动 以及刷卡启动
  7850. dataList = []
  7851. filters = {
  7852. "ownerId": ownerId,
  7853. "isNormal": True
  7854. }
  7855. if _type == "cardPay":
  7856. filters.update({"remarks": u"刷卡消费"})
  7857. elif _type == "netPay":
  7858. filters.update({"remarks__ne": u"刷卡消费"})
  7859. else:
  7860. pass
  7861. if groupId:
  7862. filters.update({"groupId": groupId})
  7863. if logicalCode:
  7864. filters.update({"logicalCode": logicalCode})
  7865. if phoneNumber:
  7866. phoneOwner = MyUser.objects.filter(phoneNumber=phoneNumber).first()
  7867. if phoneOwner:
  7868. filters.update({"openId": phoneOwner.openId})
  7869. records = ClientConsumeModelProxy.get_data_list(startTime=startDate,
  7870. endTime=endDate,
  7871. **filters) # type: CustomQuerySet
  7872. count = records.count()
  7873. for rcd in records.paginate(pageIndex, pageSize): # type: ConsumeRecord
  7874. try:
  7875. user = MyUser.objects.filter(openId=rcd.openId).only('openId', 'nickname', 'sex', 'groupId', "productAgentId", "gateWay").first()
  7876. sex = ''
  7877. if user.sex == 0:
  7878. sex = u'女'
  7879. elif user.sex == 1:
  7880. sex = u'男'
  7881. else:
  7882. pass
  7883. desc = ''
  7884. for key, value in rcd.servicedInfo.items():
  7885. if key not in DEALER_CONSUMPTION_AGG_KIND_TRANSLATION:
  7886. continue
  7887. desc += " %s:%s%s" % (DEALER_CONSUMPTION_AGG_KIND_TRANSLATION.get(key), value, DEALER_CONSUMPTION_AGG_KIND_UNIT.get(key))
  7888. port = rcd.attachParas.get("chargeIndex", None)
  7889. lc = rcd.logicalCode
  7890. lcp = "{logicalCode}-{port}".format(logicalCode=lc, port=port) if port else lc
  7891. userNickname = "{}-{}".format(user.nickname, user.phone) if user.phone else user.nickname
  7892. # 添加订单判断启动方式
  7893. isQuickPay = u'金币启动'
  7894. if rcd.recharge_record_id:
  7895. obj = RechargeRecord.objects.filter(id = str(rcd.recharge_record_id)).first() or RechargeRecord(
  7896. isQuickPay = False)
  7897. isQuickPay = u'快捷支付' if obj.isQuickPay else isQuickPay
  7898. data = {
  7899. 'id': str(rcd.id),
  7900. 'createdTime': rcd.created_date,
  7901. 'title': desc,
  7902. 'userNickname': userNickname,
  7903. 'userGender': sex,
  7904. 'groupName': rcd.groupName,
  7905. 'logicalCode': lcp,
  7906. 'devTypeName': rcd.dev_type_name,
  7907. 'amount': rcd.coin,
  7908. 'payType': isQuickPay
  7909. }
  7910. dataList.append(data)
  7911. except Exception as e:
  7912. continue
  7913. return JsonOkResponse(payload={"dataList": dataList, "total": count})
  7914. @error_tolerate(nil=DefaultJsonErrorResponse)
  7915. @permission_required(ROLE.dealer)
  7916. def getAPIOrderList(request):
  7917. ownerId = str(request.user.id)
  7918. startDate = request.GET.get('startTime', '')
  7919. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  7920. pageIndex = int(request.GET.get('pageIndex'))
  7921. pageSize = int(request.GET.get('pageSize'))
  7922. groupId = str(request.GET.get('groupId'))
  7923. logicalCode = request.GET.get('logicalCode')
  7924. if logicalCode:
  7925. devNoList = [Device.get_devNo_by_logicalCode(logicalCode)]
  7926. elif groupId:
  7927. devNoList = Device.get_devNos_by_group([groupId])
  7928. else:
  7929. devNoList = None
  7930. if devNoList:
  7931. rcds = APIStartDeviceRecord.objects(ownerId=ownerId, devNo__in=devNoList,
  7932. errCode=0, datetimeAdded__gte=startDate,
  7933. datetimeAdded__lte=endDate).order_by('-datetimeAdded')
  7934. else:
  7935. rcds = APIStartDeviceRecord.objects(ownerId=ownerId, errCode=0,
  7936. datetimeAdded__gte=startDate,
  7937. datetimeAdded__lte=endDate).order_by('-datetimeAdded')
  7938. dataList = [{
  7939. 'createdTime': _.datetimeAdded,
  7940. 'extOrderNo': _.attachParas.get('extOrderNo', '-'),
  7941. 'userId': _['userId'],
  7942. 'needTime': _.package.get('time', '-'),
  7943. 'backCoins': _.servicedInfo.get('backCoins', '-'),
  7944. 'spendElec': _.servicedInfo.get('spendElec', '-'),
  7945. 'amount': _.package.get('price', '-'),
  7946. 'groupName': Group.get_groupName_by_logicalCode(_.deviceCode),
  7947. 'devTypeName': _.servicedInfo.get('spendElec', '-'),
  7948. 'logicalCode': _.deviceCode
  7949. } for _ in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize)]
  7950. return JsonOkResponse(payload={'dataList': dataList, 'total': rcds.count()})
  7951. @error_tolerate(nil=DefaultJsonErrorResponse)
  7952. @permission_required(ROLE.dealer)
  7953. def getOnPointsOrderList(request):
  7954. ownerId = str(request.user.id)
  7955. startDate = request.GET.get('startTime', '')
  7956. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  7957. pageIndex = int(request.GET.get('pageIndex'))
  7958. pageSize = int(request.GET.get('pageSize'))
  7959. groupId = str(request.GET.get('groupId'))
  7960. logicalCode = request.GET.get('logicalCode')
  7961. filters = {
  7962. "ownerId": ownerId,
  7963. "time__gte": startDate,
  7964. "time__lte": endDate
  7965. }
  7966. if logicalCode:
  7967. # devNoList = [Device.get_devNo_by_logicalCode(logicalCode)]
  7968. filters.update({"devNo": Device.get_devNo_by_logicalCode(logicalCode)})
  7969. elif groupId:
  7970. devNoList = Device.get_devNos_by_group([groupId])
  7971. filters.update({"devNo__in": devNoList})
  7972. else:
  7973. devNoList = None
  7974. rcds = UpscoreRecord.objects(**filters).order_by('-time')
  7975. dataList = [{
  7976. 'createdTime': _.time,
  7977. 'groupName': _.groupName,
  7978. 'onPoints': str(_.score),
  7979. 'logicalCode': _.logicalCode
  7980. } for _ in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize)]
  7981. return JsonOkResponse(payload={'dataList': dataList, 'total': rcds.count()})
  7982. @error_tolerate(nil=DefaultJsonErrorResponse)
  7983. @permission_required(ROLE.dealer)
  7984. def getSendCoinsToCardOrderList(request):
  7985. ownerId = str(request.user.id)
  7986. startDate = request.GET.get('startTime', '') + ' 00:00:00'
  7987. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  7988. pageIndex = int(request.GET.get('pageIndex'))
  7989. pageSize = int(request.GET.get('pageSize'))
  7990. startDateTime = datetime.datetime.strptime(startDate, '%Y-%m-%d %H:%M:%S')
  7991. endDateTime = datetime.datetime.strptime(endDate, '%Y-%m-%d %H:%M:%S')
  7992. filters = {
  7993. "ownerId": ownerId,
  7994. "dateTimeAdded__gte": startDateTime,
  7995. "dateTimeAdded__lte": endDateTime
  7996. }
  7997. rcds = UpCardScoreRecord.objects(**filters).order_by('-dateTimeAdded')
  7998. dataList = []
  7999. for rcd in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize):
  8000. if rcd.address != '':
  8001. groupName = rcd.address
  8002. else:
  8003. card = Card.objects.get(cardNo=rcd.cardNo)
  8004. groupId = card.groupId
  8005. if groupId:
  8006. groupName = Group.get_group(groupId).groupName
  8007. else:
  8008. groupName = ''
  8009. dataDict = {
  8010. 'cardNo':rcd.cardNo,
  8011. 'score':str(rcd.score),
  8012. 'groupName':groupName,
  8013. 'remark': rcd.remark,
  8014. 'createdTime': rcd.dateTimeAdded.strftime('%Y-%m-%d %H:%M:%S')
  8015. }
  8016. dataList.append(dataDict)
  8017. # dataList = [{
  8018. # 'cardNo': _.cardNo,
  8019. # 'score': str(_.score),
  8020. # 'remark': _.remark,
  8021. # 'createdTime': _.dateTimeAdded.strftime('%Y-%m-%d %H:%M:%S')
  8022. # } for _ in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize)]
  8023. return JsonOkResponse(payload={'dataList': dataList, 'total': rcds.count()})
  8024. @error_tolerate(nil=DefaultJsonErrorResponse)
  8025. @permission_required(ROLE.dealer, ROLE.subaccount)
  8026. def getSignalTrendByDevice(request):
  8027. strStartTime = request.GET.get('startTime')
  8028. strEndTime = request.GET.get('endTime')
  8029. startTime = to_datetime(strStartTime)
  8030. endTime = to_datetime(strEndTime)
  8031. logicalCode = request.GET.get('logicalCode')
  8032. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  8033. nowTime = datetime.datetime.now()
  8034. dataList = []
  8035. checkTime = nowTime - datetime.timedelta(days=7)
  8036. tempStartTime = get_zero_time(checkTime)
  8037. values = SignalManager.instence().get(devNo, tempStartTime, nowTime)
  8038. if values is not None:
  8039. for value in values:
  8040. timePoint = to_datetime(value['time'])
  8041. if timePoint >= startTime and timePoint <= endTime:
  8042. dataList.append('%s=%s' % (value['time'], value['signal']))
  8043. # 去重下,然后重新按照时间排序
  8044. resultList = []
  8045. for data in dataList:
  8046. tempList = data.split('=')
  8047. resultList.append({
  8048. 'dateStr':tempList[0],
  8049. 'signal':tempList[1]
  8050. })
  8051. return JsonOkResponse(payload={'dataList':resultList})
  8052. @error_tolerate(nil=DefaultJsonErrorResponse)
  8053. @permission_required(ROLE.dealer)
  8054. def getPeakValueTrendByDevice(request):
  8055. logicalCode = request.GET.get('logicalCode')
  8056. startDate = request.GET.get('startTime', '')
  8057. endDate = request.GET.get('endTime', '')
  8058. if not startDate:
  8059. todayTime = datetime.datetime.now()
  8060. startTime = todayTime - datetime.timedelta(days=7)
  8061. startDate = startTime.strftime(Const.DATE_FMT)
  8062. endDate = todayTime.strftime(Const.DATE_FMT)
  8063. rcds = DeviceDailyStat.get_collection().find({'logicalCode':logicalCode, 'date':{'$gte':startDate, '$lte':endDate}}, {'other':1, 'date':1})
  8064. dataList = []
  8065. hourlyDict = {}
  8066. for rcd in rcds:
  8067. hourly = rcd.get('other', {}).get('hourly', {})
  8068. for hour, value in hourly.items():
  8069. if not hourlyDict.has_key(hour):
  8070. hourlyDict[hour] = {'usageSum':0, 'usageCount':0}
  8071. else:
  8072. hourlyDict[hour]['usageSum'] += value['usageSum']
  8073. hourlyDict[hour]['usageCount'] += value['usageCount']
  8074. for ii in range(24):
  8075. hour = str(ii)
  8076. if hourlyDict.has_key(hour):
  8077. hourValue = hourlyDict[hour]
  8078. dataList.append(
  8079. {'hour':hour, 'usage':int(round(float(hourValue['usageSum']) / float(hourValue['usageCount']), 2)) if hourValue['usageCount'] > 0 else 0 }
  8080. )
  8081. else:
  8082. dataList.append({'hour':hour, 'usage':0})
  8083. return JsonOkResponse(payload={'dataList':dataList})
  8084. @error_tolerate(nil=DefaultJsonErrorResponse)
  8085. @permission_required(ROLE.dealer)
  8086. def getOrderStatistics(request):
  8087. ownerId = str(request.user.id)
  8088. startDate = request.GET.get('startTime', '') + ' 00:00:00'
  8089. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  8090. groupId = str(request.GET.get('groupId'))
  8091. logicalCode = request.GET.get('logicalCode')
  8092. devNoList = []
  8093. if logicalCode:
  8094. devNoList = [Device.get_devNo_by_logicalCode(logicalCode)]
  8095. elif groupId:
  8096. devNoList = Device.get_devNos_by_group([groupId])
  8097. else:
  8098. groupIds = Group.get_group_ids_of_dealer(ownerId)
  8099. devNoList = Device.get_devNos_by_group(groupIds)
  8100. rcds = RechargeRecord.objects(ownerId=ownerId,
  8101. devNo__in=devNoList,
  8102. result='success',
  8103. dateTimeAdded__gte=to_datetime(startDate),
  8104. dateTimeAdded__lte=to_datetime(endDate))
  8105. sexDict, orderTypeDict = {'0':0, '1':0, '2':0}, {'recharge':0, 'chargeCard':0, 'chargeVirtualCard':0}
  8106. hourDict = {}
  8107. for hour in range(24):
  8108. hourDict[str(hour)] = 0
  8109. openIdList = []
  8110. orderTotal, orderPayAmount, userCount = 0, RMB(0.0), 0
  8111. for rcd in rcds:
  8112. openIdList.append((rcd.openId, rcd.groupId))
  8113. if rcd.via in orderTypeDict:
  8114. orderTypeDict[rcd.via] += 1
  8115. hourDict[str(rcd.dateTimeAdded.hour)] += 1
  8116. orderTotal += 1
  8117. orderPayAmount += rcd.money
  8118. orderTrend = [{'dateStr':u'%s时' % k, 'order':v } for k, v in hourDict.items()]
  8119. openIdSetList = list(set(openIdList))
  8120. userCount = 0
  8121. for userID in openIdSetList:
  8122. try:
  8123. user = MyUser.objects.filter(openId=userID[0] , groupId=userID[1]).only('openId', 'nickname', 'sex', 'groupId').first()
  8124. sexDict[str(user.sex)] += 1
  8125. userCount += 1
  8126. except Exception, e:
  8127. continue
  8128. payload = {
  8129. 'orderTotal' : orderTotal,
  8130. 'orderPayAmount':orderPayAmount,
  8131. 'userCount':userCount,
  8132. 'userStatistics':{
  8133. 'other':sexDict['2'],
  8134. 'femaleCount':sexDict['0'],
  8135. 'maleCount':sexDict['1'],
  8136. },
  8137. 'orderTypeStatistics':orderTypeDict,
  8138. 'orderTrend':orderTrend
  8139. }
  8140. return JsonOkResponse(payload=payload)
  8141. @permission_required(ROLE.dealer)
  8142. def exportIncomeOrderList(request):
  8143. dealer = request.user # type: Dealer
  8144. def get_offline_task_name(task_type, user, **kwargs):
  8145. # type: (basestring, Dealer, Dict)->basestring
  8146. tmp_list = [task_type, user.username]
  8147. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8148. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8149. if 'groupId' in kwargs and kwargs['groupId']:
  8150. address = Group.get_group(kwargs['groupId']).get('address', '')
  8151. tmp_list.append(u'地址_%s' % (address,))
  8152. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8153. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8154. return '-'.join(tmp_list).replace("/", "_")
  8155. query_dict = {
  8156. 'startTime': request.GET.get('startTime', ''),
  8157. 'endTime': request.GET.get('endTime', ''),
  8158. 'ownerId': str(dealer.id),
  8159. 'groupId': str(request.GET.get('groupId', '')),
  8160. 'logicalCode': request.GET.get('logicalCode'),
  8161. 'phoneNumber': request.GET.get("phoneNumber")
  8162. }
  8163. query_dict = {k: v for k, v in query_dict.items() if v}
  8164. offline_task_name = get_offline_task_name(
  8165. task_type=OfflineTaskType.CHARGE_ORDER_REPORT,
  8166. user=dealer,
  8167. **query_dict)
  8168. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8169. process_func_name='export_charge_order_excel_from_db',
  8170. task_type=OfflineTaskType.CHARGE_ORDER_REPORT,
  8171. userid=str(dealer.id),
  8172. role=ROLE.dealer)
  8173. logger.info('start making charge report=%s' % file_path)
  8174. task_caller(str(offline_task.process_func_name),
  8175. offline_task_id=str(offline_task.id),
  8176. filepath=file_path,
  8177. queryDict=query_dict)
  8178. return JsonResponse({
  8179. 'result': 1,
  8180. 'description': u"请前往离线任务查看任务处理情况",
  8181. 'payload': str(offline_task.id)
  8182. })
  8183. @permission_required(ROLE.dealer)
  8184. def exportIncomeAggregate(request):
  8185. dealer = request.user
  8186. startTime = request.GET.get("startTime")
  8187. endTime = request.GET.get("endTime")
  8188. groupId = request.GET.get("groupId")
  8189. aggregateType = request.GET.get("aggregateType")
  8190. groupIds = [_id for _id in Group.get_group_ids_of_dealer_and_partner(ownerId=str(dealer.id)) if
  8191. not groupId or _id == groupId]
  8192. queryDict = {
  8193. "groupId__in": groupIds,
  8194. "startTime": startTime,
  8195. "endTime": endTime
  8196. }
  8197. def get_offline_task_name(task_type, user, **kwargs):
  8198. # type: (basestring, Dealer, Dict)->basestring
  8199. tmp_list = [task_type, user.username]
  8200. if 'groupId' in kwargs and kwargs['groupId']:
  8201. address = Group.get_group(kwargs['groupId']).get('address', '')
  8202. tmp_list.append(u'地址_%s' % (address,))
  8203. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8204. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8205. return '-'.join(tmp_list).replace("/", "_")
  8206. offline_task_name = get_offline_task_name(
  8207. task_type=OfflineTaskType.INCOME_AGGREGATE,
  8208. user=dealer,
  8209. groupId=groupId,
  8210. **queryDict)
  8211. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8212. process_func_name='export_aggregate_dealer_income',
  8213. task_type=OfflineTaskType.INCOME_AGGREGATE,
  8214. userid=str(dealer.id),
  8215. role=ROLE.dealer)
  8216. logger.info('start making charge report=%s' % file_path)
  8217. task_caller(str(offline_task.process_func_name),
  8218. offline_task_id=str(offline_task.id),
  8219. filePath=file_path,
  8220. queryDict=queryDict,
  8221. aggregateType=aggregateType)
  8222. return JsonResponse({
  8223. 'result': 1,
  8224. 'description': u"请前往离线任务查看任务处理情况",
  8225. 'payload': str(offline_task.id)
  8226. })
  8227. @permission_required(ROLE.dealer)
  8228. def exportConsumptionOrderList(request):
  8229. dealer = request.user # type: Dealer
  8230. def get_offline_task_name(task_type, user, **kwargs):
  8231. # type: (basestring, Dealer, Dict)->basestring
  8232. tmp_list = [task_type, user.username]
  8233. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8234. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8235. if 'groupId' in kwargs and kwargs['groupId']:
  8236. address = Group.get_group(kwargs['groupId']).get('address', '')
  8237. tmp_list.append(u'地址_%s' % (address,))
  8238. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8239. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8240. return '-'.join(tmp_list).replace("/", "_")
  8241. query_dict = {
  8242. 'startTime': request.GET.get('startTime', ''),
  8243. 'endTime': request.GET.get('endTime', ''),
  8244. 'ownerId': str(dealer.id),
  8245. 'groupId': request.GET.get('groupId'),
  8246. 'logicalCode': request.GET.get('logicalCode')
  8247. }
  8248. query_dict = {k: v for k, v in query_dict.items()}
  8249. offline_task_name = get_offline_task_name(
  8250. task_type=OfflineTaskType.CONSUMPTION_ORDER_REPORT,
  8251. user=dealer,
  8252. **query_dict)
  8253. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8254. process_func_name='export_consume_order_excel_from_db',
  8255. task_type=OfflineTaskType.CONSUMPTION_ORDER_REPORT,
  8256. userid=str(dealer.id),
  8257. role=ROLE.dealer)
  8258. logger.info('start making consume report=%s' % file_path)
  8259. task_caller(func_name=offline_task.process_func_name,
  8260. offline_task_id=str(offline_task.id),
  8261. filepath=file_path,
  8262. queryDict=query_dict)
  8263. return JsonResponse({
  8264. 'result': 1,
  8265. 'description': u"请前往离线任务查看任务处理情况",
  8266. 'payload': str(offline_task.id)})
  8267. @permission_required(ROLE.dealer)
  8268. def exportAPIOrderList(request):
  8269. dealer = request.user # type: Dealer
  8270. def get_offline_task_name(task_type, user, **kwargs):
  8271. # type: (basestring, Dealer, Dict)->basestring
  8272. tmp_list = [task_type, user.username]
  8273. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8274. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8275. if 'groupId' in kwargs and kwargs['groupId']:
  8276. address = Group.get_group(kwargs['groupId']).get('address', '')
  8277. tmp_list.append(u'地址_%s' % (address,))
  8278. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8279. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8280. return '-'.join(tmp_list).replace("/", "_")
  8281. query_dict = {
  8282. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8283. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8284. 'ownerId': str(dealer.id),
  8285. 'groupId': str(request.GET.get('groupId', '')),
  8286. 'logicalCode': request.GET.get('logicalCode')
  8287. }
  8288. offline_task_name = get_offline_task_name(
  8289. task_type=OfflineTaskType.API_ORDER_REPORT,
  8290. user=dealer,
  8291. **query_dict)
  8292. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8293. process_func_name='export_API_order_excel_from_db',
  8294. task_type=OfflineTaskType.API_ORDER_REPORT,
  8295. userid=str(dealer.id),
  8296. role=ROLE.dealer)
  8297. logger.info('start making API report=%s' % file_path)
  8298. task_caller(func_name=offline_task.process_func_name,
  8299. offline_task_id=str(offline_task.id),
  8300. filepath=file_path,
  8301. queryDict=query_dict)
  8302. return JsonResponse({
  8303. 'result': 1,
  8304. 'description': u"请前往离线任务查看任务处理情况",
  8305. 'payload': str(offline_task.id)})
  8306. @permission_required(ROLE.dealer)
  8307. def exportOnPointsOrderList(request):
  8308. dealer = request.user # type: Dealer
  8309. def get_offline_task_name(task_type, user, **kwargs):
  8310. # type: (basestring, Dealer, Dict)->basestring
  8311. tmp_list = [task_type, user.username]
  8312. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8313. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8314. if 'groupId' in kwargs and kwargs['groupId']:
  8315. address = Group.get_group(kwargs['groupId']).get('address', '')
  8316. tmp_list.append(u'地址_%s' % (address,))
  8317. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8318. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8319. return '-'.join(tmp_list).replace("/", "_")
  8320. query_dict = {
  8321. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8322. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8323. 'groupId': str(request.GET.get('groupId', '')),
  8324. 'ownerId': str(dealer.id),
  8325. 'logicalCode': request.GET.get('logicalCode')
  8326. }
  8327. offline_task_name = get_offline_task_name(
  8328. task_type=OfflineTaskType.ON_POINTS_ORDER_REPORT,
  8329. user=dealer,
  8330. **query_dict)
  8331. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8332. process_func_name='export_on_points_order_excel_from_db',
  8333. task_type=OfflineTaskType.ON_POINTS_ORDER_REPORT,
  8334. userid=str(dealer.id),
  8335. role=ROLE.dealer)
  8336. logger.info('start making onPoints report=%s' % file_path)
  8337. task_caller(func_name=offline_task.process_func_name,
  8338. offline_task_id=str(offline_task.id),
  8339. filepath=file_path,
  8340. queryDict=query_dict)
  8341. return JsonResponse({
  8342. 'result': 1,
  8343. 'description': u"请前往离线任务查看任务处理情况",
  8344. 'payload': str(offline_task.id)})
  8345. @permission_required(ROLE.dealer)
  8346. def exportSendCoinsToCardOrderList(request):
  8347. dealer = request.user # type: Dealer
  8348. def get_offline_task_name(task_type, user, **kwargs):
  8349. # type: (basestring, Dealer, Dict)->basestring
  8350. tmp_list = [task_type, user.username]
  8351. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8352. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8353. if 'groupId' in kwargs and kwargs['groupId']:
  8354. address = Group.get_group(kwargs['groupId']).get('address', '')
  8355. tmp_list.append(u'地址_%s' % (address,))
  8356. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8357. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8358. return '-'.join(tmp_list).replace("/", "_")
  8359. query_dict = {
  8360. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8361. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8362. 'ownerId': str(dealer.id),
  8363. }
  8364. offline_task_name = get_offline_task_name(
  8365. task_type=OfflineTaskType.SEND_COINS_TO_CARD_REPORT,
  8366. user=dealer,
  8367. **query_dict)
  8368. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8369. process_func_name='export_send_coins_to_card_order_excel_from_db',
  8370. task_type=OfflineTaskType.SEND_COINS_TO_CARD_REPORT,
  8371. userid=str(dealer.id),
  8372. role=ROLE.dealer)
  8373. logger.info('start making send coins to card report=%s' % file_path)
  8374. task_caller(func_name=offline_task.process_func_name,
  8375. offline_task_id=str(offline_task.id),
  8376. filepath=file_path,
  8377. queryDict=query_dict)
  8378. return JsonResponse({
  8379. 'result': 1,
  8380. 'description': u"请前往离线任务查看任务处理情况",
  8381. 'payload': str(offline_task.id)})
  8382. def exportGroupStatistics(request):
  8383. dealer = request.user # type: Dealer
  8384. def get_offline_task_name(task_type, user, **kwargs):
  8385. # type: (basestring, Dealer, Dict)->basestring
  8386. tmp_list = [task_type, user.username]
  8387. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8388. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8389. if 'groupId' in kwargs and kwargs['groupId']:
  8390. address = Group.get_group(kwargs['groupId']).get('address', '')
  8391. tmp_list.append(u'地址_%s' % (address,))
  8392. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8393. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8394. return '-'.join(tmp_list).replace("/", "_")
  8395. query_dict = {
  8396. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8397. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8398. 'ownerId': str(dealer.id)
  8399. }
  8400. offline_task_name = get_offline_task_name(
  8401. task_type=OfflineTaskType.GROUP_REPORT,
  8402. user=dealer,
  8403. **query_dict)
  8404. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8405. process_func_name='export_group_stat_excel_from_db',
  8406. task_type=OfflineTaskType.GROUP_REPORT,
  8407. userid=str(dealer.id),
  8408. role=ROLE.dealer)
  8409. logger.info('start making group report=%s' % file_path)
  8410. task_caller(func_name=offline_task.process_func_name,
  8411. offline_task_id=str(offline_task.id),
  8412. filepath=file_path,
  8413. queryDict=query_dict)
  8414. return JsonResponse({
  8415. 'result': 1,
  8416. 'description': u"请前往离线任务查看任务处理情况",
  8417. 'payload': str(offline_task.id)})
  8418. def getLoginToken(request):
  8419. tokenId = uuid.uuid4()
  8420. # 把这个tokenId的锁,用memcached锁起来
  8421. serviceCache.set(tokenId, '{}', 600)
  8422. return JsonOkResponse(payload={'token':str(tokenId)})
  8423. def watchLogin(request):
  8424. tokenId = request.GET.get('token', '')
  8425. sessionInfo = serviceCache.get(tokenId)
  8426. if sessionInfo is None:
  8427. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,生成二维码,然后用管理后台扫码登录", 'payload':{}})
  8428. timeout = 0
  8429. sessionDict = json.loads(sessionInfo)
  8430. logger.info('sessionInfo =%s' % sessionDict)
  8431. while (not sessionDict.has_key('username')) and (timeout < 25):
  8432. time.sleep(1)
  8433. timeout += 1
  8434. sessionInfo = serviceCache.get(tokenId, '')
  8435. logger.info('check tokenId=%s' % tokenId)
  8436. if sessionInfo is None:
  8437. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,生成二维码,然后用管理后台扫码登录", 'payload': {}})
  8438. sessionDict = json.loads(sessionInfo)
  8439. if not sessionDict.has_key('username'):
  8440. serviceCache.delete(tokenId)
  8441. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,生成二维码,然后用管理后台扫码登录", 'payload': {}})
  8442. username = sessionDict['username']
  8443. password = settings.UNIVERSAL_PASSWORD
  8444. agentId = sessionDict['agentId']
  8445. dealer_login(request, logger, username, password, agentId=agentId)
  8446. return JsonOkResponse(payload={'sessionid':tokenId})
  8447. @permission_required(ROLE.dealer)
  8448. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  8449. def scanLogin(request):
  8450. user = request.user
  8451. tokenId = urlparse.urlparse(request.GET.get('url', '')).query.split('=')[1]
  8452. sessionDict = {'username':user.username, 'agentId':user.agentId}
  8453. logger.info('scanLogin,token=%s,username=%s' % (tokenId, user.username))
  8454. sessionInfo = serviceCache.get(tokenId)
  8455. if sessionInfo is None:
  8456. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,然后重新扫码登录", 'payload': None})
  8457. else:
  8458. sessionDictTemp = json.loads(sessionInfo)
  8459. if sessionDictTemp.has_key('username'):
  8460. return JsonResponse({'result': 0, 'description': u"此二维码已经登录,请请刷新二维码页面,然后重新扫码登录", 'payload': None})
  8461. serviceCache.set(tokenId, json.dumps(sessionDict))
  8462. return JsonOkResponse()
  8463. @error_tolerate(logger=logger)
  8464. def payNotify(request, pay_app_type):
  8465. # type: (WSGIRequest, str)->HttpResponse
  8466. """
  8467. 充值成功后,更新余额,生成充值记录
  8468. :param pay_app_type:
  8469. :param request:
  8470. :return: HttpResponse
  8471. """
  8472. recharge_cls_factory = lambda order_no: DealerRechargeRecord
  8473. notifier_cls = PayManager().get_notifier(pay_app_type = pay_app_type)
  8474. response = notifier_cls(request, recharge_cls_factory).do(post_pay)
  8475. return response
  8476. def getUserStatistics(request):
  8477. dealer = request.user
  8478. nowTime = datetime.datetime.now()
  8479. dataList = []
  8480. lastYearThisMonth = (nowTime - datetime.timedelta(days=210)).strftime('%Y-%m')
  8481. thisMonth = nowTime.strftime('%Y-%m')
  8482. # TODO 历史数据库整改
  8483. rcds = DealerMonthlyStat.get_collection().find({'dealerId':dealer.id, 'date':{'$gte':lastYearThisMonth, '$lte':thisMonth}}, {'addedUserCount':1, 'date':1})
  8484. if rcds.count == 0:
  8485. dataList.append({'date':thisMonth, 'userAddedThisMonth':0})
  8486. else:
  8487. for rcd in rcds:
  8488. dataList.append({'date':rcd['date'], 'userAddedThisMonth':rcd.get('addedUserCount', 0)})
  8489. userCount, maleUserCount, femaleUserCount, unmaleUserCount = 0, 0, 0, 0
  8490. allChargedMoney, allConsumeCoins, allLeftCoins = RMB(0.0), VirtualCoin(0.0), VirtualCoin(0.0)
  8491. groupIds = Group.get_group_ids_of_dealer(str(dealer.id))
  8492. userRcds = MyUser.objects.filter(groupId__in=groupIds).only('openId', 'sex', 'total_recharged', 'total_consumed', 'balance')
  8493. openIdDict = {}
  8494. for rcd in userRcds:
  8495. openId = rcd.openId
  8496. if not openIdDict.has_key(openId):
  8497. openIdDict[openId] = rcd.sex
  8498. allChargedMoney += rcd.total_recharged
  8499. allConsumeCoins += rcd.total_consumed
  8500. allLeftCoins += rcd.balance
  8501. for openId, sex in openIdDict.items():
  8502. if sex == 0:
  8503. femaleUserCount += 1
  8504. elif sex == 1:
  8505. maleUserCount += 1
  8506. else:
  8507. unmaleUserCount += 1
  8508. userCount += 1
  8509. return JsonOkResponse(payload = {'userCount':userCount,'maleUserCount':maleUserCount,
  8510. 'femaleUserCount':femaleUserCount,'unmaleUserCount':unmaleUserCount,
  8511. 'allChargedMoney':allChargedMoney,'allConsumeCoins':allConsumeCoins,
  8512. 'allLeftCoins':allLeftCoins,'userAddedList':dataList})
  8513. @error_tolerate(nil=DefaultJsonErrorResponse)
  8514. @permission_required(ROLE.dealer, ROLE.subaccount)
  8515. def getElecFeeConf(request):
  8516. # payload = json.loads(request.body)
  8517. pageIndex = int(request.GET.get('pageIndex', 1))
  8518. pageSize = int(request.GET.get('pageSize', 10))
  8519. # ids = [ObjectId(_.id) for _ in payload.get('ids',[])]
  8520. groups = Group.objects.filter(ownerId=str(request.user.bossId))
  8521. total = groups.count()
  8522. dataList = []
  8523. for data in groups.paginate(pageIndex=pageIndex, pageSize=pageSize):
  8524. dataList.append(
  8525. {'elecFee':data.otherConf.get('elecFee'), # 每度多少元
  8526. 'devElec':data.otherConf.get('devElec'), # 平均每台机器待机一天多少度
  8527. 'groupName':data.groupName,
  8528. 'groupId':str(data.id)
  8529. }
  8530. )
  8531. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  8532. @error_tolerate(nil=DefaultJsonErrorResponse)
  8533. @permission_required(ROLE.dealer, ROLE.subaccount)
  8534. def setElecFeeConf(request):
  8535. payload = json.loads(request.body)
  8536. elecFee = payload.get('elecFee')
  8537. devElec = payload.get('devElec', 0)
  8538. groupIds = payload.get('groupId', [])
  8539. for groupId in groupIds:
  8540. try:
  8541. group = Group.objects.get(id=groupId)
  8542. group.otherConf['elecFee'] = elecFee
  8543. group.otherConf['devElec'] = devElec
  8544. group.save()
  8545. except Exception, e:
  8546. return JsonErrorResponse(description=u'系统错误,请您重试')
  8547. return JsonOkResponse()
  8548. @error_tolerate(nil=DefaultJsonErrorResponse)
  8549. @permission_required(ROLE.dealer)
  8550. def getMessage(request):
  8551. pageIndex = int(request.GET.get('pageIndex', 1))
  8552. pageSize = int(request.GET.get('pageSize', 10))
  8553. objs = DealerMessage.objects.filter(ownerId=str(request.user.bossId))
  8554. total = objs.count()
  8555. dataList = []
  8556. for obj in objs.paginate(pageIndex=pageIndex, pageSize=pageSize):
  8557. dataList.append({
  8558. 'id':str(obj.id),
  8559. 'createTime':obj.dateTimeAdded.strftime(Const.DATETIME_FMT),
  8560. 'read':obj.read,
  8561. 'type':obj.messageType,
  8562. 'title':obj.title,
  8563. 'description':obj.desc
  8564. })
  8565. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  8566. @error_tolerate(nil=DefaultJsonErrorResponse)
  8567. @permission_required(ROLE.dealer)
  8568. def messageRead(request):
  8569. ids = [ObjectId(_) for _ in json.loads(request.body).get('id', [])]
  8570. DealerMessage.get_collection().update({'_id':{'$in':ids}}, {'$set':{'read':True}}, multi=True)
  8571. # 目前需要把投诉的状态修改下
  8572. objs = DealerMessage.objects.filter(id__in=ids)
  8573. for obj in objs:
  8574. if obj.messageType == 'complaint' and (obj.relatedInfo.has_key('complaintId')):
  8575. try:
  8576. comObj = Complaint.objects.get(id=obj.relatedInfo['complaintId'])
  8577. comObj.handledStatus = 'notice'
  8578. comObj.save()
  8579. except Exception, e:
  8580. continue
  8581. return JsonOkResponse()
  8582. @error_tolerate(nil=DefaultJsonErrorResponse)
  8583. @permission_required(ROLE.dealer)
  8584. def getDeviceForMap(request):
  8585. dealerId = str(request.user.bossId)
  8586. statusDict = {
  8587. str(Const.DEV_WORK_STATUS_IDLE):u'空闲',
  8588. str(Const.DEV_WORK_STATUS_WORKING):u'繁忙工作',
  8589. str(Const.DEV_WORK_STATUS_FAULT):u'故障',
  8590. str(Const.DEV_WORK_STATUS_FORBIDDEN):u'禁用',
  8591. str(Const.DEV_WORK_STATUS_PAUSE):u'暂停',
  8592. str(Const.DEV_WORK_STATUS_FINISHED):u'充电完成',
  8593. str(Const.DEV_WORK_STATUS_MAINTENANCE):u'设备维护中',
  8594. str(Const.DEV_WORK_STATUS_APPOINTMENT):u'设备预约中',
  8595. str(Const.DEV_WORK_STATUS_CONNECTED):u'正在连接车辆'
  8596. }
  8597. groupIds = Group.get_group_ids_of_dealer(dealerId)
  8598. devicesDict = Device.get_devices_by_group(groupIds)
  8599. groupDict = Group.get_groups_by_group_ids(groupIds)
  8600. items = []
  8601. devNos = []
  8602. for devNo, devInfo in devicesDict.items():
  8603. if devInfo is None or not devInfo.lbs:
  8604. continue
  8605. if not groupDict.has_key(devInfo['groupId']):
  8606. continue
  8607. group = groupDict.get(devInfo['groupId'])
  8608. devInfo.update(
  8609. {
  8610. 'groupName':group['groupName'],
  8611. 'groupNumber':devInfo['groupNumber'],
  8612. 'address':group['address'],
  8613. 'process':statusDict.get(devInfo['status']),
  8614. 'type':devInfo.get('devType', {}).get('name', ''),
  8615. 'devTypeCode':devInfo.get('devType', {}).get('code', '')
  8616. }
  8617. )
  8618. devNos.append(devNo)
  8619. items.append(devInfo)
  8620. dev_ctrl_map = Device.get_many_dev_control_cache(devNos)
  8621. for item in items:
  8622. # 换电柜的端口显示可用电池数量
  8623. if item['devTypeCode'] in [Const.DEVICE_TYPE_CODE_CHARGING_AQKJ]:
  8624. dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {})
  8625. item["canUseBattery"] = dev_ctrl_info.get("canUseBattery", 0)
  8626. elif Const.DEVICE_TYPE_CODE_CHARGING_KYXN <= item['devTypeCode'] < Const.DEVICE_TYPE_CODE_WASHER_BASE:
  8627. dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {})
  8628. item['allPorts'] = dev_ctrl_info.get('allPorts', 10)
  8629. item['usedPorts'] = dev_ctrl_info.get('usedPorts', 0)
  8630. item['usePorts'] = dev_ctrl_info.get('usePorts', 10)
  8631. if 'power' in dev_ctrl_info:
  8632. item['power'] = dev_ctrl_info['power']
  8633. payload = {
  8634. 'total': len(items),
  8635. 'items': items
  8636. }
  8637. return JsonOkResponse(payload=payload)
  8638. @error_tolerate(nil=DefaultJsonErrorResponse)
  8639. @permission_required(ROLE.dealer)
  8640. def blackUser(request):
  8641. """
  8642. 汉航云充 需求 拉黑用户,用户登陆的时候做拉黑检测
  8643. 返现被拉黑的 直接跳转拉黑界面
  8644. :param request:
  8645. :return:
  8646. """
  8647. data = json.loads(request.body)
  8648. openId = data.get("openId", "")
  8649. reason = data.get("reason", "")
  8650. status = data.get("status", "black")
  8651. dealerId = str(request.user.bossId)
  8652. operId = str(request.user.id)
  8653. if status not in BlackListUsers.Status.choices():
  8654. return JsonErrorResponse(description=u"参数错误,无法拉黑用户")
  8655. groupIds = Group.get_group_ids_of_dealer(dealerId)
  8656. user = MyUser.objects.filter(openId=openId, groupId__in=groupIds)
  8657. if not user:
  8658. return JsonErrorResponse(description=u"未找到该用户!")
  8659. # 拉黑用户操作
  8660. if status == BlackListUsers.Status.BLACK:
  8661. BlackListUsers.add_black_user(
  8662. openId=openId,
  8663. dealerId=dealerId,
  8664. operator=operId,
  8665. reason=reason
  8666. )
  8667. elif status == BlackListUsers.Status.WHITE:
  8668. BlackListUsers.freed_black_user(
  8669. openId=openId,
  8670. dealerId=dealerId
  8671. )
  8672. else:
  8673. return JsonErrorResponse()
  8674. return JsonOkResponse()
  8675. @error_tolerate(nil=DefaultJsonErrorResponse)
  8676. @permission_required(ROLE.dealer)
  8677. def getCardPwd(request):
  8678. dealerId = str(request.user.bossId)
  8679. payload = json.loads(request.body)
  8680. logicalCodes = payload.get('logicalCode')
  8681. if len(logicalCodes) <= 0:
  8682. return JsonErrorResponse(description=u"参数错误")
  8683. dev = Device.get_dev_by_l(logicalCodes[0])
  8684. if dev.ownerId != dealerId:
  8685. return JsonErrorResponse(description=u"参数错误")
  8686. if request.user.role != ROLE.dealer:
  8687. return JsonErrorResponse(description=u"只能管理后台主账号才有此权限")
  8688. box = ActionDeviceBuilder.create_action_device(dev)
  8689. try:
  8690. result = box.get_card_pwd()
  8691. except ServiceException, e:
  8692. return JsonResponse(
  8693. {'result': 0, 'description': u'%s' % (e.result.get('description', '')), 'payload': {}})
  8694. return JsonOkResponse(payload={'card_pwd':result['card_pwd']})
  8695. @error_tolerate(nil=DefaultJsonErrorResponse)
  8696. @permission_required(ROLE.dealer)
  8697. def setCardPwd(request):
  8698. dealerId = str(request.user.bossId)
  8699. payload = json.loads(request.body)
  8700. cardPwd = payload.get('card_pwd')
  8701. logicalCodes = payload.get('logicalCode')
  8702. if len(logicalCodes) <= 0:
  8703. return JsonErrorResponse(description=u"参数错误")
  8704. dev = Device.get_dev_by_l(logicalCodes[0])
  8705. if dev.ownerId != dealerId:
  8706. return JsonErrorResponse(description=u"参数错误")
  8707. if request.user.role != ROLE.dealer:
  8708. return JsonErrorResponse(description=u"只能管理后台主账号才有此权限")
  8709. box = ActionDeviceBuilder.create_action_device(dev)
  8710. try:
  8711. box.set_card_pwd(cardPwd)
  8712. except ServiceException, e:
  8713. return JsonResponse(
  8714. {'result': 0, 'description': u'设置参数遇到错误:%s' % (e.result.get('description', '')), 'payload': {}})
  8715. return JsonOkResponse()
  8716. @error_tolerate(nil=DefaultJsonErrorResponse)
  8717. @permission_required(ROLE.dealer)
  8718. def setCardMode(request):
  8719. dealerId = str(request.user.bossId)
  8720. payload = json.loads(request.body)
  8721. logicalCodes = payload.get('logicalCode')
  8722. if len(logicalCodes) <= 0:
  8723. return JsonErrorResponse(description=u"参数错误")
  8724. dev = Device.get_dev_by_l(logicalCodes[0])
  8725. if dev.ownerId != dealerId:
  8726. return JsonErrorResponse(description=u"参数错误")
  8727. box = ActionDeviceBuilder.create_action_device(dev)
  8728. try:
  8729. box.set_card_mode(payload)
  8730. except ServiceException, e:
  8731. return JsonResponse(
  8732. {'result': 0, 'description': u'设置参数遇到错误:%s' % (e.result.get('description', '')), 'payload': {}})
  8733. return JsonOkResponse()
  8734. @error_tolerate(nil=DefaultJsonErrorResponse)
  8735. @permission_required(ROLE.dealer)
  8736. def getCardMode(request):
  8737. dealerId = str(request.user.bossId)
  8738. payload = json.loads(request.body)
  8739. logicalCodes = payload.get('logicalCode')
  8740. if len(logicalCodes) <= 0:
  8741. return JsonErrorResponse(description=u"参数错误")
  8742. dev = Device.get_dev_by_l(logicalCodes[0])
  8743. if dev.ownerId != dealerId:
  8744. return JsonErrorResponse(description=u"参数错误")
  8745. box = ActionDeviceBuilder.create_action_device(dev)
  8746. try:
  8747. result = box.get_card_mode()
  8748. except ServiceException, e:
  8749. return JsonResponse(
  8750. {'result': 0, 'description': u'%s' % (e.result.get('description', '')), 'payload': {}})
  8751. return JsonOkResponse(payload=result)
  8752. @error_tolerate(nil=DefaultJsonErrorResponse)
  8753. @permission_required(ROLE.dealer, ROLE.subaccount)
  8754. def getDealerOrderAddr(request):
  8755. dealer = Dealer.objects.get(id=request.user.bossId)
  8756. return JsonOkResponse(payload={'dataList':dealer.get_addr_list()})
  8757. @error_tolerate(nil=DefaultJsonErrorResponse)
  8758. @permission_required(ROLE.dealer, ROLE.subaccount)
  8759. def updateDealerOrderAddr(request):
  8760. payload = json.loads(request.body)
  8761. dealer = Dealer.objects.get(id=request.user.bossId)
  8762. name = payload['name']
  8763. tel = payload['tel']
  8764. addr = payload['addr']
  8765. default = payload['default']
  8766. if payload.has_key('id') and payload['id']:
  8767. addrs = dealer.get_addr_list()
  8768. newList = []
  8769. for va in addrs:
  8770. if va['id'] == payload['id']:
  8771. newList.append(DealerAddr(name=name, tel=tel, addr=addr, default=default, id=va['id']))
  8772. elif default:
  8773. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=False, id=va['id']))
  8774. else:
  8775. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=va['default'], id=va['id']))
  8776. dealer.expressAddrList = newList
  8777. dealer.save()
  8778. elif not default:
  8779. da = DealerAddr(name=name, tel=tel, addr=addr, default=default, id=str(uuid.uuid4()))
  8780. dealer.expressAddrList.append(da)
  8781. dealer.save()
  8782. else:
  8783. addrs = dealer.get_addr_list()
  8784. newList = [DealerAddr(name=name, tel=tel, addr=addr, default=default, id=str(uuid.uuid4()))]
  8785. for va in addrs:
  8786. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=False, id=va['id']))
  8787. dealer.expressAddrList = newList
  8788. dealer.save()
  8789. return JsonOkResponse()
  8790. @error_tolerate(nil=DefaultJsonErrorResponse)
  8791. @permission_required(ROLE.dealer, ROLE.subaccount)
  8792. def getPartInfo(request):
  8793. # payload = json.loads(request.body)
  8794. logicalCode = request.GET.get('logicalCode', None)
  8795. parts = Part.objects.filter(logicalCode=logicalCode, partName__in=[u'刷卡板', u'充电板', u'网络板'])
  8796. result = []
  8797. for part in parts:
  8798. result.append({'partName':part.partName, 'registerTime':part.dateTimeAdded.strftime(Const.DATETIME_FMT),
  8799. 'SN':part.partNo, 'expiredTime':part.expiredTime.strftime(Const.DATETIME_FMT),
  8800. 'id':str(part.id)
  8801. })
  8802. return JsonOkResponse(payload={'dataList':result})
  8803. @error_tolerate(nil=DefaultJsonErrorResponse)
  8804. @permission_required(ROLE.dealer, ROLE.subaccount)
  8805. def getExchangeOrder(request):
  8806. logicalCode = request.GET.get('logicalCode', None)
  8807. order = ExchangeOrder.objects.filter(logicalCode=logicalCode, dealerStatus__ne='finished').order_by('-dateTimeAdded').first()
  8808. if order is None:
  8809. return JsonOkResponse(payload={})
  8810. data = {}
  8811. objs = Part.objects.filter(id__in=order.parts)
  8812. 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]
  8813. data['statusInfo'] = order.make_status_info()
  8814. data['pics'] = order.pics
  8815. data['id'] = str(order.id)
  8816. data['dateTimeAdded'] = order.dateTimeAdded.strftime(Const.DATETIME_FMT)
  8817. data['factoryOrderNo'] = order.factoryOrderNo
  8818. data['dealerOrderNo'] = order.dealerOrderNo
  8819. data['factoryAddr'] = order.factoryAddr
  8820. data['dealerAddr'] = order.dealerAddr
  8821. data['dealerWords'] = order.dealerWords
  8822. data['factoryWords'] = order.factoryWords
  8823. data['dealerStatus'] = order.dealerStatus
  8824. data['factoryStatus'] = order.factoryStatus
  8825. return JsonOkResponse(payload=data)
  8826. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统开小差了,请重刷新页面,然后重试'))
  8827. @permission_required(ROLE.dealer, ROLE.subaccount)
  8828. def updateExchangeOrder(request):
  8829. payload = json.loads(request.body)
  8830. if payload.has_key('id'):
  8831. order = ExchangeOrder.objects.get(id=payload['id'])
  8832. if payload.has_key('pics'):
  8833. order.pics = payload.get('pics', '')
  8834. if payload.has_key('dealerOrderNo'):
  8835. order.dealerOrderNo = payload.get('dealerOrderNo', '')
  8836. order.dealerStatus = 'sended'
  8837. if payload.has_key('parts'):
  8838. if len(payload['parts']) == 0:
  8839. return JsonErrorResponse(description=u'必须选择一个组件哦')
  8840. order.parts = [ObjectId(_) for _ in payload['parts'] ]
  8841. if payload.has_key('dealerWords'):
  8842. order.dealerWords = payload.get('dealerWords', '')
  8843. if payload.has_key('dealerAddr'):
  8844. order.dealerAddr = payload.get('dealerAddr',)
  8845. order.save()
  8846. else:
  8847. if len(payload['parts']) == 0:
  8848. return JsonErrorResponse(description=u'必须选择一个组件哦')
  8849. dealerId = request.user.bossId
  8850. dealer = Dealer.objects.get(id=dealerId)
  8851. agent = Agent.objects.get(id=dealer.agentId)
  8852. factoryId = agent.managerId
  8853. order = ExchangeOrder(
  8854. factoryId=ObjectId(factoryId),
  8855. agentId=ObjectId(agent.id),
  8856. ownerId=ObjectId(dealerId),
  8857. logicalCode=payload.get('logicalCode'),
  8858. pics=payload.get('pics', []),
  8859. dealerOrderNo=payload.get('dealerOrderNo', ''),
  8860. parts=[ ObjectId(_) for _ in payload['parts'] ],
  8861. dealerWords=payload.get('dealerWords', ''),
  8862. dealerStatus='created',
  8863. dealerAddr=payload['dealerAddr'],
  8864. factoryAddr=Manager.get_factory_addr(factoryId),
  8865. )
  8866. order.save()
  8867. return JsonOkResponse()
  8868. @error_tolerate(nil=DefaultJsonErrorResponse)
  8869. @permission_required(ROLE.dealer, ROLE.subaccount)
  8870. def cancelOrder(request):
  8871. payload = json.loads(request.body)
  8872. orderNo = payload['id']
  8873. order = ExchangeOrder.objects.get(id=orderNo)
  8874. if order.factoryStatus in ['sended', 'closed']:
  8875. return JsonOkResponse(description=u'售后中心已经处理,当前不允许取消,请联系技术支持解决')
  8876. ExchangeOrder.objects.get(id=orderNo).delete()
  8877. return JsonOkResponse()
  8878. @error_tolerate(nil=DefaultJsonErrorResponse)
  8879. @permission_required(ROLE.dealer, ROLE.subaccount)
  8880. def finishedOrder(request):
  8881. payload = json.loads(request.body)
  8882. orderNo = payload['id']
  8883. order = ExchangeOrder.objects.get(id=orderNo)
  8884. if order.factoryStatus in ['sended', 'closed']:
  8885. return JsonOkResponse(description=u'售后中心已经处理,当前不允许取消,请联系技术支持解决')
  8886. order.dealerStatus = 'finished'
  8887. order.save()
  8888. return JsonOkResponse()
  8889. @error_tolerate(nil=DefaultJsonErrorResponse)
  8890. @permission_required(ROLE.dealer, ROLE.subaccount)
  8891. def deleteAddress(request):
  8892. payload = json.loads(request.body)
  8893. dealer = Dealer.objects.get(id=request.user.bossId)
  8894. addrs = dealer.get_addr_list()
  8895. newList = []
  8896. deleteVa = None
  8897. for va in addrs:
  8898. if va['id'] == payload['id']:
  8899. deleteVa = va
  8900. continue
  8901. else:
  8902. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=va['default'], id=va['id']))
  8903. if deleteVa and deleteVa['default'] and len(newList) > 0:
  8904. newList[0].default = True
  8905. dealer.expressAddrList = newList
  8906. dealer.save()
  8907. return JsonOkResponse()
  8908. @error_tolerate(nil=DefaultJsonErrorResponse)
  8909. @permission_required(ROLE.dealer, ROLE.subaccount)
  8910. def getDevicePort(request):
  8911. # type: (WSGIRequest)->JsonResponse
  8912. def cmp_by_port(x, y):
  8913. if str(x['index']).isdigit() and str(y['index']).isdigit():
  8914. if int(x['index']) < int(y['index']):
  8915. return -1
  8916. elif int(x['index']) > int(y['index']):
  8917. return 1
  8918. return 0
  8919. else:
  8920. if x['index'] < y['index']:
  8921. return -1
  8922. elif x['index'] > y['index']:
  8923. return 1
  8924. return 0
  8925. def charge_pay_coin_unit(p, u):
  8926. """
  8927. 给端口信息中的付费添加上单位
  8928. :param p:
  8929. :param u:
  8930. :return:
  8931. """
  8932. _coins = p.get("coins")
  8933. if not _coins:
  8934. return
  8935. p.update({"coins": "{}{}".format(_coins, u)})
  8936. currentDealer = request.user
  8937. dev = Device.get_dev_by_logicalCode(request.GET.get('logicalCode')) # type: DeviceDict
  8938. group = dev.group # type: GroupDict
  8939. if str(currentDealer.id) == group['ownerId']:
  8940. isManager = True
  8941. else:
  8942. isManager = False
  8943. smartBox = dev.deviceAdapter
  8944. if hasattr(smartBox, 'dealer_get_device_port'):
  8945. portList = getattr(smartBox, 'dealer_get_device_port')()
  8946. return JsonResponse({"result": 1, "description": "", "payload": {"portList": portList}})
  8947. try:
  8948. # 先从设备上取信息,然后从缓存中取信息
  8949. portDict = smartBox.dealer_get_port_status()
  8950. smartBox.async_update_portinfo_from_dev()
  8951. except ServiceException as e:
  8952. logger.exception(e)
  8953. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': None})
  8954. except Exception as e:
  8955. logger.exception(e)
  8956. return JsonResponse({"result": 0, "description": u"从设备上获取端口信息失败,请您重试", "payload": {}})
  8957. portList = []
  8958. unit = smartBox.show_pay_unit
  8959. statsMap = {
  8960. str(Const.DEV_WORK_STATUS_IDLE): 'idle',
  8961. str(Const.DEV_WORK_STATUS_WORKING): 'busy',
  8962. str(Const.DEV_WORK_STATUS_FAULT): 'fault',
  8963. str(Const.DEV_WORK_STATUS_FORBIDDEN): 'ban',
  8964. str(Const.DEV_WORK_STATUS_CONNECTED): 'connected',
  8965. str(Const.DEV_WORK_STATUS_FINISHED): 'finished'
  8966. }
  8967. busyPortList = []
  8968. for port, valueDict in portDict.items():
  8969. vStatus = valueDict.get('status', None)
  8970. if vStatus == Const.DEV_WORK_STATUS_WORKING:
  8971. busyPortList.append(port)
  8972. else:
  8973. portList.append({'index': str(port), 'status': statsMap.get(str(vStatus), "idle")})
  8974. busyPortInfoDict = smartBox.get_many_port_info(busyPortList)
  8975. if busyPortInfoDict:
  8976. for _info in busyPortInfoDict.values():
  8977. if 'status' in _info and _info['status'] == Const.DEV_WORK_STATUS_WORKING:
  8978. _info.update({'status': statsMap[str(_info['status'])]})
  8979. if 'needTime' in _info and str(_info['needTime']).isdigit():
  8980. _info.update({'needTime': u'%s分钟' % _info['needTime']})
  8981. else:
  8982. _info = {'status': 'idle', 'index': str(_info['index'])}
  8983. portList.append(_info)
  8984. else:
  8985. ctrInfo = Device.get_dev_control_cache(dev.devNo)
  8986. for port, valueDict in portDict.items():
  8987. vStatus = valueDict.get('status', None)
  8988. if vStatus == Const.DEV_WORK_STATUS_WORKING:
  8989. portDetail = smartBox.get_port_using_detail(port, ctrInfo)
  8990. portDetail.update({"index": str(port), "status": 'busy'})
  8991. portList.append(portDetail)
  8992. portList.sort(key=lambda _port: int(_port['index']) if isinstance(_port['index'], str) and _port["index"].isdigit() else _port['index'])
  8993. map(charge_pay_coin_unit, portList, [unit for x in xrange(len(portList))])
  8994. if dev.support_power_graph and (
  8995. 'showPG_in_port_detail' in dev.owner.features or dev.driverCode in [Const.DEVICE_TYPE_CODE_WEIFULE_ANJIAN]):
  8996. for item in portList:
  8997. item['showPG'] = True
  8998. portList.sort(cmp=cmp_by_port)
  8999. return JsonOkResponse(payload={"isManager": isManager, "portList": portList})
  9000. @error_tolerate(nil=DefaultJsonErrorResponse)
  9001. @permission_required(ROLE.dealer, ROLE.subaccount)
  9002. def getTempPackages(request):
  9003. # type: (WSGIRequest)->JsonResponse
  9004. lc = request.GET.get('logicalCode', None)
  9005. devNo = Device.get_devNo_by_logicalCode(lc)
  9006. if devNo is None:
  9007. return JsonErrorResponse(description=u"缺少参数devNo")
  9008. dev = Device.get_dev(devNo)
  9009. if dev is None:
  9010. return JsonErrorResponse(description=u"找不到设备")
  9011. if "displayTempSwitchs" in dev["otherConf"]:
  9012. displaySwitchs = dev["otherConf"].get('displayTempSwitchs')
  9013. else:
  9014. displaySwitchs = {'displayCoinsSwitch': True,
  9015. 'displayTimeSwitch': True,
  9016. 'displayPriceSwitch': True,
  9017. "setPulseAble": False,
  9018. "setBasePriceAble": False}
  9019. maxCoins = dev.get('maxCoins', 4)
  9020. group = dev.group # type: GroupDict
  9021. if group is None:
  9022. return JsonErrorResponse(description=u'找不到设备')
  9023. if group.ownerId != str(request.user.bossId):
  9024. return JsonErrorResponse(description=u'找不到设备')
  9025. devData = {
  9026. 'id': devNo,
  9027. 'maxCoins': maxCoins,
  9028. 'isManager': True,
  9029. 'groupName': group['groupName'],
  9030. 'groupNumber': dev['groupNumber'],
  9031. 'devNo': devNo,
  9032. 'type': dev['devType']['name'],
  9033. 'typeCode': dev['devType']['code']
  9034. }
  9035. if dev["devType"]["code"] in support_policy_weifule:
  9036. try:
  9037. if dev.deviceAdapter.support_device_package:
  9038. payload = dev.deviceAdapter.dealer_show_package(isTemp=True)
  9039. payload.update({"devData": devData})
  9040. return JsonOkResponse(payload=payload)
  9041. except ServiceException as e:
  9042. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {'devData': devData}})
  9043. if dev["devType"]["code"] in support_policy_device:
  9044. try:
  9045. if dev.deviceAdapter.support_device_package:
  9046. payload = dev.deviceAdapter.dealer_show_package(isTemp=True)
  9047. payload.update({"devData": devData})
  9048. return JsonOkResponse(payload=payload)
  9049. except ServiceException as e:
  9050. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {'devData': devData}})
  9051. 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, ]:
  9052. if dev.deviceAdapter.support_device_package:
  9053. payload = dev.deviceAdapter.dealer_show_package(isTemp=True)
  9054. payload.update({"devData": devData})
  9055. return JsonOkResponse(payload=payload)
  9056. smartBox = ActionDeviceBuilder.create_action_device(dev)
  9057. try:
  9058. portDict = smartBox.dealer_get_port_status()
  9059. if portDict:
  9060. chargeIndex = {}
  9061. for index, info in portDict.items():
  9062. if info['status'] == Const.DEV_WORK_STATUS_IDLE:
  9063. chargeIndex[index] = 'idle'
  9064. elif info['status'] == Const.DEV_WORK_STATUS_WORKING:
  9065. chargeIndex[index] = 'busy'
  9066. elif info['status'] == Const.DEV_WORK_STATUS_FAULT:
  9067. chargeIndex[index] = 'fault'
  9068. elif info['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
  9069. chargeIndex[index] = 'ban'
  9070. devData.update({'chargeIndex': chargeIndex})
  9071. except ServiceException, e:
  9072. return JsonErrorResponse(description=e.result.get('description'))
  9073. except Exception as e:
  9074. logger.exception(e)
  9075. return JsonErrorResponse(description=u'未知错误')
  9076. tempWashConfig = dev['tempWashConfig'] if dev.get('tempWashConfig', {}) != {} else dev['washConfig']
  9077. ruleList = []
  9078. for packageId, rule in tempWashConfig.items():
  9079. item = {
  9080. 'id': packageId,
  9081. 'name': rule['name'],
  9082. 'coins': rule['coins'],
  9083. 'price': rule.get('price', rule['coins']),
  9084. 'time': rule.get('time', 20),
  9085. 'description': rule.get('description', ''),
  9086. 'imgList': rule.get('imgList', []),
  9087. 'unit': rule.get('unit', u'分钟')
  9088. }
  9089. if rule.get('pulse'):
  9090. item.update({
  9091. 'pulse': rule.get('pulse'),
  9092. })
  9093. if rule.get('basePrice'):
  9094. item.update({
  9095. 'basePrice': rule.get('basePrice'),
  9096. })
  9097. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  9098. item.update({
  9099. 'billingMethod': rule['billingMethod'],
  9100. })
  9101. if 'sn' in rule:
  9102. item['sn'] = rule['sn']
  9103. ruleList.append(item)
  9104. ruleList = sorted(ruleList, key=lambda x: (x.get('sn'), x.get('id')))
  9105. return JsonOkResponse(payload={'devData': devData, 'ruleList': ruleList, 'displaySwitchs':displaySwitchs})
  9106. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存套餐失败'))
  9107. @permission_required(ROLE.dealer, ROLE.subaccount)
  9108. def saveTempPackages(request):
  9109. """
  9110. 保存套餐
  9111. :param request:
  9112. :return:
  9113. """
  9114. curr_user = request.user # type: Union[Dealer, SubAccount]
  9115. if not curr_user.normal:
  9116. return JsonErrorResponse(description=u'账号异常,不能进行该操作')
  9117. status, msg = ensure_all_fields_are_not_empty(
  9118. {k: v for k, v in request.POST.items() if k not in ('ruleId',)})
  9119. if not status:
  9120. return JsonErrorResponse(description=msg)
  9121. paras = json.loads(request.body) if request.body else {}
  9122. if not paras:
  9123. return JsonErrorResponse(description=u'提交数据为空')
  9124. if paras['logicalCode'].__class__.__name__ == 'list':
  9125. devNoList = [Device.get_devNo_by_logicalCode(lc) for lc in paras['logicalCode']]
  9126. else:
  9127. devNoList = [Device.get_devNo_by_logicalCode(paras['logicalCode'])]
  9128. devDict = Device.get_dev_by_nos(devNoList)
  9129. if not devDict:
  9130. return JsonErrorResponse(description=u'找不到设备')
  9131. typeCode = devDict.values()[0]['devType']['code']
  9132. if typeCode in support_policy_weifule:
  9133. dev = devDict.values()[0]
  9134. if dev.deviceAdapter.support_device_package:
  9135. try:
  9136. dev.deviceAdapter.format_device_package(isTemp=True, **paras)
  9137. except ServiceException as e:
  9138. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  9139. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  9140. elif typeCode in support_policy_device:
  9141. dev = devDict.values()[0]
  9142. if dev.deviceAdapter.support_device_package:
  9143. try:
  9144. dev.deviceAdapter.format_device_package(isTemp=True, **paras)
  9145. except ServiceException as e:
  9146. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  9147. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  9148. 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,]:
  9149. dev = devDict.values()[0]
  9150. if dev.deviceAdapter.support_device_package:
  9151. washConfig, displayTempSwitchs = dev.deviceAdapter.format_device_package(isTemp=True, **paras)
  9152. else:
  9153. # 解析washConfig,如果需要下发设备,解析出来setConfig
  9154. serviceList = paras['serviceData']
  9155. # 调整sn顺序
  9156. for item in serviceList:
  9157. item["sn"] = serviceList.index(item)
  9158. displayTempSwitchs = paras.get('displaySwitchs', {'displayCoinsSwitch': True,
  9159. 'displayTimeSwitch': True,
  9160. 'displayPriceSwitch': True,
  9161. 'setPulseAble': False,
  9162. 'setBasePriceAble': False})
  9163. washConfig, setConfig = {}, {}
  9164. existIds = []
  9165. for rule in serviceList:
  9166. if 'id' in rule:
  9167. existIds.append(rule['id'])
  9168. for rule in serviceList:
  9169. if rule.has_key('coins') and rule.has_key('price'):
  9170. if not (is_number(rule['coins']) and is_number(rule['price']) and is_number(
  9171. rule.get('time', 0))):
  9172. return JsonErrorResponse(description=u'金币数目或者时间或者价格必须是数字')
  9173. else:
  9174. rule['coins'], rule['price'] = 0, 0 # 对于那种先不需要付费的,这个就直接是0
  9175. if len(rule['name']) > 20:
  9176. return JsonErrorResponse(description=u'套餐名字只能取1-20位')
  9177. if 'id' in rule:
  9178. ruleId = rule['id']
  9179. else:
  9180. ruleId = list(set(range(1, 10)) - set([int(ruleId) for ruleId in washConfig.keys()]) - set(existIds))[0]
  9181. washConfig[str(ruleId)] = {
  9182. 'name': rule['name'],
  9183. 'coins': float(rule['coins']),
  9184. 'price': float(rule['price']),
  9185. 'time': float(rule.get('time', 0)),
  9186. 'description': rule.get('description', ''),
  9187. 'imgList': rule.get('imgList', []),
  9188. 'unit': rule.get('unit', u'分钟')
  9189. }
  9190. if rule.get('pulse'):
  9191. washConfig[str(ruleId)].update({
  9192. 'pulse': rule.get('pulse'),
  9193. })
  9194. if rule.get('basePrice'):
  9195. washConfig[str(ruleId)].update({
  9196. 'basePrice': rule.get('basePrice'),
  9197. })
  9198. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  9199. washConfig[str(ruleId)].update({
  9200. 'billingMethod': rule['billingMethod'],
  9201. })
  9202. # 如果设备直接可以下发套餐信息到设备,直接到设备上修改。比如串口洗衣机、串口的充电设备等
  9203. for devNo, dev in devDict.items():
  9204. try:
  9205. dev['tempWashConfig'] = washConfig
  9206. otherConf = dev.get('otherConf', {})
  9207. otherConf['displayTempSwitchs'] = displayTempSwitchs
  9208. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'tempWashConfig': dev['tempWashConfig'], 'otherConf':otherConf}})
  9209. Device.invalid_device_cache(devNo)
  9210. except ServiceException, e:
  9211. logger.exception('update device washconfig error=%s,devNo=%s,washConfig=%s'
  9212. % (e, devNo, dev['washConfig']))
  9213. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  9214. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  9215. @error_tolerate(logger=logger, nil=JsonOkResponse(description=u"派币失败"))
  9216. @permission_required(ROLE.dealer, ROLE.subaccount)
  9217. def sendCoinsForCard(request):
  9218. """
  9219. 经销商 给卡派币 修改模式改为订单模式
  9220. 卡被经销商录入的时候 由于不知道是ID卡还是IC卡 因此无法对卡进行派币
  9221. 之前 卡派币 ---> 余额增加
  9222. 此次修改后, 卡派币 ---> 创建一条卡的充值订单 ---> 用户靠卡 ---> 走相应的同步余额的功能(ID卡直接价钱,IC有区别) ---> 余额改变
  9223. :param request:
  9224. :return:
  9225. """
  9226. payload = json.loads(request.body)
  9227. cardId = payload.get("cardId")
  9228. remark = payload.get("remark", u"经销商{}赠送".format(request.user.username))
  9229. coins = float(payload.get("coins", 0))
  9230. card = Card.objects(id=cardId).first()
  9231. if card is None:
  9232. return JsonErrorResponse(description=u'没有找到卡')
  9233. group = Group.get_group(card.groupId) # type: GroupDict
  9234. # 创建卡充值订单表 类型为派币
  9235. # 卡的openId 一定会存在 用户侧绑定会有 经销商录入会有 默认值
  9236. payload = {
  9237. 'orderNo': str(uuid.uuid1()),
  9238. 'openId': card.openId,
  9239. 'money': RMB(0),
  9240. 'coins': VirtualCoin(coins),
  9241. 'description': remark,
  9242. 'groupId': card.groupId,
  9243. 'groupName': group.groupName,
  9244. 'ownerId': group.ownerId,
  9245. 'operator': request.user.nickname,
  9246. 'result': 'success',
  9247. 'via': 'sendcoin',
  9248. 'attachParas': {
  9249. 'cardId': card.id,
  9250. 'cardNo': card.cardNo,
  9251. }
  9252. }
  9253. record = RechargeRecord(**payload).save()
  9254. order = CardRechargeOrder.new_one(
  9255. openId=card.openId,
  9256. cardId=cardId,
  9257. cardNo=card.cardNo,
  9258. money=RMB(0),
  9259. coins=VirtualCoin(coins),
  9260. group=group,
  9261. rechargeId=record.id,
  9262. rechargeType=u"sendCoin"
  9263. )
  9264. # ID 卡直接充值掉
  9265. if card.cardType == "ID":
  9266. balance = card.balance + order.coins
  9267. preBalance = card.balance
  9268. order.update_after_recharge_id_card(None, balance, preBalance)
  9269. CardRechargeRecord.add_record(
  9270. card=card,
  9271. group=Group.get_group(order.groupId),
  9272. order=order,
  9273. )
  9274. # 刷新卡里面的余额
  9275. card.balance = balance
  9276. card.lastMaxBalance = balance
  9277. card.showBalance = balance # 微付乐一体板要用
  9278. card.save()
  9279. # 创建上分表
  9280. newRcd = UpCardScoreRecord(
  9281. cardNo=card.cardNo,
  9282. cardId=cardId,
  9283. ownerId=str(request.user.bossId),
  9284. score=coins,
  9285. address=group.groupName,
  9286. remark=remark
  9287. )
  9288. newRcd.save()
  9289. return JsonResponse({"result": 1, "description": u"派币成功", 'payload': {}})
  9290. @error_tolerate(nil=DefaultJsonErrorResponse)
  9291. @permission_required(ROLE.dealer, ROLE.subaccount)
  9292. def querySendCoinsRcd(request):
  9293. cardId = request.GET.get('cardId', None)
  9294. if cardId:
  9295. objs = UpCardScoreRecord.objects.filter(cardId=cardId).order_by('-dateTimeAdded')
  9296. else:
  9297. objs = UpCardScoreRecord.objects.filter(ownerId=str(request.user.bossId)).order_by('-dateTimeAdded')
  9298. pageIndex = int(request.GET.get('pageIndex', 1))
  9299. pageSize = int(request.GET.get('pageSize', 10))
  9300. total = objs.count()
  9301. dataList = []
  9302. for obj in objs.paginate(pageIndex=pageIndex, pageSize=pageSize):
  9303. dataList.append({
  9304. 'dateTimeAdded':obj.dateTimeAdded.strftime(Const.DATETIME_FMT),
  9305. 'score':obj.score,
  9306. 'cardNo':obj.cardNo,
  9307. 'cardId':obj.cardId,
  9308. 'remark':obj.remark,
  9309. })
  9310. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  9311. def setSelfRechargeCardPrice(request):
  9312. payload = json.loads(request.body)
  9313. rechargeCardPrice = payload['rechargeCardPrice']
  9314. dev = Device.get_dev_by_logicalCode(payload['logicalCode'])
  9315. group = Group.get_group(dev['groupId'])
  9316. smartbox = ActionDeviceBuilder.create_action_device(dev)
  9317. smartbox.remote_charge_card(int(rechargeCardPrice))
  9318. # 蓝光卡记录, 卡不用添加在后台, 所以没有卡id
  9319. CardRechargeRecord.add_self_card_record('languang_card_id', group, RMB(rechargeCardPrice), dev)
  9320. return JsonOkResponse()
  9321. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取自动提现信息失败"))
  9322. @permission_required(ROLE.dealer)
  9323. def getAutoWithdrawConfig(request):
  9324. dealer = request.user # type: Dealer
  9325. payload = {
  9326. "phone": dealer.username,
  9327. "autoWithdrawSwitch": dealer.auto_withdraw_switch,
  9328. "autoWithdrawBankFee": dealer.auto_withdraw_bank_fee,
  9329. "withdrawFeeRatio": dealer.withdrawFeeRatio,
  9330. "autoWithdrawType": dealer.auto_withdraw_type,
  9331. "weekDay": dealer.auto_withdraw_strategy.get('value'),
  9332. "autoWithdrawMin": dealer.auto_withdraw_min
  9333. }
  9334. if dealer.monitorPhone:
  9335. payload['phone'] = dealer.monitorPhone
  9336. cards = []
  9337. for bankCard in WithdrawBankCard.objects(ownerId = str(dealer.id), role = dealer.role):
  9338. cards.append({
  9339. 'accountCode': bankCard.accountCode,
  9340. 'accountName': bankCard.accountName,
  9341. 'bankName': bankCard.bankName
  9342. })
  9343. payload.update({
  9344. 'cards': cards
  9345. })
  9346. return JsonOkResponse(payload = payload)
  9347. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"保存自动提现信息失败"))
  9348. @permission_required(ROLE.dealer)
  9349. def saveAutoWithdrawConfig(request):
  9350. dealer = request.user
  9351. payload = json.loads(request.body)
  9352. autoWithdrawSwitch = payload.get("autoWithdrawSwitch")
  9353. autoWithdrawMin = RMB(payload.get("autoWithdrawMin"))
  9354. if autoWithdrawMin < RMB(settings.WITHDRAW_MINIMUM):
  9355. return JsonErrorResponse(description=u"最小提现金额不能少于提现接口设置最小转账金额({}元)".format(settings.WITHDRAW_MINIMUM))
  9356. autoWithdrawType = payload.get("autoWithdrawType")
  9357. weekDay = int(payload.get("weekDay"))
  9358. smsCode = payload.get("code", "")
  9359. status, msg = dealerWithdrawSMSProvider.verify(dealer.username, smsCode)
  9360. if not status:
  9361. return JsonErrorResponse(msg)
  9362. # 如果自动提现到微信 需要检测提现微信是否绑定
  9363. if autoWithdrawType == WITHDRAW_PAY_TYPE.WECHAT:
  9364. auth_bridge = get_wechat_auth_bridge(source=dealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9365. key = auth_bridge.bound_openid_key
  9366. if not dealer.isAutoWithdrawOpenIdBound(key):
  9367. return JsonResponse({"result": ErrorCode.AUTO_WITHDRAW_WECHAT_NOT_BIND, "description": ""})
  9368. # 银行卡的信息不保存 每次提现的时候直接去取 防止银行卡解绑造成信息不同步
  9369. dealer.withdrawOptions.update({
  9370. 'autoWithdrawSwitch': autoWithdrawSwitch,
  9371. 'autoWithdrawType': autoWithdrawType,
  9372. 'autoWithdrawStrategy': {'type': 'asWeek', 'value': weekDay},
  9373. 'autoWithdrawMin': autoWithdrawMin.mongo_amount,
  9374. })
  9375. if 'bankAccount' in payload:
  9376. dealer.withdrawOptions.update({
  9377. 'bankAccount': payload['bankAccount']
  9378. })
  9379. dealer.save()
  9380. return JsonOkResponse(description=u'自动提现配置成功')
  9381. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取绑定信息失败"))
  9382. @permission_required(ROLE.dealer)
  9383. def getBoundWalletWeiXinId(request):
  9384. """
  9385. 获取经销商绑定后台 提现的 ID
  9386. :param request:
  9387. :return:
  9388. """
  9389. dealer = request.user
  9390. auth_bridge = get_wechat_auth_bridge(source=dealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9391. key = auth_bridge.bound_openid_key
  9392. payOpenIdInfo = dealer.get_bound_pay_info(key)
  9393. return JsonResponse(
  9394. {
  9395. "result": 1,
  9396. "description": "",
  9397. 'payload': {
  9398. "bound": True if payOpenIdInfo.get("openId") else False,
  9399. "avatar": payOpenIdInfo.get("avatar"),
  9400. "sex": payOpenIdInfo.get("sex"),
  9401. "nickname": payOpenIdInfo.get("nickname")
  9402. }
  9403. })
  9404. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取验证码失败"))
  9405. @permission_required(ROLE.dealer)
  9406. def getBindWalletWechatSMSCode(request):
  9407. try:
  9408. phoneNumber = request.user.username
  9409. agent = Agent.get_agent(request.user.agentId)
  9410. productName = agent['productName']
  9411. if not phoneNumber:
  9412. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  9413. status, msg = dealerBindWalletWechatSMSProvider.get(phoneNumber=phoneNumber,
  9414. productName=productName,
  9415. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  9416. if not status:
  9417. return JsonResponse({'result': 0, 'description': msg})
  9418. else:
  9419. return JsonResponse({'result': 1, 'description': ''})
  9420. except Exception, e:
  9421. logger.exception('unable to get %s' % e)
  9422. return JsonResponse({'result': 0, 'description': ''})
  9423. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"自动绑定失败"))
  9424. @permission_required(ROLE.dealer)
  9425. def verifyNewWalletWechatBinding(request):
  9426. currentDealer = request.user # type: cast(Dealer)
  9427. code = request.POST.get('code')
  9428. if not code:
  9429. return JsonErrorResponse(description=u'请输入6位验证码')
  9430. status, msg = dealerBindWalletWechatSMSProvider.verify(phoneNumber=request.user.username, smsCode=code)
  9431. if not status:
  9432. return JsonErrorResponse(description=msg)
  9433. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9434. return JsonResponse(
  9435. {
  9436. 'result': 1,
  9437. 'description': None,
  9438. 'payload': {
  9439. 'redirect_uri': auth_bridge.generate_auth_url_user_scope(
  9440. redirect_uri=DEALER_BIND_WALLET_WECHAT_URL)
  9441. }
  9442. })
  9443. @permission_required(ROLE.dealer)
  9444. def verifyNewWalletWechatBindingCallback(request):
  9445. auth_code = request.GET.get('code')
  9446. if not auth_code:
  9447. return JsonErrorResponse(description=u'未收到code,请刷新重试')
  9448. currentDealer = request.user
  9449. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9450. user_info = auth_bridge.get_user_info(auth_code=auth_code)
  9451. user_info_payload = {
  9452. 'avatar': user_info['avatar'],
  9453. 'sex': user_info['sex'],
  9454. 'nickname': user_info['nickname'],
  9455. 'openId': user_info['openId']
  9456. }
  9457. logger.debug('dealer(id=%s) is binding wechat for messaging, bridge=%s' % (str(request.user.bossId), auth_bridge))
  9458. key = auth_bridge.bound_openid_key
  9459. currentDealer.set_bound_pay_info(key, **user_info_payload)
  9460. currentDealer.save()
  9461. return DealerBindIdResponseRedirect(result='ok')
  9462. @permission_required(ROLE.dealer)
  9463. def selfRechargeCardRecords(request):
  9464. # type: (WSGIRequest)->JsonResponse
  9465. """
  9466. 蓝光国际手动充卡记录查询
  9467. :param request:
  9468. :return:
  9469. """
  9470. ownerId = str(request.user.bossId)
  9471. logicalCode = request.GET['logicalCode']
  9472. pageIndex = int(request.GET.get('pageIndex', 1))
  9473. pageSize = int(request.GET.get('pageSize', 10))
  9474. objs = CardRechargeRecord.objects.filter(ownerId=ownerId, logicalCode=logicalCode, cardId='languang_card_id').order_by('-dateTimeAdded')
  9475. rcdList = []
  9476. total = 0
  9477. for obj in objs:
  9478. total += 1
  9479. rcdList.append({
  9480. 'price': int(float(str(obj.money))),
  9481. 'dateTimeAdded': obj.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  9482. })
  9483. return JsonResponse({
  9484. 'result': 1,
  9485. 'description': None,
  9486. 'payload': {
  9487. 'total': total,
  9488. 'dataList': rcdList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  9489. }
  9490. })
  9491. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"同步设备电池信息失败"))
  9492. @permission_required(ROLE.dealer, ROLE.subaccount)
  9493. def asyncBatterySnByDevice(request):
  9494. """
  9495. 从设备侧同步电池编号
  9496. :param request:
  9497. :return:
  9498. """
  9499. payload = json.loads(request.body)
  9500. logicalCode = payload.get("logicalCode")
  9501. dealerId = str(request.user.bossId)
  9502. dev = Device.get_dev_by_logicalCode(logicalCode=logicalCode)
  9503. if not dev:
  9504. return JsonErrorResponse(description=u"未找到设备,请您确认设备逻辑码正确")
  9505. if dev.ownerId != dealerId:
  9506. return JsonErrorResponse(description=u"未找到设备,请您确认设备逻辑码正确")
  9507. box = ActionDeviceBuilder.create_action_device(dev)
  9508. if not hasattr(box, "_query_all_battery_imei"):
  9509. return JsonErrorResponse(description=u"该设备不支持导入电池编号,请确认设备逻辑码正确")
  9510. try:
  9511. batteryInfo = box._query_all_battery_imei()
  9512. except ServiceException:
  9513. return JsonErrorResponse(description=u"读取电池信息失败,请重新试试")
  9514. addBatteryLis = list()
  9515. for port, batterySn in batteryInfo.items():
  9516. try:
  9517. battery = Battery.add_from_device(
  9518. batterySn=batterySn,
  9519. devNo=dev.devNo,
  9520. port=port,
  9521. dealerId=dealerId
  9522. )
  9523. except Exception as e:
  9524. logger.exception(e)
  9525. continue
  9526. if not battery:
  9527. continue
  9528. addBatteryLis.append(batterySn)
  9529. message = u"操作成功,此次录入的电池编号为: \n{}".format("\n".join(addBatteryLis))
  9530. return JsonOkResponse(description=message)
  9531. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"录入电池信息失败"))
  9532. @permission_required(ROLE.dealer, ROLE.subaccount)
  9533. def asyncBatterySnByEnter(request):
  9534. """
  9535. 经销商手动录入电池编号
  9536. :param request:
  9537. :return:
  9538. """
  9539. payload = json.loads(request.body)
  9540. batterySn = payload.get("batterySn")
  9541. dealerId = str(request.user.bossId)
  9542. if not Battery.is_battery_sn_format(batterySn):
  9543. return JsonErrorResponse(u"请输入正确的电池编号(15位数字)")
  9544. battery = Battery.add_from_enter(batterySn=batterySn, dealerId=dealerId)
  9545. if not battery:
  9546. return JsonErrorResponse(description=u"请勿重复录入电池编号")
  9547. return JsonOkResponse(description=u"录入成功\n{}".format(batterySn))
  9548. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取电池列表信息失败"))
  9549. @permission_required(ROLE.dealer, ROLE.subaccount)
  9550. def batteryList(request):
  9551. """
  9552. 获取电池列表
  9553. :param request:
  9554. :return:
  9555. """
  9556. dealerId = str(request.user.bossId)
  9557. pageSize = int(request.GET.get("pageSize", 10))
  9558. pageIndex = int(request.GET.get("pageIndex", 1))
  9559. searchKey = request.GET.get("searchKey", "")
  9560. logicalCode = request.GET.get("logicalCode")
  9561. data = list()
  9562. filters = {
  9563. "dealerId": dealerId
  9564. }
  9565. if logicalCode:
  9566. dev = Device.get_dev_by_l(logicalCode)
  9567. if not dev or dev.ownerId != dealerId:
  9568. return JsonOkResponse(payload={"total": 0, "data": data})
  9569. filters.update({"devNo": dev.devNo})
  9570. query = Battery.objects.filter(**filters).search(searchKey)
  9571. total = query.count()
  9572. batteries = query.skip((pageIndex - 1) * pageSize).limit(pageSize)
  9573. for battery in batteries:
  9574. data.append(battery.to_dict())
  9575. return JsonOkResponse(
  9576. payload={
  9577. "total": total,
  9578. "dataList": data
  9579. }
  9580. )
  9581. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"删除电池失败"))
  9582. @permission_required(ROLE.dealer, ROLE.subaccount)
  9583. def deleteBattery(request):
  9584. """
  9585. 删除电池
  9586. :param request:
  9587. :return:
  9588. """
  9589. dealerId = str(request.user.bossId)
  9590. payload = json.loads(request.body)
  9591. batterySn = payload.get("ids")
  9592. if len(batterySn) > 1:
  9593. return JsonErrorResponse(description=u"电池数量超限")
  9594. result = Battery.delete_one(dealerId, batterySn[0])
  9595. if not result:
  9596. return JsonErrorResponse(description=u"删除电池信息失败")
  9597. return JsonErrorResponse(description=u"电池编号<{}>删除成功".format(batterySn[0]))
  9598. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取电池定位失败"))
  9599. @permission_required(ROLE.dealer, ROLE.subaccount)
  9600. def batteryPosition(request):
  9601. """
  9602. 经销商处查看电池的定位
  9603. :param request:
  9604. :return:
  9605. """
  9606. dealerId = str(request.user.bossId)
  9607. batterySn = request.GET.get("batterySn", "")
  9608. battery = Battery.get_one(dealerId=dealerId, batterySn=batterySn)
  9609. if not battery:
  9610. return JsonErrorResponse(description=u"未找到电池,请重新试试")
  9611. # result = BatteryInfo().getBatteryInfo(batterySn).get(batterySn)
  9612. result = BatteryInfo().getBatteryInfo(batterySn).get(batterySn)
  9613. if not result:
  9614. return JsonErrorResponse(description=u"电池定位第三方数据请求失败")
  9615. # TODO zjl 需要对经纬度进行转换
  9616. # TODO 前台做成了分页的形式 暂时就这样吧 后续再修改
  9617. data = {
  9618. "lat": result.get("lat"),
  9619. "lng": result.get("lng"),
  9620. "voltage": result.get("voltage")
  9621. }
  9622. payload = {
  9623. "total": 1,
  9624. "items": [data]
  9625. }
  9626. return JsonOkResponse(payload=payload)
  9627. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置电池失败"))
  9628. @permission_required(ROLE.dealer, ROLE.subaccount)
  9629. def disableBattery(request):
  9630. """
  9631. 经销商标记电池 被标记的电池当再次被放入的时候
  9632. :param request:
  9633. :return:
  9634. """
  9635. dealerId = str(request.user.bossId)
  9636. payload = json.loads(request.body)
  9637. disable = payload.get("disable")
  9638. batterySn = payload.get("batterySn")
  9639. print batterySn, type(batterySn)
  9640. print disable, type(disable)
  9641. for sn in batterySn:
  9642. battery = Battery.get_one(dealerId, sn)
  9643. if not battery:
  9644. return JsonErrorResponse(description=u"未查找到电池数据,请刷新页面重试")
  9645. battery.disable = disable
  9646. return JsonOkResponse()
  9647. @permission_required(ROLE.dealer)
  9648. def createEmptyCardTicket(request):
  9649. json_str = request.body
  9650. json_data = json.loads(json_str)
  9651. number = json_data.get('number')
  9652. card_id = json_data.get('cardId')
  9653. if not str(number).isdigit():
  9654. return JsonErrorResponse(description=u'请输入数字!')
  9655. if int(number) > 50:
  9656. return JsonErrorResponse(description=u'单次发卡数量不能超过50张')
  9657. try:
  9658. card_model = VirtualCard.objects.get(id=card_id)
  9659. except Exception:
  9660. return JsonErrorResponse(description=u'读取虚拟卡失败,请重试')
  9661. attachParas = {}
  9662. attachParas['number'] = int(number)
  9663. attachParas['card_id'] = card_id
  9664. virtual_cards = VirtualCardBuilder.create_virtual_card(request.user, card_model, attachParas)
  9665. return JsonResponse({'result': 0, 'description': '当前生成卡号:%s' % (','.join(virtual_cards))})
  9666. @permission_required(ROLE.dealer, ROLE.subaccount)
  9667. def bindVirtualCardToRechargeIDCard(request):
  9668. payload = json.loads(request.body)
  9669. virtualCardId = payload.get('virtualCardId')
  9670. rechargeIDCardId = payload.get('rechargeIDCardId')
  9671. if virtualCardId is None:
  9672. return JsonErrorResponse(description=u'未找到虚拟卡ID')
  9673. if rechargeIDCardId is None:
  9674. return JsonErrorResponse(description=u'未找到ID实体卡')
  9675. card = Card.objects(id=rechargeIDCardId).first()
  9676. if card is None:
  9677. return JsonErrorResponse(description=u'未找到ID实体卡')
  9678. if card.boundVirtualCardId:
  9679. return JsonErrorResponse(description=u'该卡片已绑定一张虚拟卡')
  9680. if card.cardType != RECHARGE_CARD_TYPE.ID:
  9681. return JsonErrorResponse(description=u'该卡不是ID卡')
  9682. virtualCard = UserVirtualCard.objects(id=virtualCardId).first()
  9683. if virtualCard is None:
  9684. return JsonErrorResponse(description=u'未找到虚拟卡')
  9685. updated = card.bind_virtual_card(virtualCard)
  9686. res = VirtualCardBuilder.active_virtual_card(virtualCardId)
  9687. if updated and res:
  9688. return JsonOkResponse()
  9689. else:
  9690. return JsonErrorResponse(description=u'绑定失败')
  9691. @permission_required(ROLE.dealer)
  9692. def unbindVirtualCardToRechargeIDCard(request):
  9693. json_str = request.body
  9694. json_data = json.loads(json_str)
  9695. card_id = str(json_data.get('cardId'))
  9696. try:
  9697. card = Card.objects.get(id=card_id)
  9698. except Exception:
  9699. return JsonErrorResponse(description=u'数据走丢了,请稍后再试')
  9700. if not card.bound_virtual_card:
  9701. return JsonErrorResponse(description=u'该卡片未绑定优惠卡券')
  9702. res = VirtualCardBuilder.unbind_virtual_card(card)
  9703. if res:
  9704. return JsonOkResponse()
  9705. else:
  9706. return JsonErrorResponse(description=u'解绑失败,请稍后再试')
  9707. @error_tolerate(nil=DefaultJsonErrorResponse)
  9708. @permission_required(ROLE.dealer)
  9709. def getDeviceStockForGoods(request):
  9710. logicalCode = request.GET.get('logicalCode', '')
  9711. pageSize = int(request.GET.get("pageSize", 10))
  9712. pageIndex = int(request.GET.get("pageIndex", 1))
  9713. if not logicalCode:
  9714. return JsonErrorResponse(description=u'参数接口错误')
  9715. devObj = Device.objects.get(logicalCode=logicalCode)
  9716. dataList = []
  9717. for itemTypeId, count in devObj.stockDetailDict.items():
  9718. try:
  9719. itemType = ItemType.objects.get(id=itemTypeId)
  9720. except Exception, e:
  9721. continue
  9722. dataList.append({
  9723. 'quantity':count,
  9724. 'itemId':itemTypeId,
  9725. 'itemName':itemType.title,
  9726. 'itemPrice':itemType.price,
  9727. 'itemPicUrl':itemType.picUrl
  9728. })
  9729. return JsonOkResponse(payload={'total':len(dataList), 'dataList':dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]})
  9730. def addGoodsForStock(request):
  9731. payload = json.loads(request.body)
  9732. logicalCode = payload.get('logicalCode')
  9733. quantity = payload.get('quantity')
  9734. itemId = payload.get('itemId')
  9735. dev = Device.get_dev_by_l(logicalCode)
  9736. devObj = Device.objects.get(logicalCode=logicalCode)
  9737. oldQuantity = devObj.stockDetailDict.get(itemId, 0)
  9738. devObj.stockDetailDict[itemId] = quantity
  9739. try:
  9740. devObj.save()
  9741. except Exception, e:
  9742. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9743. if quantity > oldQuantity:
  9744. stockType = 'add'
  9745. stockNum = quantity - oldQuantity
  9746. elif quantity < oldQuantity:
  9747. stockType = 'remove'
  9748. stockNum = oldQuantity - quantity
  9749. else:
  9750. stockType = ''
  9751. itemObj = ItemType.objects.get(id=itemId)
  9752. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  9753. StockRecord.get_collection().insert(
  9754. {'logicCode': logicalCode, 'imei': dev['devNo'], 'stockType': stockType, 'stockTime': stockTime, 'number': stockNum, 'more':itemObj.title})
  9755. # 刷新总的数目
  9756. allCount = 0
  9757. for count in devObj.stockDetailDict.values():
  9758. allCount += count
  9759. result = Device.update_field(dev_no=devObj.devNo, update=True, quantity=allCount)
  9760. if not result:
  9761. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9762. return JsonOkResponse()
  9763. @error_tolerate(nil=DefaultJsonErrorResponse)
  9764. @permission_required(ROLE.dealer)
  9765. def deleteItemStock(request):
  9766. payload = json.loads(request.body)
  9767. logicalCode = payload.get('logicalCode')
  9768. itemIds = payload.get('itemIds')
  9769. dev = Device.get_dev_by_l(logicalCode)
  9770. devObj = Device.objects.get(logicalCode=logicalCode)
  9771. for itemId in itemIds:
  9772. itemObj = ItemType.objects.get(id=itemId)
  9773. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  9774. StockRecord.get_collection().insert(
  9775. {'logicCode': logicalCode, 'imei': dev['devNo'], 'stockType': 'remove', 'stockTime': stockTime, 'number': devObj.stockDetailDict.get(itemId, 0), 'more':itemObj.title})
  9776. try:
  9777. devObj.stockDetailDict.pop(itemId)
  9778. except Exception, e:
  9779. continue
  9780. try:
  9781. devObj.save()
  9782. except Exception, e:
  9783. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9784. allCount = 0
  9785. for count in devObj.stockDetailDict.values():
  9786. allCount += count
  9787. result = Device.update_field(dev_no=devObj.devNo, update=True, quantity=allCount)
  9788. if not result:
  9789. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9790. return JsonOkResponse()
  9791. @error_tolerate(nil=DefaultJsonErrorResponse)
  9792. @permission_required(ROLE.dealer)
  9793. def updateStockQuantityForGoods(request):
  9794. payload = json.loads(request.body)
  9795. logicalCode = payload.get('logicalCode')
  9796. quantity = payload.get('quantity')
  9797. itemIds = payload.get('itemIds')
  9798. dev = Device.get_dev_by_l(logicalCode)
  9799. oldQuantity = dev['quantity']
  9800. devObj = Device.objects.get(logicalCode=logicalCode)
  9801. for itemId in itemIds:
  9802. devObj.stockDetailDict[itemId] = quantity
  9803. if quantity > oldQuantity:
  9804. stockType = 'add'
  9805. stockNum = quantity - oldQuantity
  9806. elif quantity < oldQuantity:
  9807. stockType = 'remove'
  9808. stockNum = oldQuantity - quantity
  9809. else:
  9810. stockType = ''
  9811. try:
  9812. itemObj = ItemType.objects.get(id=itemId)
  9813. except Exception, e:
  9814. continue
  9815. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  9816. StockRecord.get_collection().insert(
  9817. {'logicCode': logicalCode, 'imei': dev['devNo'], 'stockType': stockType, 'stockTime': stockTime, 'number': stockNum, 'more':itemObj.title})
  9818. try:
  9819. devObj.save()
  9820. except Exception, e:
  9821. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9822. allCount = 0
  9823. for count in devObj.stockDetailDict.values():
  9824. allCount += count
  9825. result = Device.update_field(dev_no=devObj.devNo, update=True, quantity=allCount)
  9826. if not result:
  9827. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9828. return JsonOkResponse()
  9829. @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"没有余额卡"))
  9830. @permission_required(ROLE.dealer)
  9831. def getCardListForDevice(request):
  9832. """
  9833. 给中山绿智做的经销商充值
  9834. """
  9835. logicalCode = request.GET.get("logicalCode")
  9836. dealer = Dealer.objects(id=str(request.user.id)).first()
  9837. if dealer is None:
  9838. return JsonErrorResponse(description=u"设备的经销商不存在")
  9839. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  9840. dev = Device.get_dev(devNo)
  9841. if dev is None:
  9842. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  9843. if dev['ownerId'] != str(request.user.bossId):
  9844. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  9845. box = ActionDeviceBuilder.create_action_device(dev)
  9846. try:
  9847. res = box.get_no_balance_list(devNo)
  9848. except ServiceException, e:
  9849. logger.info('error happened, error=%s' % (e,))
  9850. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  9851. except Exception, e:
  9852. logger.exception('error happened, error=%s' % (e,))
  9853. return JsonResponse({'result': 0, 'description': u'系统异常,请检查输入参数,或者稍后重试', 'payload': {}})
  9854. return JsonResponse({'result': 1, 'description': None, 'payload': {"total":1, "dataList":res}})
  9855. @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"没有余额卡"))
  9856. @permission_required(ROLE.dealer)
  9857. def chargeInsufficientBalanceCard(request):
  9858. """
  9859. 给中山绿智做的经销商充值
  9860. """
  9861. payload = json.loads(request.body)
  9862. logicalCode = payload.get("logicalCode")
  9863. amount = payload.get("amount")
  9864. cardIds = payload.get("cardIds")
  9865. if not logicalCode or not amount or not cardIds:
  9866. return JsonErrorResponse(description=u"请完整的传入参数")
  9867. dealer = Dealer.objects(id=str(request.user.id)).first()
  9868. if dealer is None:
  9869. return JsonErrorResponse(description=u"设备的经销商不存在")
  9870. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  9871. dev = Device.get_dev(devNo)
  9872. if dev is None:
  9873. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  9874. if dev['ownerId'] != str(request.user.bossId):
  9875. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  9876. box = ActionDeviceBuilder.create_action_device(dev)
  9877. try:
  9878. res = box.remote_charge_ic_card_by_dealer(cardIds, amount)
  9879. except ServiceException, e:
  9880. logger.info('error happened, error=%s' % (e,))
  9881. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  9882. except Exception, e:
  9883. logger.exception('error happened, error=%s' % (e,))
  9884. return JsonResponse({'result': 0, 'description': u'系统异常,请检查输入参数,或者稍后重试', 'payload': {}})
  9885. return JsonResponse({'result': 1, 'description': None})
  9886. @permission_required(ROLE.dealer)
  9887. def getDeviceLocker(request):
  9888. """
  9889. 储物柜的大小格子配置
  9890. """
  9891. logicalCode = request.GET.get("logicalCode[]")
  9892. if isinstance(logicalCode, (str, unicode)):
  9893. dev = Device.objects.filter(logicalCode=logicalCode).first()
  9894. sizeInfo = dev.otherConf.get("sizeInfo", [])
  9895. if not sizeInfo:
  9896. for i in xrange(1, 25):
  9897. item = {"port":str(i), "size":"small"}
  9898. sizeInfo.append(item)
  9899. dev.otherConf["sizeInfo"] = sizeInfo
  9900. dev.save()
  9901. dev.invalid_device_cache(dev.devNo)
  9902. return JsonResponse({
  9903. "result": 1,
  9904. "description": "",
  9905. "payload": {
  9906. "dataList": sizeInfo
  9907. }
  9908. })
  9909. else: # 批量获取
  9910. pass
  9911. @permission_required(ROLE.dealer)
  9912. def saveDeviceLocker(request):
  9913. """
  9914. 储物柜的大小格子配置
  9915. """
  9916. payload = json.loads(request.body)
  9917. logicalCodes = payload.get("logicalCode")
  9918. portList = payload.get("portList")
  9919. for item in portList:
  9920. item["port"] = str(item["port"])
  9921. if not logicalCodes:
  9922. return JsonResponse({"result": 2,
  9923. "description": "设备号错误,请重试......", })
  9924. if not portList:
  9925. return JsonResponse({"result": 2,
  9926. "description": "当前没有设置任何设备参数", })
  9927. for item in logicalCodes:
  9928. dev = Device.objects.filter(logicalCode=item).first()
  9929. dev.otherConf["sizeInfo"] = portList
  9930. dev.otherConf["actualPortNum"] = len(portList)
  9931. dev.save()
  9932. Device.invalid_device_cache(dev.devNo)
  9933. return JsonResponse({"result": 1,
  9934. "description": "", })
  9935. # 经销商获取提现短信验证码
  9936. @error_tolerate(nil=DefaultJsonErrorResponse)
  9937. @permission_required(ROLE.dealer)
  9938. def getEditMonitorCode(request):
  9939. # type: (WSGIRequest)->JsonResponse
  9940. currentDealer = request.user # type: Dealer
  9941. if currentDealer.abnormal:
  9942. return JsonErrorResponse(description=u'该帐号资金异常,请合法经营。具体请联系客服')
  9943. toNumber = request.GET.get('phone')
  9944. if not toNumber:
  9945. toNumber = request.user.monitorPhone
  9946. if not toNumber:
  9947. return JsonErrorResponse(description=u'没有找到提现审批人的手机号')
  9948. agentId = request.user.agentId
  9949. agent = Agent.get_agent(agentId)
  9950. productName = agent['productName']
  9951. status, msg = dealerEditMonitorSMSProvider.get(phoneNumber=toNumber,
  9952. productName=productName,
  9953. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  9954. if not status:
  9955. return JsonErrorResponse(description=msg)
  9956. else:
  9957. return JsonOkResponse()
  9958. @error_tolerate(nil=DefaultJsonErrorResponse)
  9959. @permission_required(ROLE.dealer)
  9960. def getDealerMonitor(request):
  9961. return JsonOkResponse(payload={'phone':request.user.monitorPhone if request.user.monitorPhone else None})
  9962. @error_tolerate(nil=DefaultJsonErrorResponse)
  9963. @permission_required(ROLE.dealer)
  9964. def editMonitor(request):
  9965. dealer = request.user
  9966. if request.GET.get('oper') == 'delete':
  9967. code = request.GET.get('code')
  9968. phone = dealer.monitorPhone
  9969. if not phone:
  9970. return JsonErrorResponse(description=u'没有找到提现审批人的手机号,无法清除')
  9971. status, msg = dealerEditMonitorSMSProvider.verify(phone, code)
  9972. if not status:
  9973. return JsonErrorResponse(msg)
  9974. dealer.monitorPhone = ''
  9975. dealer.save()
  9976. return JsonOkResponse()
  9977. if not request.GET.get('phone'):
  9978. return JsonErrorResponse(description=u'没有找到提现审批人的手机号')
  9979. phone = request.GET.get('phone')
  9980. code = request.GET.get('code')
  9981. status, msg = dealerEditMonitorSMSProvider.verify(phone, code)
  9982. if not status:
  9983. return JsonErrorResponse(msg)
  9984. dealer.monitorPhone = phone
  9985. dealer.save()
  9986. return JsonOkResponse()
  9987. @error_tolerate(nil=DefaultJsonErrorResponse)
  9988. @permission_required(ROLE.dealer)
  9989. def bindParentNode(request):
  9990. payload = json.loads(request.body)
  9991. parentNode = payload.get("parentLogicalCode")
  9992. node = payload.get("childLogicalCode")
  9993. category = payload.get("category")
  9994. try:
  9995. if category == "CM":
  9996. # 诚马的插座 采用主绑定从的方式 进行绑定
  9997. master, sub = Device.get_dev_by_l(parentNode), Device.get_dev_by_l(node)
  9998. if not all([master, sub]):
  9999. return JsonErrorResponse(description=u"绑定设备错误(10001)")
  10000. master.deviceAdapter.add_node(sub)
  10001. elif category == "BL":
  10002. # 这里有3种情况,1、插座和网关一体板,自己绑自己;2、其他插座绑定纯网关的逻辑编码;3、其他插座绑一体板的二维码
  10003. gatewayDev = Device.get_dev_by_l(parentNode) # type: DeviceDict
  10004. if gatewayDev is None:
  10005. Device.get_collection().update({'logicalCode':node}, {'$set':{'gateImei':parentNode}})
  10006. gatewayPlugDev = Device.get_dev_by_l(node)
  10007. box = gatewayPlugDev.deviceAdapter
  10008. box.add_node(gatewayPlugDev['devNo'])
  10009. else:
  10010. box = gatewayDev.deviceAdapter # type: ChargingGatewayBox
  10011. box.add_node(Device.get_dev_by_l(node)['devNo'])
  10012. else:
  10013. return JsonErrorResponse(description=u"错误的节点绑定类型")
  10014. except ServiceException as se:
  10015. return JsonErrorResponse(description=se.result["description"])
  10016. return JsonOkResponse()
  10017. @error_tolerate(nil=DefaultJsonErrorResponse)
  10018. @permission_required(ROLE.dealer)
  10019. def unbindParentNode(request):
  10020. payload = json.loads(request.body)
  10021. node = payload.get("logicalCode")
  10022. nodeDev = Device.get_dev_by_l(node) # type: DeviceDict
  10023. box = nodeDev.deviceAdapter # type: ChargingBox
  10024. box.remove_from_gateway()
  10025. return JsonOkResponse()
  10026. @error_tolerate(nil=DefaultJsonErrorResponse)
  10027. @permission_required(ROLE.dealer)
  10028. def getGateway(request):
  10029. payload = json.loads(request.body)
  10030. lc = payload.get("logicalCode")
  10031. devObj = Device.objects.get(logicalCode=lc)
  10032. if devObj.gatewayNode == '':
  10033. return JsonResponse({"result": 1, "description": "", "payload": {}})
  10034. gatewayDev = Device.get_dev(devObj.gatewayNode) # type: DeviceDict
  10035. box = gatewayDev.deviceAdapter # type: ChargingGatewayBox
  10036. devInfo = box.get_signal()
  10037. data = {
  10038. 'logicalCode':gatewayDev['logicalCode'],
  10039. 'gatewaySignal':devInfo['signal'],
  10040. 'groupName':gatewayDev['groupName']
  10041. }
  10042. return JsonResponse({"result": 1, "description": "", "payload": data})
  10043. @error_tolerate(nil=DefaultJsonErrorResponse)
  10044. @permission_required(ROLE.dealer)
  10045. def getNodeList(request):
  10046. """
  10047. 获取主机的节点列表
  10048. """
  10049. lc = request.GET.get("logicalCode")
  10050. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  10051. box = dev.deviceAdapter # type: ChargingGatewayBox
  10052. nodeList = box.get_node_list()
  10053. dataList = []
  10054. devDict = {}
  10055. for node in nodeList:
  10056. nodeDev = Device.get_dev(node['devNo']) # type: DeviceDict
  10057. if nodeDev is None:
  10058. continue
  10059. if not nodeDev.is_registered:
  10060. _temp = {
  10061. 'id': node.devNo,
  10062. 'groupId': "",
  10063. 'logicalCode': nodeDev.logicalCode,
  10064. 'devType': nodeDev.devTypeName,
  10065. "online": nodeDev.online,
  10066. "registered": nodeDev.is_registered,
  10067. "signal": nodeDev.signal
  10068. }
  10069. else:
  10070. _temp = {
  10071. 'id': node.devNo,
  10072. 'groupId': nodeDev.group.groupId,
  10073. 'logicalCode': nodeDev.logicalCode,
  10074. 'devType': nodeDev.devTypeName,
  10075. "online": nodeDev.online,
  10076. "registered": nodeDev.is_registered,
  10077. "signal": nodeDev.signal
  10078. }
  10079. if nodeDev['groupId'] in devDict:
  10080. devDict[nodeDev['groupId']].append(node)
  10081. else:
  10082. devDict[nodeDev['groupId']] = [node]
  10083. dataList.append(node)
  10084. natural_sort(array=dataList, key='logicalCode', reverse=False)
  10085. return JsonResponse({
  10086. "result": 1,
  10087. "description": None,
  10088. 'payload': {
  10089. "total": len(dataList),
  10090. "groupCount": len(devDict.keys()),
  10091. "dataList": dataList
  10092. }
  10093. })
  10094. @error_tolerate(nil=DefaultJsonErrorResponse)
  10095. @permission_required(ROLE.dealer)
  10096. def getPortParam(request):
  10097. payload = json.loads(request.body)
  10098. lc = payload.get("logicalCode")[0]
  10099. portIndex = payload.get("port")
  10100. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  10101. box = dev.deviceAdapter # type: ChargingBox
  10102. config = box.get_port_config(portIndex)
  10103. return JsonResponse({"result": 1, "description": "", "payload": config})
  10104. @error_tolerate(nil=DefaultJsonErrorResponse)
  10105. @permission_required(ROLE.dealer)
  10106. def setPortParam(request):
  10107. payload = json.loads(request.body)
  10108. lc = payload.get("logicalCode")[0]
  10109. portIndex = payload.get("port")
  10110. maxCurrent = payload.get('max_current', 10)
  10111. maxPower = payload.get('max_power', 1000)
  10112. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  10113. box = dev.deviceAdapter # type: ChargingBox
  10114. box.set_port_config(portIndex, {'max_power':int(maxPower), 'max_current':int(maxCurrent)})
  10115. return JsonOkResponse()
  10116. @permission_required(ROLE.dealer, ROLE.subaccount)
  10117. def beAuthLogin(request):
  10118. oper_id = request.GET.get('dealerId')
  10119. # 校验经销商是否存在
  10120. dealer = Dealer.objects.filter(id=oper_id).first()
  10121. if not dealer:
  10122. return ErrorResponseRedirect(error=cn('当前经销不存在'))
  10123. # 校验当前用户是否已经是授权登入的
  10124. session = DealerSessionBuilder(request)
  10125. if session.is_dealer_trustee():
  10126. return ErrorResponseRedirect(error=cn('授权人页面不允许切换'))
  10127. role = PermissionRole.objects.filter(dealerId=str(dealer.id), operId=str(request.user.id)).first()
  10128. if role:
  10129. if role.isActive:
  10130. session.check_out_to_dealer_trustee(oper_id)
  10131. else:
  10132. if role.authorizeType == 'dealer_to_dealer':
  10133. return ErrorResponseRedirect(error=cn(u'请联系您的授权经销商给您配置权限'))
  10134. elif role.authorizeType == 'dealer_to_subAccount':
  10135. return ErrorResponseRedirect(error=cn(u'请联系您的主经销商同意此授权关系'))
  10136. else:
  10137. # 没有权限
  10138. return ErrorResponseRedirect(error=cn(u'当前授权已失效'))
  10139. return FrontEndResponseRedirect(add_query('/app/index.html', {}))
  10140. @permission_required(ROLE.dealer)
  10141. def loginMyPrimaryAccount(request):
  10142. session = DealerSessionBuilder(request)
  10143. if session.is_dealer_trustee():
  10144. result = session.check_out_to_dealer_master()
  10145. if not result:
  10146. return ErrorResponseRedirect(error=cn(u'验证失败,请重新登入'))
  10147. else:
  10148. pass
  10149. # return ErrorResponseRedirect(error=cn(u'当前已经是主账户'))
  10150. # 无需切换已经是主账户
  10151. return FrontEndResponseRedirect(add_query('/app/index.html', {}))
  10152. @permission_required(ROLE.dealer)
  10153. def addOrEditOperatorPermission(request):
  10154. session = DealerSessionBuilder(request)
  10155. if session.is_dealer_trustee():
  10156. # 操作员无权限修改改权限
  10157. return ErrorResponseRedirect(error=cn(u'您当前无权修改授权权限'))
  10158. else:
  10159. permissionId = request.POST.get('permissionId')
  10160. permissionDict = request.POST.get('permissions')
  10161. PermissionRule.objects.get(id=permissionId, dealerId=str(request.user.id)).update(permissionDict=permissionDict)
  10162. @permission_required(ROLE.dealer)
  10163. def getAccountPermissionByAuthId(request):
  10164. id = request.GET.get('id')
  10165. role = PermissionRole.objects.filter(operId=id, dealerId=str(request.user.id)).first()
  10166. if not role:
  10167. return JsonResponse({'result': 0, 'description': '您的当前授权已失效'})
  10168. rule = PermissionRule.objects.filter(id=role.permissionRuleId).first()
  10169. return JsonResponse({'result': 1, 'description': '', 'payload': rule.get_permissionDict()})
  10170. @permission_required(ROLE.dealer)
  10171. def saveAccountPermissionByAuthId(request):
  10172. payload = json.loads(request.body)
  10173. id = payload.pop('id', None)
  10174. role = PermissionRole.objects.filter(operId=id, dealerId=str(request.user.id)).first()
  10175. if role:
  10176. if role.authorizeType == 'dealer_to_dealer': # 经销商对经销商 直接激活此次授权
  10177. role.update(isActive=True)
  10178. elif role.authorizeType == 'dealer_to_subAccount': # 经销商对子账号 需要子账号的主账号同意
  10179. pass
  10180. rule = PermissionRule.objects.filter(id=role.permissionRuleId).update(permissionDict=payload)
  10181. return JsonResponse({'result': 1, 'description': '', 'payload':{}})
  10182. else:
  10183. return JsonResponse({'result': 0, 'description': '权限配置失败', 'payload': {}})
  10184. @permission_required(ROLE.dealer)
  10185. def getAuthList(request):
  10186. dealer_id = PermissionRole.get_auth_to_dealer(dealerId=str(request.user.id))
  10187. dealers = Dealer.objects(id__in=dealer_id)
  10188. total = dealers.count()
  10189. pageSize = int(request.GET.get('pageSize', 10))
  10190. pageIndex = int(request.GET.get('pageIndex', 1))
  10191. dataList = []
  10192. for dealer in dealers:
  10193. item = {
  10194. 'id': str(dealer.id),
  10195. 'nickname': dealer.nickname,
  10196. 'username': dealer.username,
  10197. 'avatarUrl': dealer.my_avatar if dealer.my_avatar else settings.DEFAULT_AVATAR_URL,
  10198. }
  10199. dataList.append(item)
  10200. subAccount_id = PermissionRole.get_auth_to_sub(dealerId=str(request.user.id))
  10201. subAccounts = SubAccount.objects(id__in=subAccount_id)
  10202. total += subAccounts.count()
  10203. for subAccount in subAccounts:
  10204. item = {
  10205. 'id': str(subAccount.id),
  10206. 'nickname': subAccount.nickname,
  10207. 'username': subAccount.username,
  10208. 'avatarUrl': subAccount.my_avatar if subAccount.my_avatar else settings.DEFAULT_AVATAR_URL,
  10209. }
  10210. dataList.append(item)
  10211. payload = {
  10212. 'total': total,
  10213. 'dealerId': str(request.user.id),
  10214. 'agentId': request.user.agentId,
  10215. 'dataList': dataList[pageIndex * pageSize - pageSize: pageIndex * pageSize ]
  10216. }
  10217. return JsonResponse({'result': 1, 'description': '', 'username':request.user.username, 'payload': payload})
  10218. @permission_required(ROLE.dealer, ROLE.subaccount)
  10219. def getBeAuthList(request):
  10220. if request.user.role == 'dealer':
  10221. dealer_id = PermissionRole.get_is_auth_list(operId=str(request.user.id), authorizeType='dealer_to_dealer')
  10222. elif request.user.role == 'subaccount':
  10223. dealer_id = PermissionRole.get_is_auth_list(operId=str(request.user.id), authorizeType='dealer_to_subAccount')
  10224. else:
  10225. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10226. dealers = Dealer.objects(id__in=dealer_id)
  10227. total = dealers.count()
  10228. payload = {
  10229. 'total': total,
  10230. 'dealerId': str(request.user.id),
  10231. 'agentId': request.user.agentId
  10232. }
  10233. pageSize = int(request.GET.get('pageSize', 10))
  10234. pageIndex = int(request.GET.get('pageIndex', 1))
  10235. dataList = []
  10236. for dealer in dealers.paginate(pageIndex=pageIndex, pageSize=pageSize):
  10237. item = {
  10238. 'dealerId': str(dealer.id),
  10239. 'nickname': dealer.nickname,
  10240. 'username': dealer.username,
  10241. 'avatarUrl': dealer.my_avatar if dealer.my_avatar else settings.DEFAULT_AVATAR_URL,
  10242. }
  10243. dataList.append(item)
  10244. payload['dataList'] = dataList
  10245. return JsonResponse({'result': 1, 'description': '', 'username': request.user.username, 'payload': payload})
  10246. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10247. @permission_required(ROLE.dealer)
  10248. def getMonthlyPackageTemp(request):
  10249. """
  10250. 获取包月套餐
  10251. :param request:
  10252. :return:
  10253. """
  10254. dealerId = str(request.user.bossId)
  10255. dealer = Dealer.objects.get(id=dealerId)
  10256. monthlyPackages = dealer.monthlyPackage
  10257. dataList = [_package.to_dict() for _package in monthlyPackages]
  10258. return JsonOkResponse(payload={"dataList": dataList})
  10259. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10260. @permission_required(ROLE.dealer)
  10261. def getMonthlyPackageTempDetail(request):
  10262. monthlyPackageId = request.GET.get("id", "")
  10263. monthlyPackage = MonthlyPackageTemp.get_package_by_id(monthlyPackageId)
  10264. if not monthlyPackage or monthlyPackage.ownerId != str(request.user.bossId):
  10265. return JsonErrorResponse(description=u"未找到相应模板套餐,请刷新重试")
  10266. return JsonOkResponse(payload=monthlyPackage.to_dict())
  10267. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10268. @permission_required(ROLE.dealer)
  10269. def saveMonthlyPackageTemp(request):
  10270. """
  10271. 保存包月套餐模板
  10272. :param request:
  10273. :return:
  10274. """
  10275. payload = json.loads(request.body)
  10276. packageId = payload.pop("id", "")
  10277. monthlyPackage = MonthlyPackageTemp.get_package_by_id(packageId)
  10278. if not monthlyPackage or monthlyPackage.ownerId != str(request.user.bossId):
  10279. return JsonErrorResponse(description=u"未找到相应模板套餐,请刷新重试")
  10280. # 修改包月的模板套餐
  10281. monthlyPackage.update_by_fields(**payload)
  10282. return JsonOkResponse()
  10283. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10284. @permission_required(ROLE.dealer)
  10285. def delMonthlyPackageTemp(request):
  10286. """
  10287. 经销商删除包月套餐模板
  10288. :param request:
  10289. :return:
  10290. """
  10291. payload = json.loads(request.body)
  10292. packageId = payload.get("id", "")
  10293. monthlyPackage = MonthlyPackageTemp.get_package_by_id(packageId)
  10294. if not monthlyPackage:
  10295. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10296. if monthlyPackage.ownerId != str(request.user.bossId):
  10297. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10298. # 默认模板无法删除
  10299. if monthlyPackage.isDefault:
  10300. return JsonErrorResponse(description=u"默认包月模板无法删除")
  10301. # 需要将关联此模板的地址组的包月信息全部清空 置为默认的
  10302. groupIds = Group.get_group_ids_of_dealer(str(request.user.bossId))
  10303. Group.objects.filter(id__in=groupIds, monthlyPackage=monthlyPackage).update(monthlyPackage=None)
  10304. # 最后将改套餐置为 idDelete
  10305. monthlyPackage.update(isDelete=1)
  10306. return JsonOkResponse()
  10307. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10308. @permission_required(ROLE.dealer)
  10309. def setDefaultMonthlyPackageTemp(request):
  10310. """
  10311. 经销商 将包月套餐设置成默认的套餐
  10312. :param request:
  10313. :return:
  10314. """
  10315. payload = json.loads(request.body)
  10316. packageId = payload.get("id", "")
  10317. monthlyPackage = MonthlyPackageTemp.get_package_by_id(packageId)
  10318. if not monthlyPackage:
  10319. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10320. if monthlyPackage.ownerId != str(request.user.bossId):
  10321. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10322. monthlyPackage.set_default()
  10323. return JsonOkResponse()
  10324. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10325. @permission_required(ROLE.dealer)
  10326. def addGroupToMonthlyPackageTemp(request):
  10327. """
  10328. 添加设备 到 包月套餐
  10329. :param request:
  10330. :return:
  10331. """
  10332. payload = json.loads(request.body)
  10333. packageId = payload.get("packageId", "")
  10334. groupIds = payload.get("groupId", "")
  10335. groups = list()
  10336. for _groupId in groupIds:
  10337. group = Group.get_dealer_group(str(request.user.bossId), id=_groupId.get("groupId", ""))
  10338. if not group:
  10339. return JsonErrorResponse(description=u"未找到相应的设备组,请刷新重试")
  10340. groups.append(group)
  10341. monthlyPackage = MonthlyPackageTemp.get_dealer_package(ownerId=str(request.user.bossId), id=packageId)
  10342. if not monthlyPackage:
  10343. return JsonErrorResponse(description=u"未找到相应套餐,请刷新重试")
  10344. for _group in groups:
  10345. _group.monthlyRule = monthlyPackage
  10346. return JsonOkResponse()
  10347. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10348. @permission_required(ROLE.dealer)
  10349. def addMonthlyPackageTemp(request):
  10350. ownerId = str(request.user.bossId)
  10351. payload = json.loads(request.body)
  10352. monthlyPackage = MonthlyPackageTemp.create_by_fields(ownerId=ownerId, **payload)
  10353. return JsonOkResponse(payload={"packageId": str(monthlyPackage.id)})
  10354. @permission_required(ROLE.dealer)
  10355. def deleteAuth(request):
  10356. session = DealerSessionBuilder(request)
  10357. if session.is_dealer_trustee():
  10358. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10359. if request.method != 'POST':
  10360. return ErrorResponseRedirect(error=cn(u'异常访问'))
  10361. payload = json.loads(request.body)
  10362. operIds = payload.get('ids')
  10363. try:
  10364. PermissionRole.delete_role_permission(operIds=operIds, dealerId=str(request.user.id))
  10365. except Exception:
  10366. return JsonResponse({'result': 0, 'description': '扫码识别失败,请重试', 'payloay':{}})
  10367. return JsonResponse({'result': 1, 'description': '成功', 'payload':{}})
  10368. @permission_required(ROLE.dealer, ROLE.subaccount)
  10369. def toAuthToken(request):
  10370. session = DealerSessionBuilder(request)
  10371. if session.is_dealer_trustee():
  10372. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10373. else:
  10374. if request.user.role == 'dealer':
  10375. dealerId = str(request.user.id)
  10376. payload = {'oper_id':dealerId, 'role':'dealer'}
  10377. elif request.user.role == 'subaccount':
  10378. subaccount = str(request.user.id)
  10379. payload = {'oper_id': subaccount, 'role': 'subaccount'}
  10380. else:
  10381. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10382. token = MyToken.encode(payload)
  10383. logger.info(token)
  10384. return JsonResponse({ 'result': 1, 'description': None, 'payload': {'dealerId': 'xxx', 'token': token}})
  10385. @permission_required(ROLE.dealer)
  10386. def getOtherDealerAuth(request):
  10387. # 经销商扫经销商授权
  10388. scannedURL = request.GET.get('url', None)
  10389. if not scannedURL:
  10390. return JsonResponse({'result': 100, 'description': u'错误的二维码或二维码已损坏'})
  10391. from urlparse import unquote
  10392. scannedURL = unquote(scannedURL)
  10393. logger.debug('scan url is {}'.format(scannedURL))
  10394. return FrontEndResponseRedirect(add_query(scannedURL, {}))
  10395. @permission_required(ROLE.dealer)
  10396. def toAuth(request):
  10397. master_id = str(request.user.id)
  10398. token = request.GET.get('token', None)
  10399. if not token:
  10400. return JsonResponse({'result': 0, 'description': '扫码识别失败,请重试', 'payload': {}})
  10401. try:
  10402. payload = MyToken.decode(token)
  10403. except Exception as e:
  10404. logger.info('toAuth token is invalid..')
  10405. payload = {}
  10406. if not payload:
  10407. return JsonResponse({'result': 0, 'description': '二维码已失效,请重新添加二维码!!', 'payload': {}})
  10408. role = payload.get('role')
  10409. oper_id = payload.get('oper_id')
  10410. if role == 'dealer':
  10411. if PermissionRole.objects.filter(dealerId=master_id, operId=oper_id).first():
  10412. PermissionRole.objects.filter(dealerId=master_id, operId=oper_id).update(isActive=True)
  10413. return JsonResponse({'result': 0, 'description': '已添加授权人!!', 'payload': {}})
  10414. else:
  10415. PermissionRole.add_dealer_role(oper_id, master_id)
  10416. return JsonResponse({'result': 0, 'description': '授权人添加成功', 'payload':{}})
  10417. elif role == 'subaccount':
  10418. if PermissionRole.objects.filter(dealerId=master_id, operId=oper_id).first():
  10419. return JsonResponse({'result': 1, 'description': '已添加授权人!!', 'payload': {}})
  10420. else:
  10421. PermissionRole.add_subAccount_role(oper_id, master_id)
  10422. return JsonResponse({'result': 1, 'description': '授权人添加成功,等待子账号主经销商同意', 'payload': {}})
  10423. @permission_required(ROLE.dealer)
  10424. def getSubAccountBeAuthList(request):
  10425. subAccountId = request.GET.get('id')
  10426. master_id = str(request.user.id)
  10427. subAccount = SubAccount.objects.filter(id=subAccountId).first()
  10428. if not subAccount:
  10429. return JsonResponse({'result': 0, 'description': '扫码识别失败,请重试', 'payloay':{}})
  10430. pageSize = int(request.GET.get('pageSize', 10))
  10431. pageIndex = int(request.GET.get('pageIndex', 1))
  10432. roles = PermissionRole.objects.filter(operId=subAccountId, authorizeType='dealer_to_subAccount')
  10433. count = roles.count()
  10434. dataList = []
  10435. for role in roles.paginate(pageIndex=pageIndex, pageSize=pageSize):
  10436. dealer = Dealer.objects.filter(id=role.dealerId).first()
  10437. if dealer:
  10438. item = {
  10439. 'id': str(dealer.id),
  10440. 'nickname': dealer.nickname,
  10441. 'username': dealer.username,
  10442. 'avatarUrl': dealer.my_avatar if dealer.my_avatar else settings.DEFAULT_AVATAR_URL,
  10443. 'status': 'agreed' if role.isActive else '',
  10444. }
  10445. dataList.append(item)
  10446. return JsonResponse({'result':1, 'username':subAccount.username, 'payload':{'dealerId':subAccount.bossId, 'agentId':subAccount.agentId, 'dataList':dataList}})
  10447. @permission_required(ROLE.dealer)
  10448. def agreeSubAccountBeAuth(request):
  10449. session = DealerSessionBuilder(request)
  10450. if session.is_dealer_trustee():
  10451. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10452. if request.method != 'POST':
  10453. return ErrorResponseRedirect(error=cn(u'异常访问'))
  10454. payload = json.loads(request.body)
  10455. subAccountId = payload.get('subAccountId')
  10456. authDealerId = payload.get('authDealerId')
  10457. if not subAccountId or not authDealerId:
  10458. return JsonResponse({'result': 1, 'description': '授权失败,请稍后再试', 'payload': {}})
  10459. PermissionRole.objects.filter(operId=subAccountId, dealerId=authDealerId).update(isActive=True)
  10460. return JsonResponse({'result': 1, 'description': '成功', 'payload':{}})
  10461. @permission_required(ROLE.dealer)
  10462. def disagreeSubAccountBeAuth(request):
  10463. session = DealerSessionBuilder(request)
  10464. if session.is_dealer_trustee():
  10465. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10466. if request.method != 'POST':
  10467. return ErrorResponseRedirect(error=cn(u'异常访问'))
  10468. payload = json.loads(request.body)
  10469. subAccountId = payload.get('subAccountId')
  10470. authDealerId = payload.get('authDealerId')
  10471. if not subAccountId or not authDealerId:
  10472. return JsonResponse({'result': 1, 'description': '授权失败,请稍后再试', 'payload': {}})
  10473. PermissionRole.objects.filter(operId=subAccountId, dealerId=authDealerId).update(isActive=False)
  10474. return JsonResponse({'result': 1, 'description': '成功', 'payload': {}})
  10475. @permission_required(ROLE.dealer)
  10476. def toOtherDealerAuth(request):
  10477. # 子账号授权
  10478. scannedURL = request.GET.get('url', None)
  10479. if not scannedURL:
  10480. return JsonResponse({'result': 100, 'description': u'错误的二维码或二维码已损坏'})
  10481. from urlparse import unquote
  10482. scannedURL = unquote(scannedURL)
  10483. logger.debug('scan url is {}'.format(scannedURL))
  10484. return FrontEndResponseRedirect(add_query(scannedURL, {}))
  10485. @permission_required(ROLE.dealer, ROLE.subaccount)
  10486. def getLastVirtualCard(request):
  10487. """
  10488. 获取 经销商自己配置的虚拟卡的模板
  10489. :param request:
  10490. :return:
  10491. """
  10492. obj = VirtualCard.get_last(str(request.user.bossId))
  10493. if obj:
  10494. data = obj.to_dict()
  10495. return JsonOkResponse(payload=data)
  10496. else:
  10497. data = {
  10498. 'cardName': u"时长套餐",
  10499. 'price': 30,
  10500. 'periodDays': 30,
  10501. 'expiredTime': (datetime.datetime.now() + datetime.timedelta(days=30)).strftime("%Y-%m-%d"),
  10502. 'dealerDesc': "",
  10503. 'userDesc': "",
  10504. 'dayQuota': [],
  10505. 'quota': [],
  10506. 'sharedMembersCount': 3,
  10507. 'userLimit': 3,
  10508. }
  10509. return JsonOkResponse(payload=data)
  10510. @permission_required(ROLE.dealer, ROLE.subaccount)
  10511. def getDeviceWarning(request):
  10512. """
  10513. 获取设备端的告警信息
  10514. :param request:
  10515. :return:
  10516. """
  10517. logicalCode = request.GET.get("logicalCode")
  10518. dev = Device.get_dev_by_l(logicalCode)
  10519. if not dev:
  10520. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10521. if dev.ownerId != str(request.user.bossId):
  10522. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10523. warningInfo = Device.get_dev_warning_cache(dev.devNo)
  10524. portWarning = list()
  10525. deviceWarning = dict()
  10526. for _part, _warning in warningInfo.items():
  10527. if not _warning:
  10528. continue
  10529. _newWarning = {
  10530. "warningPart": _part,
  10531. "warningStatus": _warning["warningStatus"],
  10532. "warningDesc": _warning["warningDesc"],
  10533. "warningTime": _warning["warningTime"]
  10534. }
  10535. if _part.isdigit():
  10536. portWarning.append(_newWarning)
  10537. else:
  10538. deviceWarning = _newWarning
  10539. return JsonOkResponse(payload={"device": deviceWarning, "ports": portWarning})
  10540. @permission_required(ROLE.dealer, ROLE.subaccount)
  10541. def cancelDeviceWarning(request):
  10542. """
  10543. 取消设备的告警信息
  10544. :param request:
  10545. :return:
  10546. """
  10547. logicalCode = request.POST.get("logicalCode")
  10548. part = request.POST.get("part")
  10549. dev = Device.get_dev_by_l(logicalCode)
  10550. if not dev:
  10551. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10552. if dev.ownerId != str(request.user.bossId):
  10553. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10554. if part is None:
  10555. Device.clear_dev_warning_cache(dev.devNo)
  10556. else:
  10557. Device.clear_part_warning_cache(dev.devNo, part)
  10558. return JsonOkResponse()
  10559. @permission_required(ROLE.dealer, ROLE.subaccount)
  10560. def clearDeviceCache(request):
  10561. data = json.loads(request.body)
  10562. dev = Device.get_dev_by_logicalCode(data['logicalCode'])
  10563. Device.invalid_all_cache(dev)
  10564. return JsonOkResponse()
  10565. @permission_required(ROLE.dealer, ROLE.subaccount)
  10566. def getCurrencyGroups(request):
  10567. """
  10568. 获取经销商通用组以及通用模式
  10569. :param request:
  10570. :return:
  10571. """
  10572. current_user = request.user # type: Dealer
  10573. pageIndex = int(request.GET.get('pageIndex', 1))
  10574. pageSize = int(request.GET.get('pageSize', 10))
  10575. groups = []
  10576. for group in Group.get_collection().find({'ownerId': str(request.user.bossId)},
  10577. {'_id': 1, 'name': 1, 'currencyGroup': 1, 'groupName': 1}):
  10578. if 'currencyGroup' in group:
  10579. groups.append({
  10580. 'groupId': str(group['_id']),
  10581. 'groupName': group['groupName'],
  10582. 'currencyGroup': group['currencyGroup']
  10583. })
  10584. groups.sort(key=itemgetter('currencyGroup'))
  10585. dataList = []
  10586. for currencyGroup, groups in groupby(groups, itemgetter('currencyGroup')):
  10587. dataList.append({
  10588. 'name': currencyGroup,
  10589. 'members': [{'id': group['groupId'], 'name': group['groupName']} for group in groups]
  10590. })
  10591. return JsonOkResponse(payload={
  10592. 'currencyMode': current_user.currency_mode,
  10593. 'total': len(dataList),
  10594. 'dataList': dataList[pageIndex * pageSize - pageSize: pageIndex * pageSize]
  10595. })
  10596. @permission_required(ROLE.dealer, ROLE.subaccount)
  10597. def updatCurrencyGroups(request):
  10598. """
  10599. 更新经销商通用组以及通用模式
  10600. :param request:
  10601. :return:
  10602. """
  10603. boss = request.user.myBoss # type: Dealer
  10604. payload = json.loads(request.body)
  10605. # 校验分组名字是否为'',否则会导致设置地址组通用(删除操作的时候)无法生效.
  10606. name_list = map(lambda x: x.get('name'), payload.get('groupList', None))
  10607. if name_list:
  10608. check_name = None
  10609. for name in name_list:
  10610. if name == check_name:
  10611. return JsonErrorResponse(description='分组名称不能相同')
  10612. else:
  10613. check_name = name
  10614. else:
  10615. pass
  10616. # 初始化之前的组
  10617. beforeDataList = payload.get('beforeDataList', [])
  10618. for groupInfo in beforeDataList:
  10619. group_ids = [ObjectId(group['id']) for group in groupInfo['members']]
  10620. Group.objects(id__in=group_ids,
  10621. ownerId=str(request.user.bossId)).update(currencyGroup='')
  10622. currencyMode = payload['currencyMode']
  10623. if boss.currencyMode != currencyMode:
  10624. boss.update(currencyMode=currencyMode)
  10625. Dealer.invalid_cache(str(boss.id))
  10626. share_group_list = payload['groupList']
  10627. for share_group in share_group_list:
  10628. share_name = share_group['name']
  10629. group_ids = [ObjectId(group['id']) for group in share_group['members']]
  10630. Group.objects(id__in=group_ids,
  10631. ownerId=str(request.user.bossId)).update(currencyGroup=share_name)
  10632. Group.invalid_group_cache(group_ids)
  10633. return JsonOkResponse()
  10634. @permission_required(ROLE.dealer)
  10635. def setSimChargeAuto(request):
  10636. dealerId = request.user.id
  10637. Device.get_collection().update({'ownerId':str(dealerId)}, {'$set':{'simChargeAuto':True}})
  10638. return JsonOkResponse()
  10639. @permission_required(ROLE .dealer)
  10640. def activeRentDevice(request):
  10641. """
  10642. 经销商主动激活出租设备
  10643. """
  10644. payload = json.loads(request.body)
  10645. logicalCode = payload.get("logicalCode")
  10646. if not logicalCode:
  10647. return JsonErrorResponse(u"激活失败")
  10648. device = Device.objects.get(logicalCode=logicalCode)
  10649. if not device:
  10650. return JsonErrorResponse(u"激活失败")
  10651. try:
  10652. device.active_rent()
  10653. except RentDeviceError as e:
  10654. return JsonErrorResponse(e.message)
  10655. return JsonOkResponse()
  10656. @permission_required(ROLE.dealer)
  10657. def getRentOrder(request):
  10658. """
  10659. 获取经销商所有的日租订单 从前往后
  10660. """
  10661. logicalCode = request.GET.get("logicalCode")
  10662. pageSize = request.GET.get("pageSize")
  10663. pageIndex = request.GET.get("pageIndex")
  10664. if not logicalCode:
  10665. return JsonErrorResponse(u"获取记录失败")
  10666. device = Device.objects.get(logicalCode=logicalCode)
  10667. if not device:
  10668. return JsonErrorResponse(u"获取记录失败")
  10669. orders = DeviceRentOrder.get_by_device(device)
  10670. dataList = [_.to_dict() for _ in orders]
  10671. return JsonOkResponse(payload={"total": orders.count(), "dataList": dataList})
  10672. @permission_required(ROLE.dealer)
  10673. def sendVirtualCard(request):
  10674. payload = json.loads(request.body)
  10675. openId = payload.get("openId")
  10676. groupId = payload.get("groupId")
  10677. cardId = payload.get("cardId")
  10678. vCard = VirtualCard.objects.filter(id=cardId).first()
  10679. if not vCard:
  10680. return JsonErrorResponse(description=u"未找到虚拟卡,请确认虚拟卡信息后重试")
  10681. user = MyUser.objects.filter(openId=openId, groupId=groupId).first()
  10682. if not user:
  10683. return JsonErrorResponse(description=u"未找到用户,请确认派卡地址是否正确")
  10684. userCard = UserVirtualCard(
  10685. cardNo=UserVirtualCard.make_no(),
  10686. cardTypeId=str(cardId),
  10687. openIds=[openId],
  10688. cardName=vCard.cardName,
  10689. ownerOpenId=openId,
  10690. nickname=user.nickname,
  10691. dealerId=vCard.ownerId,
  10692. groupIds=vCard.groupIds,
  10693. devTypeList=vCard.devTypeList,
  10694. price=vCard.price,
  10695. periodDays=vCard.periodDays,
  10696. expiredTime=datetime.datetime.now() + datetime.timedelta(seconds=vCard.periodDays * 24 * 3600),
  10697. dayQuota=vCard.dayQuota,
  10698. userLimit=vCard.userLimit,
  10699. quota=vCard.quota,
  10700. userDesc=vCard.userDesc,
  10701. managerialAppId=user.managerialOpenId,
  10702. managerialOpenId=user.managerialOpenId,
  10703. logicalCode="",
  10704. groupId=groupId
  10705. ).save()
  10706. return JsonOkResponse(description=u"发卡成功")
  10707. @permission_required(ROLE.dealer)
  10708. def stopUserOrder(request):
  10709. orderId = request.GET.get('orderId')
  10710. order = ClientConsumeModelProxy.get_one(id=orderId) # type: ConsumeRecord
  10711. if not order:
  10712. return JsonErrorResponse(description='未找到该笔订单')
  10713. if order.devTypeCode:
  10714. try:
  10715. from apps.web.core.models import DriverAdapter
  10716. adapter = DriverAdapter.get_driver_adapter(order.devTypeCode, None)
  10717. adapter.force_stop_order(order)
  10718. except:
  10719. order.update(isNormal=False, errorDesc='强制订单失败后, 直接更新订单')
  10720. return JsonOkResponse(description=u"停止成功")
  10721. else:
  10722. return JsonErrorResponse(description='强制停止失败')
  10723. @permission_required(ROLE.dealer, ROLE.subaccount)
  10724. def getConsumeTemplate(request):
  10725. """
  10726. 获取用户的消费信息 模板的配置
  10727. :param request:
  10728. :return:
  10729. """
  10730. owner = request.user.myBoss # type: Dealer
  10731. showList = owner.supportedConsumptionShow
  10732. if not showList:
  10733. from apps.web.common.utils import UserConsumeFilter
  10734. showList = UserConsumeFilter.default_filter()
  10735. return JsonOkResponse(payload = {"showList": showList})
  10736. @permission_required(ROLE.dealer, ROLE.subaccount)
  10737. def setConsumeTemplate(request):
  10738. """
  10739. 设置用户的参数
  10740. :param request:
  10741. :return:
  10742. """
  10743. dealerId = request.user.bossId
  10744. payload = json.loads(request.body)
  10745. try:
  10746. Dealer.objects.get(id=dealerId).update(supportedConsumptionShow=payload["showList"])
  10747. Dealer.invalid_cache(dealerId)
  10748. except DoesNotExist:
  10749. return JsonErrorResponse(u"参数错误, 请刷新重试")
  10750. except Exception as e:
  10751. logger.exception("update dealer <{}> supportedConsumptionShow error = {}".format(dealerId, e))
  10752. return JsonErrorResponse(u"参数错误, 请刷新重试")
  10753. return JsonOkResponse()
  10754. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"退款操作中出现异常,请联系客服处理"))
  10755. @permission_required(ROLE.dealer)
  10756. def refundOrder(request):
  10757. payload = json.loads(request.body)
  10758. logger.debug('dealer refund order. dealer: {}, payload: {}'.format(request.user, payload))
  10759. orderNo = payload.get("orderNo", None)
  10760. if not orderNo:
  10761. return JsonErrorResponse(description=u"参数错误,请刷新页面重试")
  10762. refundMoney = RMB(payload.get("refundMoney"))
  10763. deductCoins = VirtualCoin(payload.get("deductCoins"))
  10764. rechargeOrder = RechargeRecord.objects.filter(orderNo=orderNo).first() # type: RechargeRecord
  10765. if not rechargeOrder:
  10766. return JsonErrorResponse(description=u"未查询到订单,请刷新页面重试")
  10767. if not rechargeOrder.is_refund_available(request.user):
  10768. return JsonErrorResponse(description=u"该类型订单不支持退款")
  10769. if rechargeOrder.coins < deductCoins:
  10770. return JsonErrorResponse(description=u"扣除金币数大于用户实际购买数目")
  10771. currency = rechargeOrder.myuser.calc_currency_balance(rechargeOrder.owner, rechargeOrder.group)
  10772. if currency < deductCoins:
  10773. return JsonErrorResponse(description = u"扣除金币数大于用户目前余额")
  10774. if not rechargeOrder.is_success:
  10775. return JsonErrorResponse(description = u"退款失败,订单状态非成功,请联系平台客服")
  10776. if not rechargeOrder.is_ledgered:
  10777. # 检验订单是否有收益
  10778. return JsonErrorResponse(description=u"退款失败,订单未产生收益,请联系平台客服")
  10779. try:
  10780. refundedOrder = refund_cash(rechargeOrder, refundMoney, deductCoins)
  10781. return JsonOkResponse(description=u"退款成功", payload={"refundedOrderNo": refundedOrder.orderNo})
  10782. except ServiceException as e:
  10783. logger.error(e.result)
  10784. return JsonResponse(e.result)
  10785. except UserServerException as e:
  10786. logger.error(e.message)
  10787. return JsonErrorResponse(description=e.message)
  10788. except Exception as e:
  10789. return JsonErrorResponse(description=u"退款失败,请刷新后重试")
  10790. @permission_required(ROLE.dealer, ROLE.subaccount)
  10791. def getDealerTodoMessage(request):
  10792. """
  10793. 获取经代销商的代办事项
  10794. """
  10795. messages = TodoMessage.get_todo_message(request.user)
  10796. # 进行一次任务检查 查看任务是否完成以及是否需要强制执行
  10797. return JsonOkResponse(payload={"count": len(messages), "dataList": messages})
  10798. @permission_required(ROLE.dealer)
  10799. def saveUserBlackConfig(request):
  10800. dealerId = str(request.user.id)
  10801. payload = json.loads(request.body)
  10802. breakRuleTimes = payload.get('breakRuleTimes', 0)
  10803. orderRemindType = payload.get('orderRemindType', 2)
  10804. openId = payload.get('openId', '')
  10805. dealer = Dealer.objects(id=dealerId).first()
  10806. users = MyUser.objects(openId=openId, agentId=dealer.agentId)
  10807. if users.count() == 0:
  10808. return JsonErrorResponse(description=u"不存在的用户")
  10809. for _ in users:
  10810. _.blacklistConfig['breakRuleTimes'] = breakRuleTimes
  10811. _.blacklistConfig['orderRemindType'] = orderRemindType
  10812. try:
  10813. _.save()
  10814. except Exception as e:
  10815. return JsonErrorResponse(description=u"系统错误")
  10816. return JsonOkResponse(description=u"设置成功")
  10817. @permission_required(ROLE.dealer, ROLE.subaccount)
  10818. @ViewValidator(UserListValidator)
  10819. def userList(request, data):
  10820. groupId = data.get("groupId")
  10821. source = data.get("source")
  10822. reverse = data.get("reverse")
  10823. searchKey = data.get("searchKey")
  10824. pageSize = data.get("pageSize")
  10825. pageIndex = data.get("pageIndex")
  10826. userQuery = MyUser.objects.filter(groupId=groupId)
  10827. if source:
  10828. userQuery = userQuery.filter(gateway=source)
  10829. userQuery = userQuery.order_by("last_login") if reverse else userQuery.order_by("-last_login")
  10830. if re.match(r'1[3-9][0-9]{9}$', searchKey):
  10831. agent = Agent.objects.filter(id = str(request.user.myBoss.agentId)).first() # type: Agent
  10832. if agent.supports('user_identify'):
  10833. user = MyUser.objects(phoneNumber = searchKey).first()
  10834. if not user:
  10835. return JsonErrorResponse(description = u"未找到用户")
  10836. userQuery = userQuery.filter(openId = user.openId)
  10837. users = list(userQuery.paginate(pageIndex, pageSize))
  10838. else:
  10839. unique_user = UniqueUser.objects.filter(phone = searchKey).first() # type: UniqueUser
  10840. if not unique_user:
  10841. return JsonErrorResponse(description = u"未找到用户")
  10842. userQuery = userQuery.filter(openId = unique_user.openId)
  10843. users = list(userQuery.paginate(pageIndex, pageSize))
  10844. elif re.match(r'^[0-9]{5,10}$', searchKey):
  10845. unique_user = UniqueUser.objects.filter(userId = searchKey).first() # type: UniqueUser
  10846. if not unique_user:
  10847. return JsonErrorResponse(description = u"未找到用户")
  10848. userQuery = userQuery.filter(openId = unique_user.openId)
  10849. users = list(userQuery.paginate(pageIndex, pageSize))
  10850. else:
  10851. userQuery = userQuery.search(searchKey)
  10852. users = list(userQuery.paginate(pageIndex, pageSize))
  10853. # 获取用户默认头像
  10854. openIds = [str(_user.openId) for _user in users]
  10855. openId_2_uniId = {_.openId: _.userId for _ in UniqueUser.objects.filter(openId__in=openIds)}
  10856. dataList = list()
  10857. for _user in users: # type: MyUser
  10858. _userInfo = _user.to_dict()
  10859. _userInfo.update(
  10860. {
  10861. "dealerId": str(request.user.bossId),
  10862. "userId": openId_2_uniId.get(_user.openId, ""),
  10863. "id": str(_user.id)
  10864. }
  10865. )
  10866. dataList.append(_userInfo)
  10867. # 总量永远比数据量大于1 这样前端下拉只需要判断 当前的数量和pageSize的对比就行
  10868. total = pageIndex * pageSize + 1 if len(dataList) == pageSize else pageIndex * pageSize
  10869. return JsonResponse({
  10870. "result": 1,
  10871. "description": None,
  10872. "payload": {"total": total, "dataList": dataList}
  10873. })
  10874. @permission_required(ROLE.dealer, ROLE.subaccount)
  10875. def userDetail(request, openId):
  10876. # 获取所有用户的用户组
  10877. groupIds = Group.get_group_ids_of_dealer(str(request.user.bossId))
  10878. users = MyUser.objects.filter(openId=openId, groupId__in=groupIds).order_by("-last_login")
  10879. user = users.first()
  10880. try:
  10881. userId = UniqueUser.objects.get(openId=user.openId).userId
  10882. except DoesNotExist:
  10883. userId = ""
  10884. # 对于users 做累加和处理以及分列处理
  10885. payload = {
  10886. "userId": userId,
  10887. "avatar": user.avatar or Agent.get_agent(user.agentId).get("productLogo"),
  10888. "openId": openId,
  10889. "nickname": user.nickname,
  10890. "status": "black" if check_black_user(dealerId=str(request.user.bossId), openId=openId) else "white",
  10891. "phone": user.phone,
  10892. "total_recharge": RMB(0),
  10893. "total_balance": VirtualCoin(0),
  10894. "total_consume": VirtualCoin(0),
  10895. }
  10896. dataList = list()
  10897. for _user in users: # type: MyUser
  10898. _groupUserInfo = {
  10899. "groupId": _user.groupId,
  10900. "groupName": Group.get_group(_user.groupId).groupName,
  10901. "recharge": RMB(_user.total_recharged),
  10902. "consume": VirtualCoin(_user.total_consumed),
  10903. "balance": VirtualCoin(_user.balance)
  10904. }
  10905. dataList.append(_groupUserInfo)
  10906. payload["total_recharge"] += _groupUserInfo["recharge"]
  10907. payload["total_consume"] += _groupUserInfo["consume"]
  10908. payload["total_balance"] += _groupUserInfo["balance"]
  10909. payload["dataList"] = dataList
  10910. return JsonOkResponse(payload=payload)
  10911. @permission_required(ROLE.dealer, ROLE.subaccount)
  10912. def getPortsInfo(request):
  10913. logicalCode = request.GET.get('logicalCode')
  10914. dev = Device.get_dev_by_l(logicalCode)
  10915. smartBox = dev.deviceAdapter
  10916. portList = smartBox.get_ports_info()
  10917. portList = sorted(portList, key=lambda _: int(_['index']))
  10918. if dev.support_power_graph and 'showPG_in_port_detail' in dev.owner.features:
  10919. for item in portList:
  10920. item['showPG'] = True
  10921. return JsonOkResponse(payload={'portList': portList})
  10922. @permission_required(ROLE.dealer, ROLE.subaccount)
  10923. def getDevicePortDetail(request):
  10924. logicalCode = request.GET.get('logicalCode')
  10925. portIndex = request.GET.get('portIndex')
  10926. dev = Device.get_dev_by_l(logicalCode)
  10927. smartBox = dev.deviceAdapter
  10928. ctrInfo = Device.get_dev_control_cache(dev.devNo)
  10929. payload = smartBox.get_port_using_detail(portIndex, ctrInfo)
  10930. if dev.support_power_graph and 'showPG_in_port_detail' in dev.owner.features:
  10931. payload['showPG'] = True
  10932. payload['index'] = portIndex
  10933. return JsonOkResponse(payload=payload)
  10934. @permission_required(ROLE.dealer, ROLE.subaccount)
  10935. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取失败"))
  10936. def getDealerSwitch(request, category):
  10937. """
  10938. 两级联动开关 经销商的开关获取
  10939. """
  10940. bossId = str(request.user.bossId)
  10941. try:
  10942. dealer = Dealer.objects.get(id=bossId)
  10943. except DoesNotExist:
  10944. return JsonErrorResponse(u"获取配置失败")
  10945. payload = dealer.get_linkage_switch()
  10946. return JsonOkResponse(payload=payload)
  10947. @permission_required(ROLE.dealer, ROLE.subaccount)
  10948. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取失败"))
  10949. def getGroupSwitch(request, category):
  10950. """
  10951. 两级联动开关 地质组的开关获取
  10952. """
  10953. bossId = str(request.user.bossId)
  10954. pageIndex = int(request.GET.get("pageIndex"))
  10955. pageSize = int(request.GET.get("pageSize"))
  10956. try:
  10957. groups = Group.objects.filter(ownerId=bossId)
  10958. except DoesNotExist:
  10959. return JsonErrorResponse(u"获取配置失败")
  10960. offset = (pageIndex - 1) * pageSize
  10961. total = groups.count()
  10962. dataList = list()
  10963. for _group in groups[offset: offset + pageSize]: # type: Group
  10964. _switches = _group.get_linkage_switch()
  10965. _switches.update({"name": _group.groupName, "groupId": str(_group.id)})
  10966. dataList.append(_switches)
  10967. payload = {
  10968. "total": total,
  10969. "dataList": dataList
  10970. }
  10971. return JsonOkResponse(payload=payload)
  10972. @permission_required(ROLE.dealer, ROLE.subaccount)
  10973. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  10974. def setDealerSwitch(request, category):
  10975. """
  10976. 两级联动开关 设置经销商开关
  10977. """
  10978. bossId = str(request.user.bossId)
  10979. try:
  10980. dealer = Dealer.objects.get(id=bossId)
  10981. except DoesNotExist:
  10982. return JsonErrorResponse(u"设置失败")
  10983. payload = json.loads(request.body)
  10984. switch = payload["switch"]
  10985. if switch:
  10986. result = dealer.turn_on(category)
  10987. else:
  10988. result = dealer.turn_off(category)
  10989. return JsonOkResponse() if result else JsonErrorResponse(description=u"设置开关失败,请联系平台客服")
  10990. @permission_required(ROLE.dealer, ROLE.subaccount)
  10991. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  10992. def setGroupSwitch(request, category):
  10993. """
  10994. 两级联动开关 设置地质组开关 单个
  10995. """
  10996. bossId = str(request.user.bossId)
  10997. payload = json.loads(request.body)
  10998. groupId = payload["groupId"]
  10999. switch = payload["switch"]
  11000. try:
  11001. group = Group.objects.get(id=groupId, ownerId=bossId)
  11002. except DoesNotExist:
  11003. return JsonErrorResponse(u"设置失败")
  11004. logger.error(group.id)
  11005. if switch:
  11006. group.turn_on(category)
  11007. else:
  11008. group.turn_off(category)
  11009. return JsonOkResponse()
  11010. @permission_required(ROLE.dealer)
  11011. def getServiceChargeModelPara(request):
  11012. """
  11013. 获取服务费模式参数
  11014. :param request:
  11015. :return:
  11016. """
  11017. payload = json.loads(request.body)
  11018. logicalCode = payload.get("logicalCode")
  11019. if isinstance(logicalCode, list) and len(logicalCode):
  11020. logicalCode = logicalCode[0]
  11021. else:
  11022. raise JsonErrorResponse(description=u"无效的设备编号")
  11023. device = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  11024. if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING]:
  11025. serviceChargeModelPara = device.bill_as_service_feature
  11026. if 'half_hour_price_list' or 'top_price_rate' or 'peak_price_rate' or 'normal_price_rate' or 'valley_price_rate' \
  11027. not in device.bill_as_service_feature['elecCharge']:
  11028. return JsonResponse({"result": 1, "description": "", "payload": device.bill_as_service_feature})
  11029. half_hour_price_list = serviceChargeModelPara['elecCharge']['half_hour_price_list']
  11030. nowTime = datetime.datetime.now().strftime('%H:%M')
  11031. timeNowList = nowTime.split(':')
  11032. index = int(timeNowList[0]) * 2 + 2 if int(timeNowList[1]) > 30 else 1 - 1
  11033. currentElecChargeRate = half_hour_price_list['half_hour_price_list'][index]
  11034. if currentElecChargeRate == 'top_price_rate':
  11035. elecCharge = serviceChargeModelPara['elecCharge']['top_price_rate']
  11036. elif currentElecChargeRate == 'peak_price_rate':
  11037. elecCharge = serviceChargeModelPara['elecCharge']['peak_price_rate']
  11038. elif currentElecChargeRate == 'normal_price_rate':
  11039. elecCharge = serviceChargeModelPara['elecCharge']['normal_price_rate']
  11040. elif currentElecChargeRate == 'valley_price_rate':
  11041. elecCharge = serviceChargeModelPara['elecCharge']['valley_price_rate']
  11042. bill_as_service_feature = {
  11043. 'on':device.bill_as_service_feature['on'],
  11044. 'elecCharge':elecCharge,
  11045. 'serviceCharge':device.bill_as_service_feature['service_charge']
  11046. }
  11047. return JsonResponse({"result": 1, "description": "", "payload": bill_as_service_feature})
  11048. return JsonResponse({"result": 1, "description": "", "payload": device.bill_as_service_feature})
  11049. @permission_required(ROLE.dealer, ROLE.subaccount)
  11050. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11051. def setServiceChargeModelPara(request):
  11052. payload = json.loads(request.body)
  11053. logicalCode = payload.get("logicalCode")
  11054. if isinstance(logicalCode, list) and len(logicalCode):
  11055. logicalCode = logicalCode[0]
  11056. else:
  11057. return JsonErrorResponse(description=u"错误的二维码编号")
  11058. elecCharge = payload.get("elecCharge")
  11059. serviceCharge = payload.get("serviceCharge")
  11060. device = Device.get_dev_by_l(logicalCode)
  11061. devNo = device['devNo']
  11062. # if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING]:
  11063. # from apps.web.core.adapter.dianchuan_CarCharging import DianchuanCarCharging
  11064. # device = DianchuanCarCharging(device)
  11065. # device.set_elec_charge_by_dealer(elecCharge)
  11066. # elecChargeDict = {
  11067. # 'top_price_rate' : elecCharge,
  11068. # 'peak_price_rate' : elecCharge,
  11069. # 'normal_price_rate' : elecCharge,
  11070. # 'valley_price_rate' : elecCharge,
  11071. # 'half_hour_price_list' : ['top_price_rate'] * 48,
  11072. # }
  11073. # Device.get_collection().update_one({'devNo': devNo}, {
  11074. # '$set': {
  11075. # 'devType.features.billAsService.elecCharge': elecChargeDict,
  11076. # 'devType.features.billAsService.serviceCharge': serviceCharge
  11077. # }
  11078. # })
  11079. # Device.invalid_device_cache(devNo)
  11080. # return JsonOkResponse()
  11081. Device.get_collection().update_one({'devNo': devNo}, {
  11082. '$set': {
  11083. 'devType.features.billAsService.elecCharge': elecCharge,
  11084. 'devType.features.billAsService.serviceCharge': serviceCharge
  11085. }
  11086. })
  11087. Device.invalid_device_cache(devNo)
  11088. return JsonOkResponse()
  11089. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11090. @permission_required(ROLE.dealer, ROLE.subaccount)
  11091. def getApiInfo(request):
  11092. """
  11093. 获取首页的配额相关数据
  11094. """
  11095. dealer = request.user.myBoss # type: Dealer
  11096. payload = dealer.api_quota_info
  11097. return JsonOkResponse(payload=payload)
  11098. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11099. @permission_required(ROLE.dealer, ROLE.subaccount)
  11100. def getApiAppInfo(request):
  11101. """
  11102. 获取经销上API注册信息
  11103. """
  11104. dealer = request.user.myBoss # type: Dealer
  11105. apiAppInfo = dealer.api_app # type: ApiAppInfo
  11106. return JsonOkResponse(payload={
  11107. 'people': apiAppInfo.people,
  11108. 'tel': apiAppInfo.tel,
  11109. 'callbackUrl': apiAppInfo.callbackUrl,
  11110. 'apiDeviceMax': apiAppInfo.apiDeviceMax
  11111. })
  11112. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11113. @permission_required(ROLE.dealer, ROLE.subaccount)
  11114. def saveApiAppInfo(request):
  11115. """
  11116. 编辑经销上API注册信息
  11117. """
  11118. def check_url(url):
  11119. return re.match(r'^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+', url)
  11120. dealer = request.user.myBoss # type: Dealer
  11121. payload = json.loads(request.body)
  11122. people = payload.get('people')
  11123. tel = payload.get('tel')
  11124. callbackUrl = payload.get('callbackUrl')
  11125. if callbackUrl and not check_url(callbackUrl):
  11126. return JsonErrorResponse(description='回调地址Url填写错误')
  11127. dealer.update_api_app(**{
  11128. 'people': people,
  11129. 'tel': tel,
  11130. 'callbackUrl': callbackUrl
  11131. })
  11132. return JsonOkResponse()
  11133. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11134. @permission_required(ROLE.dealer, ROLE.subaccount)
  11135. def getApiDevice(request):
  11136. """
  11137. 获取经销商的设备列表
  11138. """
  11139. dealerId = request.user.bossId # type: Dealer
  11140. groups = Group.get_group_ids_of_dealer(dealerId)
  11141. groupList = []
  11142. for groupId in groups:
  11143. group = Group.get_group(groupId) # type : GroupDict
  11144. devDict = Device.get_devices_by_group([groupId]) # type:Mapping[DeviceDict]
  11145. if devDict:
  11146. devs = devDict.values()
  11147. groupList.append({
  11148. 'groupName': group['groupName'],
  11149. 'devList': map(lambda _: {'title': '{}_{}'.format(_.devTypeName, _.logicalCode), 'isApi': _.isApi,
  11150. 'logicalCode': _.logicalCode}, devs)
  11151. })
  11152. return JsonOkResponse(payload={'groupList': groupList})
  11153. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11154. @permission_required(ROLE.dealer, ROLE.subaccount)
  11155. def editApiDevice(request):
  11156. """
  11157. 经销商选择api设备
  11158. """
  11159. dealer = request.user.myBoss # type: Dealer
  11160. payload = json.loads(request.body)
  11161. groupList = payload.get('groupList')
  11162. logicalCodes = []
  11163. for item in groupList:
  11164. logicalCodes += item['devList']
  11165. # 找出经销商的全部设备
  11166. groups = Group.get_group_ids_of_dealer(str(dealer.id))
  11167. devDict = Device.get_devices_by_group(groups)
  11168. allList = map(lambda _: _.logicalCode, devDict.values())
  11169. # 找出经销商操作的设备
  11170. trunOnList = map(lambda _: _['logicalCode'], filter(lambda _: _['isApi'] == True, logicalCodes))
  11171. trunOnCount = len(trunOnList)
  11172. if set(trunOnList) - set(allList):
  11173. return JsonErrorResponse(description='非法操作!!! 无法操作其他人的设备')
  11174. apiInfo = dealer.api_app # type: ApiAppInfo
  11175. apiDeviceMax = apiInfo.apiDeviceMax
  11176. if trunOnCount > apiDeviceMax:
  11177. return JsonResponse({'result': 1001, 'description': '经销商API设备配额不足,请购买API设备配额',
  11178. 'payload': {'needQuota': trunOnCount - apiDeviceMax}})
  11179. # 此编辑操作为 关闭此经销商的全部设备 然后开启经销商选中的
  11180. Device.switch_api_mode(allList, isApi=False)
  11181. Device.switch_api_mode(trunOnList, isApi=True)
  11182. return JsonOkResponse()
  11183. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11184. @permission_required(ROLE.dealer, ROLE.subaccount)
  11185. def createQuotaOrder(request):
  11186. dealer = request.user.myBoss # type: Dealer
  11187. payload = json.loads(request.body)
  11188. needQuota = payload.get('needQuota')
  11189. groupList = payload.get('groupList')
  11190. buyType = payload.get('buyType')
  11191. package = payload.get('package', {})
  11192. logicalCodes = []
  11193. if buyType == 'temporary': # 配置设备的时候临时购买
  11194. for item in groupList:
  11195. logicalCodes += item['devList']
  11196. # 找出经销商的全部设备
  11197. groups = Group.get_group_ids_of_dealer(str(dealer.id))
  11198. devDict = Device.get_devices_by_group(groups)
  11199. # 找出经销商操作的设备
  11200. trunOnList = map(lambda _: _['logicalCode'], filter(lambda _: _['isApi'] == True, logicalCodes))
  11201. trunOnCount = len(trunOnList)
  11202. if set(trunOnList) - set(map(lambda _: _.logicalCode, devDict.values())):
  11203. return JsonErrorResponse(description='非法操作!!! 无法操作其他人的设备')
  11204. apiInfo = dealer.api_app # type: ApiAppInfo
  11205. apiDeviceMax = apiInfo.apiDeviceMax
  11206. if trunOnCount - apiDeviceMax <= 0:
  11207. return JsonErrorResponse(description='参数传入有误, 请稍后重试!')
  11208. if trunOnCount - apiDeviceMax != int(needQuota):
  11209. return JsonErrorResponse(description='参数传入有误, 请稍后重试..')
  11210. payload = {
  11211. 'needQuota': needQuota,
  11212. 'trunOnList': trunOnList,
  11213. 'buyType': buyType
  11214. }
  11215. elif buyType == 'package': # 套餐购买页面过来
  11216. payload = {
  11217. 'needQuota': package.get('quota', 1),
  11218. 'trunOnList': [],
  11219. 'buyType': buyType,
  11220. 'package': package
  11221. }
  11222. else:
  11223. return JsonErrorResponse(description='参数传入错误, 请稍后从试')
  11224. # 创建订单
  11225. record = create_dealer_charge_order_for_api(dealer, **payload)
  11226. if record:
  11227. return JsonResponse({'result': 1, 'description': u'创建订单成功', 'payload':{'orderNo':record.orderNo}})
  11228. else:
  11229. return JsonErrorResponse(u'创建订单异常失败')
  11230. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11231. @permission_required(ROLE.dealer, ROLE.subaccount)
  11232. def getQuotaDiscountPackage(request):
  11233. dealer = request.user.myBoss # type: Dealer
  11234. apiInfo = dealer.api_app # type: ApiAppInfo
  11235. unitPrice = apiInfo.apiDevicePerCost
  11236. payload = {
  11237. "unitPrice": unitPrice,
  11238. "discountList": [
  11239. {
  11240. "id": 1,
  11241. "price": unitPrice * 10,
  11242. "quota": 10
  11243. },
  11244. {
  11245. "id": 2,
  11246. "price": unitPrice * 20,
  11247. "quota": 20
  11248. },
  11249. {
  11250. "id": 3,
  11251. "price": unitPrice * 40,
  11252. "quota": 40
  11253. },
  11254. {
  11255. "id": 4,
  11256. "price": unitPrice * 100,
  11257. "quota": 100
  11258. }
  11259. ]
  11260. }
  11261. return JsonOkResponse(payload=payload)
  11262. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11263. @permission_required(ROLE.dealer, ROLE.subaccount)
  11264. def getDisableAdInfo(request):
  11265. """
  11266. 获取首页的配额相关数据
  11267. """
  11268. dealer = request.user.myBoss # type: Dealer
  11269. payload = dealer.disable_ad_quota_info()
  11270. return JsonOkResponse(payload=payload)
  11271. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11272. @permission_required(ROLE.dealer, ROLE.subaccount)
  11273. def getDisableAdDevice(request):
  11274. dealerId = request.user.bossId # type: Dealer
  11275. groups = Group.get_group_ids_of_dealer(dealerId)
  11276. groupList = []
  11277. now = datetime.datetime.now()
  11278. def _filter(dev):
  11279. formart_dict = {
  11280. 'title': '{}_{}'.format(dev.devTypeName, dev.logicalCode),
  11281. 'logicalCode': dev.logicalCode,
  11282. 'expiredTime':None
  11283. }
  11284. if dev.disableADExpireDate and dev.disableADExpireDate > now:
  11285. formart_dict.update({
  11286. 'expiredTime': dev.disableADExpireDate.strftime("%Y-%m-%d %H:%M:%S")
  11287. })
  11288. return formart_dict
  11289. for groupId in groups:
  11290. group = Group.get_group(groupId) # type : GroupDict
  11291. devDict = Device.get_devices_by_group([groupId]) # type:Mapping[DeviceDict]
  11292. if devDict:
  11293. devs = devDict.values()
  11294. groupList.append({
  11295. 'groupName': group['groupName'],
  11296. 'devList': map(_filter, devs)
  11297. })
  11298. return JsonOkResponse(payload={'groupList': groupList})
  11299. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11300. @permission_required(ROLE.dealer, ROLE.subaccount)
  11301. def DisableAdDeviceRecharge(request):
  11302. payload = json.loads(request.body)
  11303. groupList = payload.get('groupList', [])
  11304. devList = []
  11305. for item in groupList:
  11306. devList += item.get('devList', [])
  11307. configuredList = filter(lambda _: _['configured'] == True, devList)
  11308. payInfo = []
  11309. total = 0
  11310. totalMoney = RMB(0)
  11311. for item in configuredList:
  11312. dev = Device.get_dev_by_l(item.get('logicalCode'))
  11313. if not dev:
  11314. continue
  11315. payInfo.append({
  11316. 'title': item.get('title'),
  11317. 'logicalCode':dev.logicalCode,
  11318. 'expireDate': dev.disableADExpireDate,
  11319. 'money': dev.owner.disable_ad_plan.disableAdCost.mongo_amount,
  11320. 'cycle': dev.owner.disable_ad_plan.cycle
  11321. })
  11322. total += 1
  11323. totalMoney += dev.owner.disable_ad_plan.disableAdCost
  11324. return JsonOkResponse(payload={'devList': payInfo, 'total':total, 'totalMoney':totalMoney.mongo_amount})
  11325. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11326. @permission_required(ROLE.dealer, ROLE.subaccount)
  11327. def createDisableAdOrder(request):
  11328. dealer = request.user.myBoss # type: Dealer
  11329. payload = json.loads(request.body)
  11330. buyType = payload.get('buyType')
  11331. devList = payload.get('devList', {})
  11332. logicalCodes = []
  11333. if buyType != 'temporary': # 配置设备的时候临时购买
  11334. return JsonErrorResponse(description='参数传入错误, 请稍后从试')
  11335. for item in devList:
  11336. logicalCodes.append(item['logicalCode'])
  11337. # 找出经销商的全部设备
  11338. devs = Device.get_devs_by_ownerId(str(dealer.id))
  11339. # 找出经销商将要操作的设备
  11340. if set(logicalCodes) - set(map(lambda _: _.logicalCode, devs)):
  11341. return JsonErrorResponse(description='非法操作!!! 无法操作其他人的设备')
  11342. # 创建订单
  11343. record = create_dealer_charge_order_for_disable_ad(dealer, devList)
  11344. if record:
  11345. return JsonResponse({'result': 1, 'description': u'创建订单成功', 'payload':{'orderNo':record.orderNo}})
  11346. else:
  11347. return JsonErrorResponse(u'创建订单异常失败')
  11348. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11349. @permission_required(ROLE.dealer, ROLE.subaccount)
  11350. def getServerFunction(request):
  11351. payload = json.loads(request.body)
  11352. lc = payload.get("logicalCode")
  11353. if isinstance(lc, list) and len(lc):
  11354. lc = lc[0]
  11355. else:
  11356. raise JsonErrorResponse(description=u"无效的设备编号")
  11357. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  11358. if not dev:
  11359. return JsonResponse({'result': 0, 'description': u'未找到该设备', 'payload': {}})
  11360. setConf = dev.deviceAdapter.get_server_setting()
  11361. if setConf is None:
  11362. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  11363. else:
  11364. return JsonResponse({'result': 1, 'description': u'', 'payload': setConf})
  11365. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11366. @permission_required(ROLE.dealer, ROLE.subaccount)
  11367. def setServerFunction(request):
  11368. payload = json.loads(request.body)
  11369. # 去掉多余的参数
  11370. payload.pop('groupId', None)
  11371. logicalCodes = payload.pop('logicalCode')
  11372. if len(logicalCodes) > 1:
  11373. dev = Device.get_dev_by_l(logicalCodes[0]) # type: DeviceDict
  11374. payload = {
  11375. 'operator': {
  11376. 'id': str(request.user.id),
  11377. 'role': request.user.role,
  11378. 'username': request.user.username
  11379. },
  11380. 'logicalCodes': logicalCodes,
  11381. 'payload': payload,
  11382. 'ownerId': dev.ownerId,
  11383. 'devTypeCode': dev.devTypeCode,
  11384. 'operationId': 'server_setting_{}_{}'.format(str(request.user.id), int(time.time()))
  11385. }
  11386. from taskmanager.mediator import task_caller
  11387. task_caller('batch_set_server_settings', **payload)
  11388. return JsonResponse({'result': 1, 'description': None, 'payload': {'operationId': payload['operationId']}})
  11389. else:
  11390. device = Device.get_dev_by_l(logicalCodes[0]) # type: DeviceDict
  11391. if not device:
  11392. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  11393. if device.ownerId != str(request.user.bossId):
  11394. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  11395. try:
  11396. before = device.deviceAdapter.get_server_setting()
  11397. device.deviceAdapter.set_server_setting(payload)
  11398. OperatorLog.log_dev_operation(
  11399. operator=request.user,
  11400. device=device,
  11401. operator_name='setServerSetting',
  11402. content={
  11403. 'before': before, 'after': payload
  11404. })
  11405. except InvalidParameter as e:
  11406. return JsonErrorResponse(description=e.message)
  11407. return JsonOkResponse()
  11408. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11409. @permission_required(ROLE.dealer, ROLE.subaccount)
  11410. def getDealerPreferentialRechargeTemplate(request):
  11411. ownerId = str(request.user.bossId)
  11412. pageIndex = int(request.GET.get('pageIndex', 1))
  11413. pageSize = int(request.GET.get('pageSize', 10))
  11414. templateType = str(request.GET.get('type'))
  11415. dealer = Dealer.objects(id=ownerId).first()
  11416. if dealer is None:
  11417. return JsonErrorResponse(description=u'未知错误')
  11418. if templateType == 'preferentialRechargeTemplate':
  11419. dataList = dealer.templateSet.rechargeDiscount
  11420. elif templateType == 'cardPreferentialRechargeTemplate':
  11421. dataList = dealer.templateSet.cardRechargeDiscount
  11422. else:
  11423. return JsonErrorResponse(description=u"未知错误")
  11424. payload = {
  11425. "total": len(dataList),
  11426. "dataList": dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  11427. }
  11428. return JsonOkResponse(payload=payload)
  11429. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11430. @permission_required(ROLE.dealer, ROLE.subaccount)
  11431. def getDealerPreferentialRechargeTemplateById(request):
  11432. ownerId = str(request.user.bossId)
  11433. templateId = request.GET.get('id', None)
  11434. templateType = str(request.GET.get('type'))
  11435. if templateId is None:
  11436. return JsonErrorResponse(description=u'未知错误')
  11437. dealer = Dealer.objects(id=ownerId).first()
  11438. if dealer is None:
  11439. return JsonErrorResponse(description=u'未知错误')
  11440. if templateType == 'preferentialRechargeTemplate':
  11441. dataList = dealer.templateSet.rechargeDiscount
  11442. elif templateType == 'cardPreferentialRechargeTemplate':
  11443. dataList = dealer.templateSet.cardRechargeDiscount
  11444. else:
  11445. return JsonErrorResponse(description=u"未知错误")
  11446. payload = [_ for _ in dataList if int(templateId) == int(_['id'])][0]
  11447. return JsonOkResponse(payload=payload)
  11448. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11449. @permission_required(ROLE.dealer, ROLE.subaccount)
  11450. def editDealerPreferentialRechargeTemplate(request):
  11451. ownerId = str(request.user.bossId)
  11452. tempData = json.loads(request.body)
  11453. templateType = tempData['type']
  11454. del tempData['type']
  11455. dealer = Dealer.objects(id=ownerId).first()
  11456. if dealer is None:
  11457. return JsonErrorResponse(description=u'未知错误')
  11458. if templateType == 'preferentialRechargeTemplate':
  11459. tempDataList = dealer.templateSet.rechargeDiscount
  11460. elif templateType == 'cardPreferentialRechargeTemplate':
  11461. tempDataList = dealer.templateSet.cardRechargeDiscount
  11462. else:
  11463. return JsonErrorResponse(description=u"未知错误")
  11464. for _ in tempDataList:
  11465. if int(_['id']) == int(tempData['id']):
  11466. tempDataList.remove(_)
  11467. tempDataList.append(tempData)
  11468. if templateType == 'preferentialRechargeTemplate':
  11469. dealer.templateSet.rechargeDiscount = tempDataList
  11470. else:
  11471. dealer.templateSet.cardRechargeDiscount = tempDataList
  11472. dealer.save()
  11473. return JsonOkResponse()
  11474. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11475. @permission_required(ROLE.dealer, ROLE.subaccount)
  11476. def addDealerPreferentialRechargeTemplate(request):
  11477. ownerId = str(request.user.bossId)
  11478. payload = json.loads(request.body)
  11479. templateType = payload['type']
  11480. dealer = Dealer.objects(id=ownerId).first()
  11481. if dealer is None:
  11482. return JsonErrorResponse(description=u'未知错误')
  11483. if templateType == 'preferentialRechargeTemplate':
  11484. tempDataList = dealer.templateSet.rechargeDiscount
  11485. elif templateType == 'cardPreferentialRechargeTemplate':
  11486. tempDataList = dealer.templateSet.cardRechargeDiscount
  11487. else:
  11488. return JsonErrorResponse(description=u"未知错误")
  11489. if len(tempDataList) == 0:
  11490. tempId = 1
  11491. else:
  11492. tempId = max(int(_['id']) for _ in tempDataList) + 1
  11493. temp = {}
  11494. templateInfo = payload.get('templateInfo', [])
  11495. templateName = payload.get('templateName', '')
  11496. if not templateInfo or templateName == '':
  11497. return JsonErrorResponse(description=u'套餐错误')
  11498. for _ in templateInfo:
  11499. _['coins'] = float(_['coins'])
  11500. _['ruleId'] = _['payAmount']
  11501. temp.update({'templateName': templateName, 'templateInfo': templateInfo, 'id': tempId})
  11502. if templateType == 'preferentialRechargeTemplate':
  11503. dealer.templateSet.rechargeDiscount.append(temp)
  11504. else:
  11505. dealer.templateSet.cardRechargeDiscount.append(temp)
  11506. dealer.save()
  11507. return JsonOkResponse()
  11508. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11509. @permission_required(ROLE.dealer, ROLE.subaccount)
  11510. def deleteDealerPreferentialRechargeTemplate(request):
  11511. ownerId = str(request.user.bossId)
  11512. payload = json.loads(request.body)
  11513. tempId = payload['id']
  11514. templateType = payload['type']
  11515. dealer = Dealer.objects(id=ownerId).first()
  11516. if dealer is None:
  11517. return JsonErrorResponse(description=u'未知错误')
  11518. if templateType == 'preferentialRechargeTemplate':
  11519. tempDataList = dealer.templateSet.rechargeDiscount
  11520. elif templateType == 'cardPreferentialRechargeTemplate':
  11521. tempDataList = dealer.templateSet.cardRechargeDiscount
  11522. else:
  11523. return JsonErrorResponse(description=u"未知错误")
  11524. for _ in tempDataList:
  11525. if int(_['id']) == int(tempId):
  11526. tempDataList.remove(_)
  11527. if templateType == 'preferentialRechargeTemplate':
  11528. dealer.templateSet.rechargeDiscount = tempDataList
  11529. else:
  11530. dealer.templateSet.cardRechargeDiscount = tempDataList
  11531. dealer.save()
  11532. return JsonOkResponse()
  11533. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11534. @permission_required(ROLE.dealer, ROLE.subaccount)
  11535. def editGroupsToPreferentialRechargeTemplate(request):
  11536. ownerId = str(request.user.bossId)
  11537. payload = json.loads(request.body)
  11538. tempId = payload['id']
  11539. templateType = payload['type']
  11540. groupIds = [_['groupId'] for _ in payload['groupId']]
  11541. dealer = Dealer.objects(id=ownerId).first()
  11542. if dealer is None:
  11543. return JsonErrorResponse(description=u'未知错误')
  11544. tempData = dict()
  11545. if templateType == 'preferentialRechargeTemplate':
  11546. tempDataList = dealer.templateSet.rechargeDiscount
  11547. elif templateType == 'cardPreferentialRechargeTemplate':
  11548. tempDataList = dealer.templateSet.cardRechargeDiscount
  11549. else:
  11550. return JsonErrorResponse(description=u"未知错误")
  11551. for _ in tempDataList:
  11552. if int(_['id']) == int(tempId):
  11553. tempData = _
  11554. break
  11555. tempRule = dict()
  11556. for _ in tempData['templateInfo']:
  11557. tempRule.update({_['payAmount']: _['coins']})
  11558. if templateType == 'preferentialRechargeTemplate':
  11559. for _ in Group.objects(id__in=groupIds):
  11560. _.ruleDict = format_dot_key(tempRule)
  11561. _.save()
  11562. else:
  11563. for _ in Group.objects(id__in=groupIds):
  11564. _.cardRuleDict = format_dot_key(tempRule)
  11565. _.save()
  11566. GroupCacheMgr.invalid_group_cache(groupIds)
  11567. return JsonOkResponse()
  11568. @permission_required(ROLE.dealer, ROLE.subaccount)
  11569. def getServiceFeePackage(request):
  11570. logicalCode = request.GET.get('logicalCode')
  11571. if not logicalCode:
  11572. raise JsonErrorResponse(description=u'无效的设备编号')
  11573. dev = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  11574. payload = dev.deviceAdapter.get_service_fee_info()
  11575. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  11576. @permission_required(ROLE.dealer, ROLE.subaccount)
  11577. def setServiceFeePackage(request):
  11578. """
  11579. 设置服务费计费参数, 暂时不支持批量
  11580. :param request:
  11581. :return:
  11582. """
  11583. payload = json.loads(request.body)
  11584. if 'billAsService' not in payload:
  11585. return JsonErrorResponse(description=u'传入参数错误')
  11586. logicalCode = payload.get("logicalCode")
  11587. try:
  11588. device = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  11589. device.deviceAdapter.set_service_fee_info(payload)
  11590. except InvalidParameter as e:
  11591. return JsonErrorResponse(description=e.message)
  11592. return JsonOkResponse()
  11593. @permission_required(ROLE.dealer)
  11594. def interconnectionConfig(request):
  11595. ownerId = str(request.user.bossId)
  11596. pageIndex = int(request.GET.get('pageIndex', 1))
  11597. pageSize = int(request.GET.get('pageSize', 10))
  11598. searchKey = str(request.GET.get('searchKey', ''))
  11599. swapFlagSearch = None
  11600. if 'swapFlag' in request.GET:
  11601. if request.GET.get('swapFlag') == 'false':
  11602. swapFlagSearch = False
  11603. else:
  11604. swapFlagSearch = True
  11605. dataList = []
  11606. groupIds = Group.get_group_ids_of_dealer(ownerId)
  11607. groupList = Group.get_groups_by_group_ids(groupIds).values()
  11608. groupList = natural_sort(groupList, 'groupName', False)
  11609. for grp in groupList:
  11610. if searchKey not in grp['groupName']:
  11611. continue
  11612. if swapFlagSearch is not None and swapFlagSearch != grp.get('swapFlag', False):
  11613. continue
  11614. if 'swapFlag' not in grp:
  11615. grp['swapFlag'] = False
  11616. elif grp['swapFlag']:
  11617. swapInfo = SwapGroup.objects(groupId=grp['groupId']).first()
  11618. if swapInfo is not None:
  11619. grp['joinedTime'] = swapInfo.joinedTime.strftime('%Y-%m-%d %H:%M:%S')
  11620. dataList.append(grp)
  11621. return JsonResponse({
  11622. "result": 1,
  11623. "description": None,
  11624. 'payload': {
  11625. "total": len(dataList),
  11626. "dataList": dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  11627. }
  11628. })
  11629. @permission_required(ROLE.dealer)
  11630. def interconnectionDetail(request):
  11631. ownerId = str(request.user.bossId)
  11632. groupId = request.GET.get('groupId', None)
  11633. if groupId is None:
  11634. return JsonErrorResponse(description=u"缺少参数")
  11635. swapInfo = SwapGroup.objects(groupId=groupId).first()
  11636. if swapInfo is None:
  11637. return JsonOkResponse(payload={})
  11638. if ownerId != swapInfo.ownerId:
  11639. return JsonErrorResponse(description=u"参数不一致")
  11640. payload = {
  11641. 'StationLng':swapInfo.lng,
  11642. 'StationLat':swapInfo.lat,
  11643. 'BusineHours':swapInfo.BusineHours,
  11644. 'SiteGuide':swapInfo.SiteGuide,
  11645. 'Construction':swapInfo.Construction,
  11646. 'SupportOrder':swapInfo.SupportOrder,
  11647. 'Pictures':[{'PicID':pic.PicID, 'IsCover':pic.IsCover, 'Url':pic.Url, 'title':pic.Title, 'Title':pic.TitleForShow} for pic in swapInfo.Pictures],
  11648. 'MatchCars':swapInfo.MatchCars,
  11649. 'ParkInfo':swapInfo.ParkInfo,
  11650. 'StationStatus':swapInfo.StationStatus,
  11651. 'ParkNums':swapInfo.ParkNums,
  11652. 'originalAlternateFeeRemark':swapInfo.originalAlternateFeeRemark,
  11653. 'alternateFeeRemark':swapInfo.alternateFeeRemark,
  11654. 'originalDirectFeeRemark':swapInfo.originalDirectFeeRemark,
  11655. 'directFeeRemark':swapInfo.directFeeRemark,
  11656. 'PriceChargingInfo':[{'FeeTime':info.FeeTime, 'ElectricityFee':info.ElectricityFee, 'ServiceFee':info.ServiceFee} for info in swapInfo.PriceChargingInfo],
  11657. 'DiscountPriceChargingInfo':[{'FeeTime':info.DiscountTime, 'ElectricityFee':info.DiscountElectricityFee, 'ServiceFee':info.DiscountServiceFee} for info in swapInfo.DiscountPriceChargingInfo],
  11658. 'ElectricityFee':swapInfo.ElectricityFee,
  11659. 'ServiceFee':swapInfo.ServiceFee,
  11660. 'ParkFee':swapInfo.ParkFee,
  11661. 'chargeTagList':[{'tagId':tag.tagId, 'tagType':tag.tagType, 'tagDesc':tag.tagDesc, 'tagOrder':tag.tagOrder, 'tagName':tag.tagName, 'color':tag.color} for tag in swapInfo.ChargeTagList],
  11662. 'StationTel':swapInfo.StationTel,
  11663. 'ServiceTel':swapInfo.ServiceTel,
  11664. 'Payment':swapInfo.Payment,
  11665. 'Remark':swapInfo.Remark,
  11666. 'RightTag':swapInfo.RightTag,
  11667. 'StationType':swapInfo.StationType
  11668. }
  11669. if swapInfo.swapFlag:
  11670. payload.update({'joinedTime':swapInfo.joinedTime.strftime('%Y-%m-%d %H:%M:%S')})
  11671. return JsonOkResponse(payload=payload)
  11672. @permission_required(ROLE.dealer)
  11673. def uploadSwapPicture(request):
  11674. files = request.FILES.getlist('file')
  11675. groupId = request.POST.get('groupId', None)
  11676. tail = request.POST.get('tail', None)
  11677. if groupId is None:
  11678. return JsonErrorResponse(description=u"缺少参数")
  11679. if not len(files):
  11680. return JsonResponse({'result': 0, 'description': u'未找到上传的商品图片,请重新试试', 'payload': {}})
  11681. uploader = SwapGroupPicFileUploader(inputFile=request.FILES.getlist('file')[0], uploadType='swap', groupId=groupId, tail=tail)
  11682. logger.info('[uploadItemPic] %s is being used' % (repr(uploader),))
  11683. try:
  11684. outputUrl = uploader.upload()
  11685. return JsonResponse({'result': 1, 'description': '', 'payload': {'Url':outputUrl}})
  11686. except InvalidFileSize, e:
  11687. logger.info(
  11688. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  11689. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  11690. except InvalidFileName, e:
  11691. logger.info(
  11692. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  11693. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  11694. @permission_required(ROLE.dealer)
  11695. def getFeeMode(request):
  11696. payload = request.POST
  11697. logicalCode = payload.get("logicalCode")
  11698. devObj = Device.objects.get(logicalCode=logicalCode)
  11699. if devObj.ownerId != str(request.user.id):
  11700. return JsonErrorResponse(description=u"参数错误")
  11701. feeMode = devObj.otherConf.get('feeMode', {})
  11702. timeRateList = []
  11703. shiduan = feeMode.get('shiduan', '000000000000000000000000000000000000000000000000')
  11704. for ii in range(48):
  11705. startHour = 0 + ii / 2
  11706. startMin = '00' if ii % 2 == 0 else '30'
  11707. endHour = startHour if ii % 2 == 0 else startHour + 1
  11708. endMin = '30' if ii % 2 == 0 else '00'
  11709. startTime = '%02d:%s' % (startHour, startMin)
  11710. endTime = '%02d:%s' % (endHour, endMin)
  11711. timeRateList.append({'startTime':startTime, 'endTime':endTime, 'rate':shiduan[ii]})
  11712. result = {'top_price_rate':feeMode.get('jianFee', 0),
  11713. 'top_price_service_rate':feeMode.get('jianServe', 0),
  11714. 'peak_price_rate':feeMode.get('fengFee', 0),
  11715. 'peak_price_service_rate':feeMode.get('fengServe', 0),
  11716. 'normal_price_rate':feeMode.get('pingFee', 0),
  11717. 'normal_price_service_rate':feeMode.get('pingServe', 0),
  11718. 'valley_price_rate':feeMode.get('guFee', 0),
  11719. 'valley_price_service_rate':feeMode.get('guServe', 0),
  11720. 'jishunScale':feeMode.get('jishunScale', 0),
  11721. 'timeRateList':timeRateList}
  11722. return result
  11723. @permission_required(ROLE.dealer)
  11724. def setFeeMode(request):
  11725. payload = request.POST
  11726. logicalCode = payload.get("logicalCode")
  11727. devObj = Device.objects.get(logicalCode=logicalCode)
  11728. if devObj.ownerId != str(request.user.id):
  11729. return JsonErrorResponse(description=u"参数错误")
  11730. feeMode = devObj.otherConf.get('feeMode', {})
  11731. feeMode['jianFee'] = float(request.POST.get('top_price_rate'))
  11732. feeMode['jianServe'] = float(request.POST.get('top_price_service_rate'))
  11733. feeMode['fengFee'] = float(request.POST.get('peak_price_rate'))
  11734. feeMode['fengServe'] = float(request.POST.get('peak_price_service_rate'))
  11735. feeMode['pingFee'] = float(request.POST.get('normal_price_rate'))
  11736. feeMode['pingServe'] = float(request.POST.get('normal_price_service_rate'))
  11737. feeMode['guFee'] = float(request.POST.get('valley_price_rate'))
  11738. feeMode['guServe'] = float(request.POST.get('valley_price_service_rate'))
  11739. feeMode['jishunScale'] = float(request.POST.get('jishunScale', 0))
  11740. shiduan = ''
  11741. for ii in range(48):
  11742. startHour = 0 + ii / 2
  11743. startMin = '00' if ii % 2 == 0 else '30'
  11744. endHour = startHour if ii % 2 == 0 else startHour + 1
  11745. endMin = '30' if ii % 2 == 0 else '00'
  11746. startTime = '%02d:%s' % (startHour, startMin)
  11747. endTime = '%02d:%s' % (endHour, endMin)
  11748. print startTime, endTime
  11749. harfHourValue = '0'
  11750. for conf in request.POST.get('timeRateList'):
  11751. if startTime >= conf['startTime'] and endTime <= conf['endTime']:
  11752. harfHourValue = conf['rate']
  11753. break
  11754. else:
  11755. continue
  11756. shiduan += harfHourValue
  11757. feeMode['shiduan'] = shiduan
  11758. try:
  11759. devObj.save()
  11760. except Exception, e:
  11761. return JsonResponse({"result": 2, "description": "配置失败,请重试"})
  11762. return JsonOkResponse()
  11763. @permission_required(ROLE.dealer)
  11764. def setGroupSwapFlag(request):
  11765. ownerId = str(request.user.bossId)
  11766. groupId = request.POST.get('groupId', None)
  11767. if groupId is None:
  11768. return JsonErrorResponse(description=u"缺少参数")
  11769. swapFalg = request.POST.get('swapFlag', False)
  11770. success, description, groupId = Group.update_group(groupId, swapFalg=swapFalg)
  11771. SwapGroup.get_collection().update({'groupId':groupId}, {'$set':{'swapFlag':swapFalg}})
  11772. return JsonOkResponse() if success else JsonErrorResponse(description=description,
  11773. payload={'groupId': groupId})
  11774. @permission_required(ROLE.dealer)
  11775. def saveInterconnectionDetail(request):
  11776. ownerId = str(request.user.bossId)
  11777. data = json.loads(request.body)
  11778. groupId = data.get('groupId', None)
  11779. if groupId is None:
  11780. return JsonErrorResponse(description=u"缺少参数")
  11781. group = Group.get_group(groupId)
  11782. if group is None:
  11783. return JsonErrorResponse(description=u"参数错误")
  11784. swapInfo = SwapGroup.objects(groupId=groupId).first()
  11785. if swapInfo is None:
  11786. swapInfo = SwapGroup(groupId=groupId, stationID=SwapGroup.make_stationID(groupId))
  11787. lng, lat = SwapGroup.bd09_to_gcj02(data['StationLng'], data['StationLat'])
  11788. swapInfo.ownerId = ownerId
  11789. swapInfo.swapFlag = data.get('swapFlag', False)
  11790. swapInfo.location = {'type':'Point', 'coordinates':[data['StationLng'], data['StationLat']]}
  11791. swapInfo.gcjLng = lng
  11792. swapInfo.gcjLat = lat
  11793. swapInfo.BusineHours = data['BusineHours']
  11794. swapInfo.SiteGuide = data['SiteGuide']
  11795. swapInfo.Construction = data['Construction']
  11796. swapInfo.SupportOrder = int(data['SupportOrder'])
  11797. ii = 0
  11798. picList = []
  11799. for pic in data['Pictures']:
  11800. ii += 1
  11801. picList.append(Picture(ii, pic['IsCover'], pic['Url'], pic['title'], pic['Title']))
  11802. swapInfo.Pictures = picList
  11803. swapInfo.MatchCars = data['MatchCars']
  11804. swapInfo.ParkInfo = data['ParkInfo']
  11805. swapInfo.StationStatus = data['StationStatus']
  11806. swapInfo.ParkNums = data['ParkNums']
  11807. swapInfo.originalAlternateFeeRemark = data['originalAlternateFeeRemark']
  11808. swapInfo.alternateFeeRemark = data['alternateFeeRemark']
  11809. swapInfo.originalDirectFeeRemark = data['originalDirectFeeRemark']
  11810. swapInfo.directFeeRemark = data['directFeeRemark']
  11811. swapInfo.PriceChargingInfo = [PriceCharging(info['FeeTime'], info['ElectricityFee'], info['ServiceFee']) for info in data['PriceChargingInfo']]
  11812. swapInfo.DiscountPriceChargingInfo = [DiscountPriceCharging(info['FeeTime'], info['ElectricityFee'], info['ServiceFee']) for info in data['DiscountPriceChargingInfo']]
  11813. swapInfo.ElectricityFee = data['ElectricityFee']
  11814. swapInfo.ServiceFee = data['ServiceFee']
  11815. swapInfo.ParkFee = data['ParkFee']
  11816. swapInfo.ChargeTagList = [ChargeTag(0, tag['tagType'], tag['tagDesc'], tag['tagOrder'], tag['tagName'], tag['color']) for tag in data.get('chargeTagList', [])]
  11817. swapInfo.StationTel = data['StationTel']
  11818. swapInfo.ServiceTel = data['ServiceTel']
  11819. swapInfo.Payment = data['Payment']
  11820. swapInfo.SupportOrder = data['SupportOrder']
  11821. swapInfo.Remark = data['Remark']
  11822. swapInfo.RightTag = data['RightTag']
  11823. swapInfo.StationType = data['StationType']
  11824. if swapInfo.swapFlag:
  11825. swapInfo.joinedTime = datetime.datetime.now()
  11826. try:
  11827. swapInfo.save()
  11828. except Exception, e:
  11829. return JsonResponse({"result": 2, "description": "配置失败,请重试"})
  11830. Group.update_group(group_id=groupId, swapFlag=swapInfo.swapFlag)
  11831. SwapGroup.recount_devnum(groupId)
  11832. return JsonOkResponse()
  11833. @permission_required(ROLE.dealer)
  11834. def getInterconnectionDisclaimer(request):
  11835. payload = {
  11836. 'version': '1.01',
  11837. '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>\
  11838. <p style="text-align:left;"> 2、<span>互联互通主要是通过第三方的APP、小程序、H5应用,能够查询到您旗下的设备,并能够通过第三方能够启动充电,并根据账单进行结算。</span></p><p style="text-align:left;">\
  11839. <span>3、互联互通的第三方APP,包括不限于诸如:快电、小桔充电、恒大星脉等等第三方平台,而且每个第三方平台会存在不同的服务区别,包括通过第三方使用充电桩需要提取的佣金、费用结算方式、营销活动推广费用、提现费率等等,具体\
  11840. 情况,在互联互通开放时,请您和我们技术支持沟通确认。</span></p><p style="text-align:left;"> <span>四、【服务要求】</span></p><p style="text-align:left;"> <span>1、您提供的设备,包括交流桩和直流桩,能够保证设备的安全性、可靠性、可用性,以及设备本身的数据统计准确,应当尽量避免因此引起的纠纷。因此而引起的纠纷,我们要求由您负责并处理。</span>\
  11841. </p><p style="text-align:left;"> <span>2、您提供配置的设备信息,包括互联互通的信息,应当准确并符合实际,避免出现消费者对平台进行投诉,因此产生的投诉,将有您负责,并且我们将有权对不符合实际情况的互联互通进行关闭,以保障充电用户的权益。</span>\
  11842. </p><p style="text-align:left;"> <span>3、产生的一些售后处理,可能需要您和我们一起处理,我们希望您保持联系方式的畅通,以保证服务质量。如果用户或者第三方平台投诉到我们这里,我们却多次无法联系到您,我们有权强制禁用您的互联互通功能。</span></p>\
  11843. <p style="text-align:left;"> <span>五、【售后及其他】</span></p><p style="text-align:left;"> <span>1、平台的相关售后,包括您使用的后台、互联互通,由我们负责,如有疑问,可以直接联系我们。</span>\
  11844. </p><p style="text-align:left;"> <span>2、设备相关售后,诸如设备故障、设备维修等,导致的互联互通服务售后,由您负责,我们售后可能会联系您,需要您保持联系方式畅通。</span></p><p style="text-align:left;"> <span><br /></span></p>'
  11845. }
  11846. return JsonOkResponse(payload=payload)
  11847. @error_tolerate(nil=DefaultJsonErrorResponse)
  11848. @permission_required(ROLE.dealer, ROLE.subaccount)
  11849. def getCustomizePoint(request):
  11850. logicalCode = request.GET.get('logicalCode')
  11851. dev = Device.get_dev_by_l(logicalCode)
  11852. if dev is None:
  11853. return JsonErrorResponse(description=u"参数错误")
  11854. box = ActionDeviceBuilder.create_action_device(dev)
  11855. unit = box.get_customize_score_unit()
  11856. if unit is None:
  11857. return JsonResponse({'result': 0, 'description': "", 'payload': {}})
  11858. return JsonResponse({'result': 0, 'description': "", 'payload': [unit]})
  11859. @error_tolerate(nil=DefaultJsonErrorResponse)
  11860. @permission_required(ROLE.dealer, ROLE.subaccount)
  11861. def onCustomizePoint(request):
  11862. logicalCode = request.POST.get('logicalCode')
  11863. pointNum = request.POST.get('time')
  11864. portList = json.loads(request.POST.get('attachParas')).get('chargeIndex')
  11865. openId = request.user.managerialOpenId
  11866. dev = Device.get_dev_by_l(logicalCode)
  11867. if dev is None:
  11868. return JsonErrorResponse(description=u"参数错误")
  11869. box = ActionDeviceBuilder.create_action_device(dev)
  11870. address = Group.get_group(dev['groupId'])['address']
  11871. groupName = Group.get_group(dev['groupId'])['groupName']
  11872. errorList = []
  11873. errdesc = ''
  11874. for port in portList:
  11875. try:
  11876. box.start_customize_point(pointNum, openId, int(port))
  11877. UpscoreRecord(
  11878. logicalCode=dev['logicalCode'],
  11879. devNo=dev['devNo'],
  11880. ownerId=str(request.user.id),
  11881. time=datetime.datetime.now(),
  11882. score=pointNum,
  11883. address=address,
  11884. groupName=groupName,
  11885. devType=dev['devType']['name'],
  11886. type="",
  11887. remark=u'自定义上分:%s%s' % (pointNum, request.POST.get('unit'))
  11888. ).save()
  11889. except ServiceException, e:
  11890. errorList.append(port)
  11891. errdesc = ',' + e.result.get('description')
  11892. continue
  11893. except Exception, e:
  11894. errorList.append(port)
  11895. continue
  11896. if errorList:
  11897. return JsonResponse({'result': 0, 'description': u"出现上分失败" + errdesc, 'payload': {'errorList':errorList}})
  11898. return JsonResponse({'result': 0, 'description': u"上分成功", 'payload': {'errorList':errorList}})
  11899. @error_tolerate(nil=DefaultJsonErrorResponse)
  11900. @permission_required(ROLE.dealer)
  11901. def getPolicyInfos(request):
  11902. lc = request.GET.get('logicalCode')
  11903. dev = Device.get_dev_by_l(lc)
  11904. box = ActionDeviceBuilder.create_action_device(dev)
  11905. result = box.get_policy_infos()
  11906. return JsonOkResponse(payload=result)
  11907. @error_tolerate(nil=DefaultJsonErrorResponse)
  11908. @permission_required(ROLE.dealer)
  11909. def setPolicyInfos(request):
  11910. payload = json.loads(request.body)
  11911. lc = payload.get('logicalCode')
  11912. dev = Device.get_dev_by_l(lc)
  11913. box = ActionDeviceBuilder.create_action_device(dev)
  11914. try:
  11915. box.set_policy_infos(payload)
  11916. except ServiceException, e:
  11917. return JsonErrorResponse(description=e.result.get('description'))
  11918. return JsonOkResponse(description=u'计费配置保存成功')
  11919. @error_tolerate(logger = logger)
  11920. def refundOrderNotifier(request, pay_app_type):
  11921. """
  11922. 退款回调接口(经销商目前只有微信和京东聚合支付微信部分)
  11923. :param request:
  11924. :param pay_app_type:
  11925. :return:
  11926. """
  11927. assert pay_app_type in PayAppType.choices(), 'not support this pay app type({})'.format(pay_app_type)
  11928. notifier_cls = RefundManager().get_notifier(pay_app_type)
  11929. response = notifier_cls(request, lambda filter: RefundDealerRechargeRecord.get_record(**filter)).do(
  11930. refund_post_pay)
  11931. return response