views.py 241 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. """
  4. web.user.views
  5. ~~~~~~~~~
  6. 关于扫码终端用户的一切视图
  7. """
  8. import base64
  9. import datetime
  10. import logging
  11. import random
  12. import re
  13. import time
  14. import uuid
  15. from copy import deepcopy
  16. from math import radians, fabs, cos, asin, sqrt, sin, isnan
  17. import simplejson as json
  18. from bson.objectid import ObjectId
  19. from django.conf import settings
  20. from mongoengine.errors import DoesNotExist
  21. from mongoengine.queryset.visitor import Q
  22. from typing import TYPE_CHECKING, cast, Optional, Union, Tuple, Dict
  23. from voluptuous.error import MultipleInvalid
  24. from apilib.monetary import VirtualCoin, RMB
  25. from apilib.utils_datetime import to_datetime, timestamp_to_dt
  26. from apilib.utils_json import JsonResponse
  27. from apilib.utils_string import cn
  28. #: ad
  29. from apilib.utils_sys import memcache_lock
  30. from apilib.utils_url import add_query, before_frag_add_query
  31. from apps import serviceCache
  32. from apps.common.utils import coordinateHandler
  33. from apps.web.ad.models import AdRecord, DevRegToAli
  34. from apps.web.agent.models import Agent, MoniApp
  35. from apps.web.common.proxy import ClientRechargeModelProxy, ClientConsumeModelProxy
  36. from apps.web.common.transaction.pay import OrderCacheMgr, PayManager, RefundManager
  37. from apps.web.common.utils import UserConsumeFilter
  38. from apps.web.common.validation import check_phone_number, check_entity_name
  39. from apps.web.constant import Const, GPS_TYPE, START_DEVICE_STATUS, ErrorCode, RECHARGE_CARD_TYPE, APP_TYPE, \
  40. AppPlatformType, DeviceOnlineStatus, support_policy_weifule, \
  41. support_policy_device, RechargeRecordVia
  42. from apps.web.core import PayAppType, ROLE
  43. from apps.web.core.auth.ali import AlipayAuthBridge
  44. from apps.web.core.auth.wechat import WechatAuthBridge
  45. from apps.web.core.bridge import WechatClientProxy
  46. from apps.web.core.exceptions import ServiceException, InvalidParameter, InvalidFileSize, \
  47. InvalidFileName, InterceptException
  48. from apps.web.core.file import AliOssFileUploader
  49. from apps.web.core.helpers import ActionDeviceBuilder
  50. from apps.web.core.messages.sms import userMobileVerifySMSProvider
  51. from apps.web.core.models import WechatPayApp, BoundOpenInfo, WechatAuthApp
  52. from apps.web.core.sysparas import SysParas
  53. from apps.web.core.utils import DefaultJsonErrorResponse
  54. from apps.web.core.utils import JsonErrorResponse, JsonOkResponse
  55. from apps.web.dealer.models import Dealer, OnSale, OnSaleRecord, VirtualCard, Complaint, \
  56. DealerMessage
  57. from apps.web.device.define import DeviceChannelType
  58. from apps.web.device.models import Device, Group, FeedBack, Comment, Cell, DeviceType, SwapGroup
  59. from apps.web.device.models import DeviceDict
  60. from apps.web.device.models import GroupDict
  61. from apps.web.device.utils import device_control_cache_key
  62. from apps.web.exceptions import UserServerException
  63. from apps.web.helpers import get_ali_auth_bridge, get_wx_config, get_wechat_auth_bridge, \
  64. get_user_manager_agent, get_app, start_device_lock_key
  65. from apps.web.management.models import Manager
  66. from apps.web.services.bluetooth.service import ActionBtDeviceBuilder
  67. #: user
  68. from apps.web.south_intf.yuchuanApi import YuChuanApi
  69. from apps.web.user import UserAuthState, MoniUserAuthState
  70. from apps.web.user.auth import response_with_login
  71. from apps.web.user.conf import USER_AUTH_REDIRECT_URL, PAY_NOTIFY_URL
  72. from apps.web.user.models import MyUser, ConsumeRecord, RechargeRecord, ServiceProgress, Card, CardRechargeRecord, \
  73. CardConsumeRecord, CardRechargeOrder, UserVirtualCard, VCardConsumeRecord, \
  74. RefundMoneyRecord, MoniUser, VirtualCardRechargeRecord, SwapCardRecord, MonthlyPackage, \
  75. EndUserLocation, Redpack, MyUserDetail
  76. from apps.web.user.transaction import post_pay
  77. from apps.web.user.transaction_deprecated import refund_post_pay
  78. from apps.web.user.utils import (
  79. get_homepage_response, auth_wechat_pay_app,
  80. auth_wechat_manager_app, login_required,
  81. user_last_time_use_ended_cache, parse_auth_payload, batteryInfo,
  82. is_need_renew, check_user_tel, check_black_user, PayParam, BUILDER_MAP, RedpackBuilder)
  83. from apps.web.user.utils2 import get_user_not_complete_order
  84. from apps.web.user.validation import feedbackSchema
  85. from apps.web.utils import (
  86. detect_alipay_client, detect_wechat_client, permission_required, error_tolerate, ErrorResponseRedirect,
  87. NotSupportedPlatformResponseRedirect, get_start_key_status, set_start_key_status,
  88. NetDeviceResponseRedirect, AdAccessResponseRedirect, ExternalResponseRedirect,
  89. FrontEndResponseRedirect, concat_server_end_url, concat_user_cardTicketList_entry_url,
  90. record_operation_behavior, get_client_ip, WechatAuthDummyRedirect, trace_call, concat_user_recharge_url)
  91. from apps.web.wrapper import request_limit_by_user
  92. from library.alipay.exceptions import AliException
  93. from library.wechatbase.exceptions import WechatOAuthDummyException
  94. from taskmanager.mediator import task_caller
  95. if TYPE_CHECKING:
  96. from django.core.handlers.wsgi import WSGIRequest
  97. from django.http import HttpResponse, HttpResponseRedirect
  98. from apps.web.common.proxy import QuerySetProxy
  99. from apps.web.core.db import CustomQuerySet
  100. from apps.web.core.models import PayAppBase
  101. logger = logging.getLogger(__name__)
  102. # 报错页面
  103. defaultErrorResponseRedirect = ErrorResponseRedirect(error = cn(u'系统错误,请重试'))
  104. def checkAdClick(request):
  105. # type: (WSGIRequest)->HttpResponse
  106. """
  107. :param request:
  108. :return:
  109. """
  110. adId = request.GET.get('adId', None)
  111. logger.debug('get adId success adId = %s' % adId)
  112. if not adId:
  113. return ErrorResponseRedirect(error = cn(u'无效的链接,无此广告'))
  114. return AdAccessResponseRedirect(adId = str(adId))
  115. @error_tolerate(nil = defaultErrorResponseRedirect)
  116. @login_required(error_response = ErrorResponseRedirect(error = cn(u'您未登陆,请扫码登录')))
  117. def adAccess(request):
  118. # type: (WSGIRequest)->HttpResponse
  119. """
  120. 减少cookie依赖, 参数全部通过state封装
  121. 用户领取广告效果奖励
  122. :param request:
  123. :return:
  124. """
  125. adId = request.GET.get('state', None)
  126. return ErrorResponseRedirect(error = cn(u'该广告不可用'))
  127. @trace_call(logger = logger)
  128. @error_tolerate(nil = defaultErrorResponseRedirect)
  129. def userLogin(request):
  130. # type: (WSGIRequest)->HttpResponse
  131. """
  132. 用户扫码-> 登陆渲染的首屏页面
  133. 扫码的读取分配入口,同时兼容老式设备号和新式逻辑码
  134. .. 2017/10/30 加入对支付宝识别的兼容。
  135. :param request:
  136. :return:
  137. """
  138. def by_agent(request, agentId, href):
  139. # type: (WSGIRequest, str, str)->(basestring, str)
  140. return UserAuthState.by_agent(agentId=agentId, href=href, productAgentId=agentId)
  141. def by_dev(request, devNo, logicalCode, port=None):
  142. # type: (WSGIRequest, str, str, str)->(basestring, str)
  143. logger.debug('user login. device = (logicalCode=%s), port = %s' % (logicalCode, port))
  144. if (logicalCode is not None) and (devNo is None):
  145. logicalCode = logicalCode.strip()
  146. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  147. if not devNo:
  148. raise UserServerException(u'该设备未开通网络支付,请投币或者联系客服(1002)')
  149. devNo = devNo.strip()
  150. dev = Device.get_dev(devNo) # type: Optional[DeviceDict]
  151. if dev is None:
  152. raise UserServerException(u'该设备未开通网络支付,请投币或者联系客服(1003)')
  153. if not dev.is_registered or 'groupId' not in dev or 'washConfig' not in dev:
  154. raise UserServerException(u'该设备未开通网络支付,请投币或者联系客服(1005)')
  155. if dev.is_expired:
  156. raise UserServerException(
  157. u'设备({})的物联网卡已经过期,目前离线,无法扫码支付。请您联系提醒设备运营商进行充值,以便尽快恢复使用。'.format(
  158. dev.logicalCode))
  159. if dev.is_fault:
  160. raise UserServerException(u'设备故障中,正在等师傅过来维修,您试试看其他设备吧')
  161. if dev.is_DND_now:
  162. raise UserServerException(u'设备处于禁用时段,暂不支持扫码使用')
  163. if dev.ban:
  164. raise UserServerException(u'该设备暂时不可使用,请联系经销商')
  165. if port and dev.channelType != DeviceChannelType.Channel_BT:
  166. isFree = Group.get_group(dev.groupId).get('isFree', False)
  167. if not isFree:
  168. box = ActionDeviceBuilder.create_action_device(dev)
  169. isCanAdd = dev['devType'].get('payableWhileBusy', False)
  170. canUse, desc = box.is_port_can_use(port, isCanAdd)
  171. if not canUse:
  172. raise UserServerException(desc)
  173. dealer = dev.owner # type: Dealer
  174. # 平台agent必须配置自定义公众号, 否则普通扫码用户无法获取
  175. product_agent = get_user_manager_agent(dealer)
  176. state = UserAuthState.by_dev(devNo=devNo,
  177. chargeIndex=port,
  178. agentId=str(dealer.agentId),
  179. productAgentId=str(product_agent.id))
  180. logger.debug('initial user state = {}'.format(repr(state)))
  181. return dev, product_agent, state
  182. def generate_card_recharge_href(_cardNo, _product_agent_id): # type:(str, str) -> Optional[str]
  183. _baseHref = "/user/index.html#/chargeCard?cardNo={}&cardId={}"
  184. try:
  185. card = Card.objects.get(cardNo=_cardNo, agentId=str(_product_agent_id))
  186. except DoesNotExist:
  187. logger.error('card is not exist, cardNo=%s' % _cardNo)
  188. return None
  189. except Exception as e:
  190. logger.error(e)
  191. return None
  192. return _baseHref.format(_cardNo, str(card.id))
  193. def login_context(request):
  194. if 'devNo' not in request.GET and 'l' not in request.GET and 'agentId' not in request.GET:
  195. return ErrorResponseRedirect(error=cn(u'错误的二维码或者二维码损坏,请联系工作人员进行维修'))
  196. href = request.GET.get('redirect', '/user/index.html#/user/me')
  197. if 'agentId' in request.GET:
  198. # 个人中心登录
  199. dev = None # type: Optional[DeviceDict]
  200. product_agent_id = str(request.GET.get("agentId"))
  201. product_agent = Agent.objects(id = product_agent_id).get() # type: Agent
  202. cardNo = request.GET.get("cardNo")
  203. if cardNo:
  204. href = generate_card_recharge_href(cardNo, product_agent_id) or href
  205. state = by_agent(request, product_agent_id, href)
  206. groupId = MyUser._product_group_id(product_agent_id)
  207. else:
  208. # 扫描登录
  209. devNo = request.GET.get('devNo', None)
  210. logicalCode = request.GET.get('l', None)
  211. dev, product_agent, state = by_dev(request, devNo, logicalCode, request.GET.get('chargeIndex', None))
  212. groupId = dev.groupId
  213. if detect_wechat_client(request):
  214. # 微信平台登录
  215. auth_bridge = get_wechat_auth_bridge(
  216. source = product_agent, app_type = APP_TYPE.WECHAT_AUTH) # type: WechatAuthBridge
  217. pay_type = u'微信'
  218. auth_callback = None # 具体处理流程中写死
  219. elif detect_alipay_client(request):
  220. # 支付宝平台登录
  221. auth_bridge = get_ali_auth_bridge(source=product_agent,
  222. app_type=APP_TYPE.ALIPAY_AUTH) # type: AlipayAuthBridge
  223. pay_type = u'支付宝'
  224. auth_callback = USER_AUTH_REDIRECT_URL.ALIPAY
  225. else:
  226. raise UserServerException(u'不支持该平台下扫码')
  227. if not auth_bridge.enable:
  228. raise UserServerException(u'{}平台暂时未开通,请使用其他方式登录'.format(pay_type))
  229. if not product_agent.customizedUserGzhAllowable:
  230. return ErrorResponseRedirect(error=cn(u'系统配置错误,请联系平台客服(10009)'))
  231. return auth_bridge, auth_callback, product_agent, state, pay_type, dev, groupId
  232. def clone_from_login_user(login_user, auth_bridge, groupId, new_product_agent_id, new_agent_id):
  233. if login_user.groupId == groupId:
  234. my_user = login_user
  235. need_save = False
  236. if my_user.agentId != new_agent_id:
  237. my_user.agentId = new_agent_id
  238. need_save = True
  239. if my_user.productAgentId != new_product_agent_id:
  240. my_user.productAgentId = new_product_agent_id
  241. need_save = True
  242. if need_save:
  243. my_user.save()
  244. else:
  245. if login_user.productAgentId == new_product_agent_id:
  246. payload = login_user.cloneable_user_info
  247. else:
  248. payload = {}
  249. payload.update({
  250. 'authAppId': auth_bridge.appid,
  251. 'agentId': new_agent_id,
  252. 'productAgentId': new_product_agent_id
  253. })
  254. my_user = MyUser.get_or_create(app_platform_type = auth_bridge.gateway_type,
  255. open_id = login_user.openId,
  256. group_id = groupId,
  257. **payload)
  258. return my_user
  259. try:
  260. ip = get_client_ip(request)
  261. logger.debug("user<ip={}> login. ".format(ip))
  262. auth_bridge, auth_callback, product_agent, state, pay_type, dev, groupId = login_context(request)
  263. login_user = request.user # type: MyUser
  264. if auth_bridge.gateway_type == AppPlatformType.WECHAT:
  265. need_auth = (not login_user.is_authenticated()) or (login_user.authAppId != auth_bridge.appid)
  266. if state.by == UserAuthState.BY.AGENT:
  267. if need_auth:
  268. manager_auth_bridge = get_wechat_auth_bridge(product_agent, APP_TYPE.WECHAT_USER_MANAGER)
  269. if manager_auth_bridge.appid == auth_bridge.appid:
  270. logger.debug('auth bridge is same with manager auth bridge.')
  271. return ExternalResponseRedirect(
  272. auth_bridge.generate_auth_url_user_scope(
  273. redirect_uri = USER_AUTH_REDIRECT_URL.WECHAT_USER_CENTER_AUTH_USER,
  274. payload = state.encode()))
  275. else:
  276. return ExternalResponseRedirect(
  277. auth_bridge.generate_auth_url_base_scope(
  278. redirect_uri = USER_AUTH_REDIRECT_URL.WECHAT_USER_CENTER_AUTH_BASE,
  279. payload = state.encode()))
  280. else:
  281. my_user = clone_from_login_user(
  282. login_user, auth_bridge, groupId, str(product_agent.id), str(product_agent.id))
  283. manager_auth_bridge = get_wechat_auth_bridge(product_agent, APP_TYPE.WECHAT_USER_MANAGER)
  284. manager_openid = my_user.get_bound_pay_openid(manager_auth_bridge.bound_openid_key)
  285. if manager_openid and (manager_openid != my_user.managerialOpenId):
  286. my_user.managerialAppId = manager_auth_bridge.appid
  287. my_user.managerialOpenId = manager_openid
  288. my_user.save()
  289. if (not manager_openid) or (not my_user.nickname):
  290. state.uid = str(my_user.id)
  291. return ExternalResponseRedirect(
  292. manager_auth_bridge.generate_auth_url_user_scope(
  293. redirect_uri = USER_AUTH_REDIRECT_URL.WECHAT_USER_CENTER_MANAGER_AUTH_USER,
  294. payload = state.encode()))
  295. else:
  296. if need_auth:
  297. return ExternalResponseRedirect(
  298. auth_bridge.generate_auth_url_base_scope(
  299. redirect_uri = USER_AUTH_REDIRECT_URL.WECHAT_AUTH_BASE,
  300. payload = state.encode()))
  301. else:
  302. my_user = clone_from_login_user(
  303. login_user, auth_bridge, groupId, str(product_agent.id),
  304. dev.owner.agentId if dev else str(product_agent.id))
  305. state.uid = str(my_user.id)
  306. response = auth_wechat_manager_app(my_user, product_agent, state, dev)
  307. if response:
  308. return response
  309. response = auth_wechat_pay_app(
  310. my_user, dev.owner, product_agent, state, USER_AUTH_REDIRECT_URL.WECHAT_PAY_AUTH_BASE)
  311. if response:
  312. return response
  313. else:
  314. if not login_user.is_authenticated():
  315. return ExternalResponseRedirect(
  316. auth_bridge.generate_auth_url_user_scope(
  317. redirect_uri=auth_callback,
  318. payload=state.encode()))
  319. else:
  320. my_user = clone_from_login_user(
  321. login_user, auth_bridge, groupId, str(product_agent.id),
  322. dev.owner.agentId if dev else str(product_agent.id))
  323. if my_user.nickname is None:
  324. return ExternalResponseRedirect(
  325. auth_bridge.generate_auth_url_user_scope(
  326. redirect_uri = auth_callback,
  327. payload = state.encode()))
  328. if state.by == UserAuthState.BY.AGENT:
  329. response = FrontEndResponseRedirect(str(state.href))
  330. else:
  331. response = get_homepage_response(auth_bridge.gateway_type, my_user, dev,
  332. state.chargeIndex if state.chargeIndex else '', product_agent)
  333. return response_with_login(request, my_user, response)
  334. except UserServerException as e:
  335. return ErrorResponseRedirect(error=cn(e.message))
  336. except Exception as e:
  337. logger.exception(e)
  338. return ErrorResponseRedirect(error=cn(u'系统错误'))
  339. @trace_call(logger = logger)
  340. @error_tolerate(nil = defaultErrorResponseRedirect, logger = logger)
  341. def wxpayBaseAccess(request):
  342. # type: (WSGIRequest)->HttpResponse
  343. """
  344. 获取微信用户支付的openId
  345. :param request:
  346. :return:
  347. """
  348. def authorize(app, request):
  349. # type: (Optional[WechatPayApp], WSGIRequest)->None
  350. if isinstance(app, WechatPayApp):
  351. code = request.GET.get('code', None)
  352. if not code:
  353. raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.AUTH_CODE_IS_NULL))
  354. auth_bridge = WechatAuthBridge(app)
  355. openId = auth_bridge.authorize(code)
  356. user.set_bound_pay_openid(auth_bridge.bound_openid_key, openId = openId)
  357. user.save()
  358. try:
  359. if 'code' not in request.GET and 'openId' not in request.GET:
  360. raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.AUTH_CODE_IS_NULL))
  361. state = parse_auth_payload(request)
  362. if not state.is_valid():
  363. raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.USER_STATE_IS_NOT_VALID))
  364. user = MyUser.objects.get(id = state.uid) # type: MyUser
  365. dev = Device.get_dev(state.devNo) # type: DeviceDict
  366. product_agent = Agent.objects(id = str(state.productAgentId)).get()
  367. app = get_app(source = product_agent,
  368. app_type = APP_TYPE.WECHAT_ENV_PAY,
  369. role = ROLE.myuser) # type: PayAppBase
  370. authorize(app, request)
  371. response = get_homepage_response(AppPlatformType.WECHAT, user, dev,
  372. state.chargeIndex if state.chargeIndex else '', product_agent)
  373. return response_with_login(request, user, response)
  374. except Exception as e:
  375. logger.exception(e)
  376. return ErrorResponseRedirect(error = u'系统错误, 请重新扫码')
  377. @trace_call(logger = logger)
  378. @error_tolerate(nil = defaultErrorResponseRedirect)
  379. def wechatAuthBase(request):
  380. # type: (WSGIRequest)->HttpResponse
  381. """
  382. 老终端用户扫码进入
  383. 只获取openId
  384. 用户通过扫码转到的中继器
  385. :param request:
  386. :return:
  387. """
  388. try:
  389. auth_code = request.GET.get('code', None)
  390. if auth_code is None:
  391. raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.AUTH_CODE_IS_NULL)
  392. state = parse_auth_payload(request) # type: UserAuthState
  393. logger.info('return to wechatAuthBase. code = %s; state = %s' % (auth_code, state))
  394. product_agent = Agent.objects(id = str(state.productAgentId)).get() # type: Agent
  395. dev = Device.get_dev(state.devNo) # type: DeviceDict
  396. groupId = dev.groupId
  397. auth_bridge = get_wechat_auth_bridge(source = product_agent, app_type = APP_TYPE.WECHAT_AUTH)
  398. logger.debug(
  399. 'wechat auth for login. appid = {}, code = {}, state = {}, agent = {}, group_id = {}'.format(
  400. auth_bridge.appid, auth_code, str(state.encode()), str(product_agent.id), groupId))
  401. openId = auth_bridge.authorize(auth_code)
  402. if not openId:
  403. logger.error(
  404. 'auth error, app = %s; payload = %s' % (repr(auth_bridge.app), str(state.encode())))
  405. return ErrorResponseRedirect(error = u'系统错误,请重新扫码')
  406. payload = {
  407. 'authAppId': auth_bridge.app.appid,
  408. 'agentId': str(state.agentId),
  409. 'productAgentId': str(state.productAgentId),
  410. 'payOpenIdMap': {
  411. auth_bridge.bound_openid_key: BoundOpenInfo(openId = openId)
  412. }
  413. }
  414. manager_auth_bridge = get_wechat_auth_bridge(source = product_agent, app_type = APP_TYPE.WECHAT_USER_MANAGER)
  415. if manager_auth_bridge.appid == auth_bridge.appid:
  416. payload.update({
  417. 'managerialAppId': auth_bridge.appid,
  418. 'managerialOpenId': openId
  419. })
  420. my_user = MyUser.get_or_create(
  421. app_platform_type = AppPlatformType.WECHAT, open_id = openId, group_id = groupId, **payload)
  422. if not my_user:
  423. raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.LOGIN_USER_IS_NULL)
  424. dealer = dev.owner # type: Dealer
  425. state.uid = str(my_user.id)
  426. response = auth_wechat_manager_app(my_user, product_agent, state, dev)
  427. if response:
  428. return response
  429. response = auth_wechat_pay_app(my_user, dealer, product_agent, state, USER_AUTH_REDIRECT_URL.WECHAT_PAY_AUTH_BASE)
  430. if response:
  431. return response
  432. response = get_homepage_response(AppPlatformType.WECHAT, my_user, dev,
  433. state.chargeIndex if state.chargeIndex else '', product_agent)
  434. return response_with_login(request, my_user, response)
  435. except UserServerException as e:
  436. logger.error(e.message)
  437. return ErrorResponseRedirect(error = cn(e.message))
  438. except Exception as e:
  439. logger.exception(e)
  440. return ErrorResponseRedirect(error = cn(u'网络开小差了,重新扫码试试喔'))
  441. @trace_call(logger = logger)
  442. @error_tolerate(nil = ErrorResponseRedirect, logger = logger)
  443. def wechatManagerAuthBase(request):
  444. # type: (WSGIRequest)->HttpResponse
  445. """
  446. manager做基础鉴权, 获取OpenId. 只有从用户信息获取不到managerOpenId的情况下才会走这个分支
  447. :param request:
  448. :return:
  449. """
  450. try:
  451. auth_code = request.GET.get(WechatAuthBridge.auth_code_key, None)
  452. if not auth_code:
  453. raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.AUTH_CODE_IS_NULL))
  454. state = parse_auth_payload(request)
  455. my_user = MyUser.objects.get(id = state.uid)
  456. product_agent = Agent.objects(id = str(state.productAgentId)).get()
  457. manager_auth_bridge = get_wechat_auth_bridge(
  458. source = product_agent, app_type = APP_TYPE.WECHAT_USER_MANAGER) # type: WechatAuthBridge
  459. openId = manager_auth_bridge.authorize(auth_code)
  460. if openId is None:
  461. logger.error(
  462. 'manager auth error, app = %s; state = %s' % (repr(manager_auth_bridge.app), str(state.encode())))
  463. return ErrorResponseRedirect(error = u'系统错误, 请重新扫码')
  464. my_user.managerialAppId = manager_auth_bridge.appid
  465. my_user.managerialOpenId = openId
  466. my_user.set_bound_pay_openid(manager_auth_bridge.bound_openid_key, openId = openId)
  467. my_user.save()
  468. dev = Device.get_dev(state.devNo) # type: DeviceDict
  469. response = auth_wechat_manager_app(my_user, product_agent, state, dev)
  470. if response:
  471. return response
  472. response = auth_wechat_pay_app(my_user, dev.owner, product_agent, state, USER_AUTH_REDIRECT_URL.WECHAT_PAY_AUTH_BASE)
  473. if response:
  474. return response
  475. response = get_homepage_response(AppPlatformType.WECHAT, my_user, dev,
  476. state.chargeIndex if state.chargeIndex else '', product_agent)
  477. return response_with_login(request, my_user, response)
  478. except UserServerException as e:
  479. logger.error(e.message)
  480. return ErrorResponseRedirect(error = cn(e.message))
  481. except WechatOAuthDummyException as e:
  482. logger.error(e.message)
  483. return WechatAuthDummyRedirect()
  484. except Exception as e:
  485. logger.exception(e)
  486. return ErrorResponseRedirect(error = cn(u'网络开小差了,重新扫码试试喔'))
  487. @trace_call(logger = logger)
  488. @error_tolerate(nil = ErrorResponseRedirect, logger = logger)
  489. def wechatManagerAuthUser(request):
  490. # type: (WSGIRequest)->HttpResponse
  491. """
  492. 用户首次授权,需要创建用户
  493. :param request:
  494. :return:
  495. """
  496. try:
  497. auth_code = request.GET.get(WechatAuthBridge.auth_code_key, None)
  498. if not auth_code:
  499. raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.AUTH_CODE_IS_NULL))
  500. state = parse_auth_payload(request)
  501. user = MyUser.objects.get(id = state.uid)
  502. product_agent = Agent.objects(id = str(state.productAgentId)).get()
  503. manager_auth_bridge = get_wechat_auth_bridge(
  504. source = product_agent, app_type = APP_TYPE.WECHAT_USER_MANAGER) # type: WechatAuthBridge
  505. userInfo = manager_auth_bridge.get_user_info(auth_code = auth_code)
  506. openId = userInfo['openId']
  507. if openId is None:
  508. logger.error(
  509. 'manager auth error, app = %s; payload = %s' % (repr(manager_auth_bridge.app), str(state.encode())))
  510. return ErrorResponseRedirect(error = u'系统错误, 请重新扫码')
  511. user.sex = userInfo.get('sex', 0)
  512. user.city = userInfo.get('city', '')
  513. user.province = userInfo.get('province', '')
  514. user.country = userInfo.get('country', '')
  515. user.nickname = userInfo.get('nickname', '')
  516. user.avatar = userInfo.get('avatar', '')
  517. user.unionId = userInfo.get('unionid', '')
  518. user.set_bound_pay_openid(manager_auth_bridge.bound_openid_key, openId = openId)
  519. user.managerialAppId = manager_auth_bridge.appid
  520. user.managerialOpenId = openId
  521. user.save()
  522. dev = Device.get_dev(state.devNo) # type: DeviceDict
  523. response = auth_wechat_pay_app(user, dev.owner, product_agent, state, USER_AUTH_REDIRECT_URL.WECHAT_PAY_AUTH_BASE)
  524. if response:
  525. return response
  526. response = get_homepage_response(AppPlatformType.WECHAT, user, dev,
  527. state.chargeIndex if state.chargeIndex else '', product_agent)
  528. return response_with_login(request, user, response)
  529. except UserServerException as e:
  530. logger.error(e.message)
  531. return ErrorResponseRedirect(error = cn(e.message))
  532. except WechatOAuthDummyException as e:
  533. logger.error(e.message)
  534. return WechatAuthDummyRedirect()
  535. except Exception as e:
  536. logger.exception(e)
  537. return ErrorResponseRedirect(error = cn(u'网络开小差了,重新扫码试试喔'))
  538. @trace_call(logger = logger)
  539. @error_tolerate(nil=defaultErrorResponseRedirect)
  540. def wechatBaseAuthForUserCenter(request):
  541. # type: (WSGIRequest)->HttpResponse
  542. """
  543. 个人中心
  544. :param request:
  545. :return:
  546. """
  547. try:
  548. auth_code = request.GET.get('code', None)
  549. if auth_code is None:
  550. raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.AUTH_CODE_IS_NULL)
  551. state = parse_auth_payload(request) # type: UserAuthState
  552. assert state.by == UserAuthState.BY.AGENT, 'must be enter user center.'
  553. logger.info('return to wechatBaseAuthForUserCenter. code = %s; state = %s' % (auth_code, state))
  554. product_agent = Agent.objects(id = str(state.productAgentId)).get() # type: Agent
  555. groupId = MyUser.groupId.default
  556. auth_bridge = get_wechat_auth_bridge(source = product_agent, app_type = APP_TYPE.WECHAT_AUTH)
  557. logger.debug(
  558. 'wechat base auth for user center login. appid = {}, code = {}, state = {}, agent = {}, group_id = {}'.format(
  559. auth_bridge.appid, auth_code, str(state.encode()), str(product_agent.id), groupId))
  560. openId = auth_bridge.authorize(auth_code)
  561. if not openId:
  562. logger.error(
  563. 'auth error, app = %s; payload = %s' % (repr(auth_bridge.app), str(state.encode())))
  564. return ErrorResponseRedirect(error = u'系统错误,请重新扫码')
  565. payload = {
  566. 'authAppId': auth_bridge.app.appid,
  567. 'agentId': str(state.agentId),
  568. 'productAgentId': str(state.productAgentId),
  569. 'payOpenIdMap': {
  570. auth_bridge.bound_openid_key: BoundOpenInfo(openId = openId)
  571. }
  572. }
  573. user = MyUser.get_or_create(
  574. app_platform_type = AppPlatformType.WECHAT, open_id = openId, group_id = groupId, **payload)
  575. manager_auth_bridge = get_wechat_auth_bridge(
  576. source = product_agent, app_type = APP_TYPE.WECHAT_USER_MANAGER)
  577. manager_openid = user.get_bound_pay_openid(manager_auth_bridge.bound_openid_key)
  578. if manager_openid and (manager_openid != user.managerialOpenId):
  579. user.managerialOpenId = manager_openid
  580. user.managerialAppId = manager_auth_bridge.appid
  581. user.save()
  582. if (not manager_openid) or (not user.nickname):
  583. state.uid = str(user.id)
  584. return ExternalResponseRedirect(
  585. manager_auth_bridge.generate_auth_url_user_scope(
  586. redirect_uri = USER_AUTH_REDIRECT_URL.WECHAT_USER_CENTER_MANAGER_AUTH_USER,
  587. payload = state.encode()))
  588. else:
  589. logger.debug('redirect url is: {}'.format(state.href))
  590. response = FrontEndResponseRedirect(str(state.href))
  591. return response_with_login(request, user, response)
  592. except UserServerException as e:
  593. logger.error(e.message)
  594. return ErrorResponseRedirect(error = cn(e.message))
  595. except Exception as e:
  596. logger.exception(e)
  597. return ErrorResponseRedirect(error = cn(u'网络开小差了,重新扫码试试喔'))
  598. @trace_call(logger = logger)
  599. @error_tolerate(nil = defaultErrorResponseRedirect)
  600. def wechatUserAuthForUserCenter(request):
  601. # type: (WSGIRequest)->HttpResponse
  602. """
  603. 个人中心
  604. :param request:
  605. :return:
  606. """
  607. try:
  608. auth_code = request.GET.get('code', None)
  609. if auth_code is None:
  610. raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.AUTH_CODE_IS_NULL)
  611. state = parse_auth_payload(request) # type: UserAuthState
  612. assert state.by == UserAuthState.BY.AGENT, 'must be enter user center.'
  613. logger.info('return to wechatUserAuthForUserCenter. code = %s; state = %s' % (auth_code, state))
  614. product_agent = Agent.objects(id = str(state.productAgentId)).get() # type: Agent
  615. groupId = MyUser.groupId.default
  616. auth_bridge = get_wechat_auth_bridge(source = product_agent, app_type = APP_TYPE.WECHAT_AUTH)
  617. logger.debug(
  618. 'wechat user auth for user center login. appid = {}, code = {}, state = {}, agent = {}, group_id = {}'.format(
  619. auth_bridge.appid, auth_code, str(state.encode()), str(product_agent.id), groupId))
  620. userInfo = auth_bridge.get_user_info(auth_code = auth_code)
  621. openId = userInfo['openId']
  622. if openId is None:
  623. logger.error(
  624. 'manager auth error, app = %s; payload = %s' % (repr(auth_bridge.app), str(state.encode())))
  625. return ErrorResponseRedirect(error = u'系统错误, 请重新扫码')
  626. payload = {
  627. 'sex': userInfo.get('sex', 0),
  628. 'city': userInfo.get('city', ''),
  629. 'province': userInfo.get('province', ''),
  630. 'country': userInfo.get('country', ''),
  631. 'nickname': userInfo.get('nickname', ''),
  632. 'avatar': userInfo.get('avatar', ''),
  633. 'unionId': userInfo.get('unionid', ''),
  634. 'authAppId': auth_bridge.appid,
  635. 'payOpenIdMap': {
  636. auth_bridge.bound_openid_key: BoundOpenInfo(openId = openId)
  637. },
  638. 'agentId': str(state.agentId),
  639. 'productAgentId': str(state.productAgentId),
  640. 'managerialAppId': auth_bridge.appid,
  641. 'managerialOpenId': openId
  642. }
  643. user = MyUser.get_or_create(app_platform_type = AppPlatformType.WECHAT,
  644. open_id = openId, group_id = groupId, **payload)
  645. logger.debug('redirect url is: {}'.format(state.href))
  646. response = FrontEndResponseRedirect(str(state.href))
  647. return response_with_login(request, user, response)
  648. except UserServerException as e:
  649. logger.error(e.message)
  650. return ErrorResponseRedirect(error = cn(e.message))
  651. except WechatOAuthDummyException as e:
  652. logger.error(e.message)
  653. return WechatAuthDummyRedirect()
  654. except Exception as e:
  655. logger.exception(e)
  656. return ErrorResponseRedirect(error = cn(u'网络开小差了,重新扫码试试喔'))
  657. @trace_call(logger = logger)
  658. @error_tolerate(nil=ErrorResponseRedirect, logger=logger)
  659. def wechatManagerAuthForUserCenter(request):
  660. # type: (WSGIRequest)->HttpResponse
  661. """
  662. :param request:
  663. :return:
  664. """
  665. try:
  666. auth_code = request.GET.get(WechatAuthBridge.auth_code_key, None)
  667. if not auth_code:
  668. raise InvalidParameter(u'参数错误,请重新扫码({})'.format(ErrorCode.AUTH_CODE_IS_NULL))
  669. state = parse_auth_payload(request)
  670. assert state.by == UserAuthState.BY.AGENT, 'must enter in user center.'
  671. user = MyUser.objects.get(id=state.uid)
  672. product_agent = Agent.objects(id=str(state.productAgentId)).get()
  673. manager_auth_bridge = get_wechat_auth_bridge(
  674. source=product_agent, app_type=APP_TYPE.WECHAT_USER_MANAGER) # type: WechatAuthBridge
  675. userInfo = manager_auth_bridge.get_user_info(auth_code=auth_code)
  676. openId = userInfo['openId']
  677. if openId is None:
  678. logger.error(
  679. 'manager auth error, app = %s; payload = %s' % (repr(manager_auth_bridge.app), str(state.encode())))
  680. raise UserServerException(u'系统错误, 请重新扫码')
  681. user.sex = userInfo.get('sex', 0)
  682. user.city = userInfo.get('city', '')
  683. user.province = userInfo.get('province', '')
  684. user.country = userInfo.get('country', '')
  685. user.nickname = userInfo.get('nickname', '')
  686. user.avatar = userInfo.get('avatar', '')
  687. user.unionId = userInfo.get('unionid', '')
  688. user.set_bound_pay_openid(manager_auth_bridge.bound_openid_key, openId=openId)
  689. user.managerialAppId = manager_auth_bridge.appid
  690. user.managerialOpenId = openId
  691. user.save()
  692. logger.debug('redirect url is: {}'.format(state.href))
  693. response = FrontEndResponseRedirect(str(state.href))
  694. return response_with_login(request, user, response)
  695. except UserServerException as e:
  696. logger.error(e.message)
  697. return ErrorResponseRedirect(error=cn(e.message))
  698. except WechatOAuthDummyException as e:
  699. logger.error(e.message)
  700. return WechatAuthDummyRedirect()
  701. except Exception as e:
  702. logger.exception(e)
  703. return ErrorResponseRedirect(error=cn(u'网络开小差了,重新扫码试试喔'))
  704. @permission_required(ROLE.myuser)
  705. def baseMoniAccess(request):
  706. """
  707. moni app 的鉴权
  708. """
  709. code = request.GET.get("code", None)
  710. if code is None:
  711. raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.MONI_AUTH_IS_NULL)
  712. state = parse_auth_payload(request) # type: UserAuthState
  713. inhouseMoniApp = MoniApp.objects.filter(appid=state.appid).first() # type: MoniApp
  714. if not inhouseMoniApp:
  715. raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.MONI_APP_IS_NULL)
  716. user = MyUser.objects.filter(id=state.uid).first()
  717. if not user:
  718. raise UserServerException(u'网络开小差了,重新扫码试试喔(%s)' % ErrorCode.LOGIN_USER_IS_NULL)
  719. # 存在app 的情况下 使用app进行解码 写入数据
  720. moniAuthBridge = WechatAuthBridge(WechatAuthApp(appid=inhouseMoniApp.appid, secret=inhouseMoniApp.secret))
  721. openId = moniAuthBridge.authorize(code)
  722. user.set_bound_pay_openid(moniAuthBridge.bound_openid_key, openId=openId)
  723. user.save()
  724. productAgent = Agent.objects.get(id=state.productAgentId)
  725. dev = Device.get_dev(state.devNo)
  726. response = get_homepage_response(AppPlatformType.WECHAT, user, dev, state.chargeIndex, productAgent)
  727. return response_with_login(request, user, response)
  728. @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"系统繁忙,请稍后重试"))
  729. @permission_required(ROLE.myuser)
  730. @request_limit_by_user(operation='equipmentPara', logger=logger)
  731. def equipmentPara(request):
  732. # type: (WSGIRequest)->HttpResponse
  733. """
  734. 扫码后获取设备侧以及用户的相关信息
  735. """
  736. currentUser = request.user # type: MyUser
  737. logicalCode = request.GET.get("logicalCode")
  738. force = True if request.GET.get('refresh', 'false') == 'true' else False
  739. dev = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  740. if not dev:
  741. logger.info('(%s) cannot find device, devNo = %s' % (request.user, logicalCode))
  742. return JsonErrorResponse(description=u"该设备尚未注册(1002)")
  743. if not dev.group:
  744. logger.info('can not find group. dev = %s' % dev)
  745. return JsonErrorResponse(description=u'该设备未注册,暂时无法使用支付宝或者微信支付, 请投币(1010)')
  746. if not dev.dealer:
  747. logger.info('can not find dealer. dev = %s; group = %s' % (str(dev), str(dev.group)))
  748. return JsonErrorResponse(description=u'该设备未注册,暂时无法使用支付宝或者微信支付, 请投币(1011)')
  749. if check_black_user(dealerId=dev.get("ownerId"), openId = request.user.openId):
  750. return JsonErrorResponse(u"该设备暂不对您开放,请联系经销商")
  751. agent = Agent.objects(id=str(dev.dealer['agentId'])).first() # type: Agent
  752. agentFeatures = set(agent.features) if agent is not None else set([])
  753. dealer_features = map(lambda x: x['key'], filter(lambda x: x['value'] is True, dev.dealer['featureList']))
  754. if 'mini_recharge' in dealer_features:
  755. agentFeatures.add('mini_recharge')
  756. if 'mini_card_recharge' in dealer_features:
  757. agentFeatures.add('mini_card_recharge')
  758. devType = deepcopy(dev.devType)
  759. try:
  760. portDict = dev.deviceAdapter.get_port_status(force)
  761. if not force:
  762. dev.deviceAdapter.async_update_portinfo_from_dev()
  763. if portDict:
  764. chargeIndex = {}
  765. for index, info in portDict.items():
  766. if info['status'] == Const.DEV_WORK_STATUS_IDLE:
  767. chargeIndex[index] = 'idle'
  768. elif info['status'] == Const.DEV_WORK_STATUS_WORKING:
  769. chargeIndex[index] = 'busy'
  770. elif info['status'] == Const.DEV_WORK_STATUS_FAULT:
  771. chargeIndex[index] = 'fault'
  772. elif info['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
  773. chargeIndex[index] = 'ban'
  774. elif info['status'] == Const.DEV_WORK_STATUS_CONNECTED:
  775. chargeIndex[index] = 'connected'
  776. elif info['status'] == Const.DEV_WORK_STATUS_FINISHED:
  777. chargeIndex[index] = 'finished'
  778. elif info['status'] == Const.DEV_WORK_STATUS_ESTOP:
  779. chargeIndex[index] = 'estop'
  780. elif info['status'] == Const.DEV_WORK_STATUS_READY:
  781. chargeIndex[index] = 'ready'
  782. else:
  783. chargeIndex[index] = 'busy'
  784. devType.update({"chargeIndex": chargeIndex})
  785. except ServiceException as e:
  786. return JsonErrorResponse(description=e.result.get('description'))
  787. except Exception as e:
  788. logger.exception('cannot get_port_status, error=%s' % (str(e),))
  789. return JsonErrorResponse(description=u'未知错误')
  790. data = {
  791. "devType": devType,
  792. "groupId": dev.groupId,
  793. "cityId": dev.group.get('districtId', ''),
  794. "inFreeGroup": dev.group.get('isFree', False),
  795. "lbs": dev.lbs,
  796. "instructions": dev.get('instructions', ''),
  797. "logicalCode": dev.logicalCode,
  798. "payAfterAd": dev.dealer['adShow'],
  799. "dealerId": dev.ownerId,
  800. "dealerDes": dev.dealer['description'],
  801. 'devNo': dev.devNo,
  802. 'channelType': dev.channelType,
  803. 'avatarUrl': currentUser.avatar,
  804. 'nickname': currentUser.nickname,
  805. 'openId': currentUser.openId,
  806. 'agentFeatures': list(agentFeatures),
  807. 'countDown': False,
  808. 'bottomAd': dev.dealer.get('bottomAd', {}),
  809. 'noRecharge': dev.dealer.get('noRecharge', False),
  810. 'favorite': True if dev.devNo in currentUser.collectedDeviceList else False,
  811. "payAfterUse": dev.get("otherConf", dict()).get("payAfterUse", False),
  812. 'majorDeviceType': dev.majorDeviceType,
  813. 'subTemplateId': agent.get_user_sub_template_id_list(),
  814. 'priceDescription': dev.priceDescription,
  815. 'popPriceDescriptionButton': dev.group.popPriceDescriptionButton
  816. }
  817. if "hasTempPackage" in dev.dealer:
  818. if dev.devTypeCode in [Const.DEVICE_TYPE_CODE_WEIFULE_POLICY_CLASSIC]:
  819. data["hasTempPackage"] = False
  820. data["displayTempPackage"] = False
  821. elif dev.devTypeCode in support_policy_weifule + support_policy_device:
  822. try:
  823. data["displayTempPackage"] = dev.dealer.get("displayTempPackage", True)
  824. packages = dev.deviceAdapter.user_show_package(isTemp=True)
  825. if packages:
  826. data["hasTempPackage"] = True
  827. else:
  828. data["hasTempPackage"] = False
  829. except Exception as e:
  830. logger.error("[equipmentPara] get hasTempPackage error = {}".format(e))
  831. data["hasTempPackage"] = False
  832. else:
  833. if dev.dealer.get("hasTempPackage", None) is True:
  834. data["hasTempPackage"] = dev.dealer.get("hasTempPackage")
  835. data["displayTempPackage"] = dev.dealer.get("displayTempPackage", True)
  836. if dev.need_fetch_online:
  837. data.update({'online': DeviceOnlineStatus.DEV_STATUS_ONLINE})
  838. else:
  839. data.update({'online': DeviceOnlineStatus.DEV_STATUS_OFFLINE})
  840. if "telVerify" in agent.features:
  841. needTelVerify = check_user_tel(request.user)
  842. data.update({
  843. "needTelVerify": needTelVerify
  844. })
  845. data.update({'countDown': dev.deviceAdapter.support_count_down()})
  846. if dev.devTypeCode == Const.DEVICE_TYPE_CODE_TIMESWITCH7:
  847. pricePerHour = dev.my_obj.otherConf.get('pricePerHour', 2.0)
  848. data.update({'pricePerHour': pricePerHour})
  849. elif dev.devTypeCode in [
  850. Const.DEVICE_TYPE_CODE_CAR_NENGPAI,
  851. Const.DEVICE_TYPE_CODE_CHARGE_WEIFULE_CAR,
  852. Const.DEVICE_TYPE_CODE_CAR_WEIFULE_CHARGING_DOUB,
  853. Const.DEVICE_TYPE_CODE_CAR_WEIFULE_21KW,
  854. Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,
  855. Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG,
  856. ]:
  857. infos = dev.deviceAdapter.get_policy_for_user()
  858. data.update({"policyInfos": infos})
  859. resultResponse = JsonResponse({'result': 1, 'description': '', 'payload': data})
  860. resultResponse = Agent.record_cookie(dev.dealer['agentId'], resultResponse)
  861. return resultResponse
  862. @error_tolerate(nil = defaultErrorResponseRedirect)
  863. @permission_required(ROLE.myuser)
  864. def deviceInfo(request):
  865. """
  866. 通过logicalCode获取 设备的一些基本信息, 功能上需要和equipment区分开
  867. :param request:
  868. :return:
  869. """
  870. logicalCode = request.GET.get("logicalCode")
  871. if not logicalCode:
  872. return JsonErrorResponse(description = u"无效的设备编号")
  873. dev = Device.get_dev_by_l(logicalCode)
  874. if not dev:
  875. return JsonErrorResponse(description = u"无效的设备编号")
  876. group = Group.get_group(dev.get("groupId", ""))
  877. # TODO zjl 目前只添加这些信息,后续有需要再添加 但是此接口定义为获取设备的简易信息 需要和equipment区分
  878. data = {
  879. "devNo": dev.get("devNo", ""),
  880. "logicalCode": dev.get("logicalCode", ""),
  881. "ownerId": dev.get("ownerId", ""),
  882. "groupId": dev.get("groupId", ""),
  883. "groupName": group.get("groupName", ""),
  884. "isFree": group.get("isFree", False)
  885. }
  886. return JsonOkResponse(payload = data)
  887. @permission_required(ROLE.myuser)
  888. def userBalance(request):
  889. # type: (WSGIRequest)->JsonResponse
  890. """
  891. 用户余额
  892. 用户余额是以地址为单位建立 但是由于地址可以设置通用 并且个人中心也需要显示总余额
  893. """
  894. logicalCode = request.GET.get("logicalCode")
  895. if not logicalCode:
  896. overallBalance = sum((u.balance for u in request.user.product_users), RMB(0))
  897. return JsonOkResponse(
  898. payload={
  899. 'balance': overallBalance,
  900. 'overallBalance': overallBalance,
  901. 'currencyCoins': overallBalance
  902. })
  903. dev = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  904. if not dev:
  905. return JsonErrorResponse(description=u'设备没有注册,或者二维码错误,请联系客服处理')
  906. if not dev.is_registered:
  907. return JsonErrorResponse(description=u'设备没有注册,请联系客服处理')
  908. if dev.ownerId != dev.group.ownerId:
  909. return JsonErrorResponse(description=u'设备注册信息错误,请联系客服处理')
  910. if dev.group.groupId != request.user.groupId:
  911. product_agent = get_user_manager_agent(dev.owner) # type: Agent
  912. if str(product_agent.id) != request.user.productAgentId:
  913. return JsonErrorResponse(description=u'设备投放地址不属于该平台,请重新扫描设备二维码。')
  914. # 分别为用户总余额、用户经销商下的余额、用户的通用地址余额
  915. overall, dealer_balance, usable_balance = request.user.get_balance_in_dealer(dev.owner, dev.group)
  916. return JsonOkResponse(
  917. payload={
  918. 'balance': usable_balance,
  919. 'balanceInDealer': dealer_balance,
  920. 'overallBalance': overall
  921. })
  922. @permission_required(ROLE.myuser)
  923. def getBalanceList(request):
  924. # type: (WSGIRequest)->Union[HttpResponse,JsonResponse]
  925. """
  926. 用户账户详情
  927. :param request:
  928. :return:
  929. """
  930. pageIndex = int(request.GET.get('pageIndex', 1))
  931. pageSize = int(request.GET.get('pageSize', 10))
  932. currentGroupId = request.GET.get('groupId', None)
  933. if currentGroupId == '-1':
  934. currentGroupId = None
  935. if currentGroupId:
  936. current_group = Group.get_group(currentGroupId) # type: GroupDict
  937. else:
  938. current_group = None # type: None
  939. totalCharge, totalBestow, total, dataList = request.user.filter_my_balance(current_group)
  940. cmp_dealer = lambda x, y: 1 if x['dealerId'] > y['dealerId'] else -1
  941. dataList.sort(cmp = cmp_dealer)
  942. return JsonResponse(
  943. {
  944. 'result': 1,
  945. 'description': '',
  946. 'payload': {
  947. 'totalCharge': totalCharge,
  948. 'totalBestow': totalBestow,
  949. 'total': total,
  950. 'dataList': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  951. }
  952. }
  953. )
  954. def asynDiscountList(request):
  955. # type: (WSGIRequest)->JsonResponse
  956. """
  957. 用户充值菜单
  958. :param request:
  959. :return:
  960. """
  961. devNo = Device.get_dev_no_from_request(request)
  962. dev = Device.get_dev(devNo)
  963. if dev is None:
  964. return JsonResponse({'result': 0, 'description': u'该设备未开通网络支付,请投币或者联系客服(1000)', 'payload': {}})
  965. group = Group.get_group(dev['groupId']) # type:GroupDict
  966. if not group:
  967. return JsonResponse({'result': 0, 'description': u'该设备未开通网络支付,请投币或者联系客服(1001)', 'payload': {}})
  968. return JsonResponse({
  969. 'result': 1,
  970. 'description': 'SUCCESS',
  971. 'payload': {
  972. 'discountList': group.recharge_rule_list
  973. }
  974. })
  975. @permission_required(ROLE.myuser)
  976. def getPackage(request):
  977. # type: (WSGIRequest)->JsonResponse
  978. """
  979. 获取设备套餐
  980. :param request:
  981. :return:
  982. """
  983. devNo = request.GET.get("devNo")
  984. device = Device.get_dev(devNo) # type: DeviceDict
  985. if device is None:
  986. return JsonResponse({'result': 0, 'description': u'无此设备', 'payload': {}})
  987. washConfig = device['washConfig']
  988. otherConf = device.get('otherConf')
  989. if "displaySwitchs" in otherConf:
  990. displaySwitchs = otherConf.get('displaySwitchs')
  991. displaySwitchs = dict(filter(lambda x: "display" in x[0], displaySwitchs.items()))
  992. else:
  993. displaySwitchs = {
  994. 'displayCoinsSwitch': True,
  995. 'displayTimeSwitch': True,
  996. 'displayPriceSwitch': True
  997. }
  998. if device.devTypeCode in support_policy_weifule + support_policy_device + [
  999. Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE,
  1000. Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,
  1001. Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG,
  1002. Const.DEVICE_TYPE_CODE_CHARGE_XIAOKEDOU
  1003. ]:
  1004. try:
  1005. if device.deviceAdapter.support_device_package:
  1006. packages = device.deviceAdapter.user_show_package()
  1007. return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': packages})
  1008. except Exception as e:
  1009. logger.exception(e)
  1010. return JsonResponse({'result': 0, 'description': '当前套餐参数有误, 请联系经销商重新配置', 'payload': []})
  1011. packages = []
  1012. for packageId, rule in washConfig.items():
  1013. # 没有启用的套餐 直接掠过
  1014. if not rule.get("switch", True):
  1015. continue
  1016. price = rule['price']
  1017. imgList = []
  1018. try:
  1019. for img in rule.get('imgList', []):
  1020. if img.startswith('/'):
  1021. imgList.append('{}{}'.format(settings.OSS_RESOURCE_URL, img))
  1022. else:
  1023. imgList.append(img)
  1024. except Exception as e:
  1025. logger.exception(e)
  1026. imgList = rule.get('imgList', [])
  1027. item = {
  1028. 'id': packageId,
  1029. 'name': rule['name'],
  1030. 'time': rule['time'],
  1031. 'price': price,
  1032. 'description': rule.get('description', ''),
  1033. 'imgList': imgList,
  1034. 'unit': rule.get('unit', u'分钟'),
  1035. }
  1036. if rule.get('basePrice'):
  1037. item.update({'basePrice': rule.get('basePrice')})
  1038. if rule.get('sn', None) is not None:
  1039. item.update({'sn': rule.get('sn')})
  1040. if rule['name'] == u'充满自停' and float(rule['coins']) == 0 and float(price) == 0:
  1041. item.update({'displayCoinsSwitch': False, 'displayTimeSwitch': False, 'displayPriceSwitch': False})
  1042. else:
  1043. item.update(displaySwitchs)
  1044. packages.append(item)
  1045. packages = sorted(packages, key=lambda x: (x.get('sn'), x.get('price')))
  1046. return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': packages})
  1047. @permission_required(ROLE.myuser)
  1048. def getTempPackage(request):
  1049. # type: (WSGIRequest)->JsonResponse
  1050. """
  1051. 设备套餐
  1052. :param request:
  1053. :return:
  1054. """
  1055. def cmp_by_price(x, y):
  1056. if x['price'] < y['price']:
  1057. return -1
  1058. elif x['price'] > y['price']:
  1059. return 1
  1060. else:
  1061. return 0
  1062. devNo = Device.get_dev_no_from_request(request)
  1063. if not devNo:
  1064. return JsonResponse({'result': 0, 'description': u'获取数据失败,请重新扫码登录'})
  1065. device = Device.get_dev(devNo)
  1066. if device is None:
  1067. return JsonResponse({'result': 0, 'description': u'无此设备', 'payload': {}})
  1068. if device['devType']['code'] in support_policy_weifule + support_policy_device:
  1069. try:
  1070. if device.deviceAdapter.support_device_package:
  1071. packages = device.deviceAdapter.user_show_package(isTemp=True)
  1072. if not packages:
  1073. return JsonResponse({'result': 0, 'description': '当前设备未配置临时套餐, 请联系经销商去配置', 'payload': {}})
  1074. else:
  1075. return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': packages})
  1076. else:
  1077. return JsonResponse({'result': 0, 'description': '当前套餐参数有误, 请联系经销商重新配置', 'payload': []})
  1078. except:
  1079. return JsonResponse({'result': 0, 'description': '当前套餐参数有误, 请联系经销商重新配置', 'payload': []})
  1080. elif device['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,]:
  1081. tempWashConfig = device['tempWashConfig']
  1082. if not tempWashConfig:
  1083. return JsonResponse({'result': 0, 'description': u'当前设备未配置临时套餐, 请联系经销商去配置', 'payload': {}})
  1084. packages = device.deviceAdapter.user_show_package(isTemp=True)
  1085. return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': packages})
  1086. if device['tempWashConfig'] == {}:
  1087. Device.get_and_update_device_cache(device["devNo"], tempWashConfig = device['washConfig'])
  1088. device = Device.get_dev(devNo)
  1089. tempWashConfig = device['tempWashConfig']
  1090. otherConf = device.get('otherConf')
  1091. if "displayTempSwitchs" in otherConf:
  1092. displayTempSwitchs = otherConf.get('displayTempSwitchs')
  1093. displayTempSwitchs = dict(filter(lambda x: "display" in x[0], displayTempSwitchs.items()))
  1094. else:
  1095. displayTempSwitchs = {'displayCoinsSwitch': True,
  1096. 'displayTimeSwitch': True,
  1097. 'displayPriceSwitch': True,
  1098. }
  1099. group = Group.get_group(device['groupId'])
  1100. # 探测是否地址为免费活动组,默认为否
  1101. is_free_service = group.get('isFree', False)
  1102. appendix = u' 免费使用' if is_free_service else ''
  1103. packages = []
  1104. for packageId, rule in tempWashConfig.items():
  1105. item = {
  1106. 'id': packageId,
  1107. 'coins': rule['coins'],
  1108. 'name': rule['name'] + appendix,
  1109. 'time': rule['time'],
  1110. 'price': rule['price'],
  1111. 'description': rule.get('description', ''),
  1112. 'imgList': rule.get('imgList', []),
  1113. 'unit': rule.get('unit', u'分钟')
  1114. }
  1115. if rule.get('basePrice'):
  1116. item.update({'basePrice': rule.get('basePrice')})
  1117. if rule.get('sn', None) is not None:
  1118. item.update({'sn': rule.get('sn')})
  1119. item.update(displayTempSwitchs)
  1120. packages.append(item)
  1121. packages = sorted(packages, key = lambda x: (x.get('sn'), x.get('price')))
  1122. return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': packages})
  1123. def authCallback(request, gateway):
  1124. try:
  1125. state = UserAuthState.decode(str(request.GET.get('payload'))) # type: UserAuthState
  1126. if not state.is_valid():
  1127. return ErrorResponseRedirect(error = cn(u'网络异常,请重新扫码(10000)'))
  1128. if state.by == UserAuthState.BY.AGENT:
  1129. source = Agent.objects(id = str(state.agentId)).get() # type: Agent
  1130. group_id = MyUser.groupId.default
  1131. dealer = None
  1132. else:
  1133. dev = Device.get_dev(state.devNo) # type: DeviceDict
  1134. if not dev:
  1135. return ErrorResponseRedirect(error = u'该设备未开通网络支付,请投币或者联系客服(1006)')
  1136. source = dealer = dev.owner
  1137. if not dealer:
  1138. return ErrorResponseRedirect(error = u'该设备未开通网络支付,请投币或者联系客服(1007)')
  1139. group_id = dev.groupId
  1140. # 配置平台的代理商ID必定配置自定义公众号, 否则扫码客户无法知道平台代理商是谁
  1141. product_agent = get_user_manager_agent(source)
  1142. if str(product_agent.id) != state.productAgentId:
  1143. return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10004)')
  1144. if gateway == AppPlatformType.ALIPAY:
  1145. auth_bridge = get_ali_auth_bridge(source = product_agent,
  1146. app_type = APP_TYPE.ALIPAY_AUTH) # type: AlipayAuthBridge
  1147. else:
  1148. return ErrorResponseRedirect(error = cn(u'参数错误,请重新扫码(10001)'))
  1149. auth_code = request.GET.get(auth_bridge.auth_code_key)
  1150. if not auth_code:
  1151. return ErrorResponseRedirect(error = cn(u'参数错误,请重新扫码(10002)'))
  1152. user_info = auth_bridge.get_user_info(auth_code = auth_code)
  1153. open_id = user_info.pop('openId')
  1154. user = MyUser.get_or_create(
  1155. app_platform_type = auth_bridge.gateway_type,
  1156. open_id = open_id,
  1157. group_id = group_id,
  1158. authAppId = auth_bridge.appid,
  1159. agentId = state.agentId,
  1160. productAgentId = state.productAgentId,
  1161. payOpenIdMap = {
  1162. auth_bridge.bound_openid_key: BoundOpenInfo(openId = open_id)
  1163. },
  1164. **user_info)
  1165. if state.by == UserAuthState.BY.AGENT:
  1166. response = FrontEndResponseRedirect(state.href)
  1167. else:
  1168. response = get_homepage_response(gateway, user, dev, state.chargeIndex if state.chargeIndex else '',
  1169. product_agent)
  1170. return response_with_login(request, user, response)
  1171. except (JDException, AliException) as e:
  1172. logger.error(repr(e))
  1173. return ErrorResponseRedirect(error = cn(e.errMsg))
  1174. @error_tolerate(nil = u"获取消费详情失败", logger = logger)
  1175. @permission_required(ROLE.myuser)
  1176. def getConsumeRecord(request):
  1177. """
  1178. 获取用户的单一的 消费订单记录
  1179. :param request:
  1180. :return:
  1181. """
  1182. recordId = request.GET.get("id", None)
  1183. cardTicketId = request.GET.get('cardTicketId', None)
  1184. # 这个接口是同时 查询虚拟卡消费记录 以及用户的直接消费记录 的入口
  1185. if not any([recordId, cardTicketId]):
  1186. return JsonErrorResponse(description = u'参数错误,请刷新后再试')
  1187. if recordId:
  1188. ownerId = request.GET.get('ownerId', None)
  1189. if ownerId:
  1190. record = ClientConsumeModelProxy.get_one(shard_filter = {'ownerId': ownerId},
  1191. id = recordId) # type: ConsumeRecord
  1192. else:
  1193. record = ConsumeRecord.objects(id = recordId).first()
  1194. else:
  1195. record = VCardConsumeRecord.objects(id = cardTicketId).first() # type: VCardConsumeRecord
  1196. if not record:
  1197. return JsonErrorResponse(description = u"未查询到相应订单,请刷新页面重试")
  1198. payload = record.to_user_detail()
  1199. try:
  1200. agentId = request.user.productAgentId
  1201. agent = Agent.objects.get(id = agentId)
  1202. except Exception as e:
  1203. logger.exception(e)
  1204. agent = None
  1205. if payload.get("actualNeedTime"):
  1206. elecKeys = [_key for _key in payload.keys() if _key.startswith("elec") or _key.endswith("elec")]
  1207. for _elecKey in elecKeys:
  1208. payload.pop(_elecKey, None)
  1209. if not agent or 'show_elec_data_for_user' not in agent.features:
  1210. payload.pop('elec', None)
  1211. payload.pop('needElec', None)
  1212. if agent and 'hide_time_data_for_user' in agent.features:
  1213. payload.pop("leftTime", None)
  1214. payload.pop("duration", None)
  1215. payload = UserConsumeFilter(record.owner, payload).filter()
  1216. return JsonOkResponse(payload = payload)
  1217. @permission_required(ROLE.myuser)
  1218. def asynTransactionRecord(request):
  1219. # type: (WSGIRequest)->JsonResponse
  1220. """
  1221. 用户消费记录
  1222. :param request:
  1223. :return: JsonResponse
  1224. """
  1225. pageIndex = int(request.GET.get('pageIndex', 1))
  1226. pageSize = int(request.GET.get('pageSize', 10))
  1227. startTime = request.GET.get('startTime', Const.QUERY_START_DATE)
  1228. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  1229. dataList = []
  1230. if 'cardTicketId' in request.GET and request.GET.get('cardTicketId'):
  1231. records = VCardConsumeRecord.objects.filter(cardId = request.GET.get('cardTicketId')).order_by('-dateTimeAdded')
  1232. total = records.count()
  1233. for rcd in records.paginate(pageIndex, pageSize):
  1234. dataList.append(rcd.summary)
  1235. else:
  1236. dealer_ids = MyUser.get_dealer_ids(openId = request.user.openId, productAgentId = request.user.productAgentId)
  1237. if len(dealer_ids) > 0:
  1238. records = ClientConsumeModelProxy.get_data_list(
  1239. ownerId__in = dealer_ids,
  1240. startTime = startTime,
  1241. endTime = endTime,
  1242. openId = request.user.openId,
  1243. isNormal = True,
  1244. hint = [('openId', 1), ('dateTimeAdded', -1)]) # type: CustomQuerySet
  1245. total = records.count()
  1246. for rcd in records.paginate(pageIndex, pageSize):
  1247. dataList.append(rcd.summary)
  1248. else:
  1249. total = 0
  1250. return JsonResponse(
  1251. {
  1252. 'result': 1,
  1253. 'description': '',
  1254. 'payload': {'total': total, 'dataList': dataList}
  1255. })
  1256. @permission_required(ROLE.myuser)
  1257. def getChargeRecordDetail(request):
  1258. # type: (WSGIRequest)->JsonResponse
  1259. """
  1260. 用户充值详细记录
  1261. :param request:
  1262. :return: JsonResponse
  1263. """
  1264. _id = str(request.GET.get('id'))
  1265. ownerId = request.GET.get('ownerId')
  1266. record = ClientRechargeModelProxy.get_one(shard_filter = {'ownerId': ownerId}, id = _id) # type: RechargeRecord
  1267. if not record:
  1268. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  1269. payload = {
  1270. 'createdTime': record.dateTimeAdded,
  1271. 'orderNo': record.orderNo,
  1272. 'amount': record.my_amount,
  1273. 'groupName': record.groupName,
  1274. 'groupNumber': record.groupNumber,
  1275. 'address': record.address,
  1276. 'logicalCode': record.logicalCode,
  1277. 'devTypeName': record.dev_type_name,
  1278. 'via': record.via,
  1279. 'ownerId': record.ownerId
  1280. }
  1281. payload.update(record.extra_detail_info)
  1282. return JsonResponse(
  1283. {
  1284. 'result': 1,
  1285. 'description': '',
  1286. 'payload': payload
  1287. }
  1288. )
  1289. @permission_required(ROLE.myuser)
  1290. def hybridStartAction(request):
  1291. """
  1292. 此处有红包链接, 可以判断出往下走的流程是拉起支付还是直接启动
  1293. """
  1294. payload = json.loads(request.body)
  1295. urlId = payload.get('urlId')
  1296. dev = Device.get_dev(payload['devNo'])
  1297. if not dev:
  1298. return JsonErrorResponse(description= '设备参数缺失, 请重试')
  1299. if not urlId:
  1300. return JsonErrorResponse(description='传入参数有误, 请重试')
  1301. url = payload.pop('url', None)
  1302. payload = {
  1303. "packageId": payload['packageId'],
  1304. "groupId": dev.groupId,
  1305. "devNo": dev['devNo'],
  1306. "logicalCode": dev['logicalCode'],
  1307. "openId": payload['openId'],
  1308. "attachParas": payload['attachParas']
  1309. }
  1310. serviceCache.set('urlId_{}'.format(urlId), payload)
  1311. return JsonResponse(
  1312. {
  1313. 'result': 1,
  1314. 'description': '',
  1315. 'payload': {'url': url}
  1316. }
  1317. )
  1318. @permission_required(ROLE.myuser)
  1319. def getHybridStartActionInfo(request):
  1320. """
  1321. 返回缓存的参数 直接拉起支付
  1322. """
  1323. payload = json.loads(request.body)
  1324. urlId = payload.get('mktId')
  1325. openId = request.user.openId
  1326. redpack = Redpack.objects.filter(openId=openId, urlId=urlId).first()
  1327. if redpack:
  1328. if redpack.taskStatus != redpack.Result.FINISHED:
  1329. try:
  1330. # 去查询
  1331. ApiRequest = json.loads(redpack.extra.get('ApiRequest', ''))
  1332. clicklink = ApiRequest['Seatbid'][0]['Bid'][0]['Ads'][0]['Trackers']['Imps'][0]
  1333. adid = ApiRequest['Seatbid'][0]['Bid'][0]['Ads'][0]['Id']
  1334. from apps.thirdparties.aliyun import AlipayYunMaV3
  1335. resp = AlipayYunMaV3().query_task_status(
  1336. clicklink=clicklink,
  1337. openId=openId,
  1338. adid=adid,
  1339. )
  1340. if resp.body.success and resp.body.result.success:
  1341. redpack = Redpack.take_effect(openId=openId, urlId=urlId,
  1342. **{'ApiResult': json.dumps(resp.body.result.to_map(),
  1343. ensure_ascii=False)})
  1344. RedpackBuilder._set_alipay_key(openId, redpack.factoryCode, urlId, redpack.money.mongo_amount,
  1345. showType=redpack.showType)
  1346. else:
  1347. pass
  1348. except:
  1349. import traceback
  1350. logger.error(traceback.format_exc())
  1351. else:
  1352. pass
  1353. if redpack.taskStatus == redpack.Result.FINISHED:
  1354. cacheInfo = serviceCache.get('urlId_{}'.format(urlId))
  1355. serviceCache.delete('urlId_{}'.format(urlId))
  1356. if urlId and cacheInfo:
  1357. logicalCode = cacheInfo['logicalCode']
  1358. attachParas = cacheInfo['attachParas']
  1359. device = Device.get_dev_by_l(logicalCode)
  1360. if "isTempPackage" in attachParas and attachParas['isTempPackage'] is True:
  1361. washConfig = device["tempWashConfig"]
  1362. else:
  1363. washConfig = device["washConfig"]
  1364. package = washConfig.get(cacheInfo['packageId'])
  1365. if not package:
  1366. payload = {
  1367. "startAction": False,
  1368. "logicalCode": logicalCode
  1369. }
  1370. else:
  1371. showInfo = {
  1372. 'goodsInfo': {
  1373. 'name': '{}, {}'.format(device.majorDeviceType, device.logicalCode),
  1374. 'port': attachParas.get('chargeIndex'),
  1375. },
  1376. 'packageInfo': {
  1377. 'name': '{}{}'.format(package.get('time', ''), package.get('unit', '')),
  1378. 'coins': package['coins'],
  1379. 'price': package['price']
  1380. },
  1381. 'redPackInfo': {
  1382. 'price': min(redpack.money.amount, package['price']),
  1383. # 'coins': Redpack.pre_deducted_coins(str(redpack.id), package),
  1384. },
  1385. # 'checkoutInfo': {
  1386. # 'price': (RMB(package['price']) - redpack.money).mongo_amount,
  1387. # 'coins': RMB(package['coins'] - Redpack.pre_deducted_coins(str(redpack.id), package)).mongo_amount,
  1388. # },
  1389. }
  1390. attachParas['redpackId'] = str(redpack.id)
  1391. payload = {
  1392. "packageId": cacheInfo['packageId'],
  1393. "groupId": cacheInfo['groupId'],
  1394. "devNo": cacheInfo['devNo'],
  1395. "logicalCode": logicalCode,
  1396. "openId": cacheInfo['openId'],
  1397. "attachParas": attachParas,
  1398. "startAction": True,
  1399. 'showInfo': showInfo
  1400. }
  1401. else:
  1402. payload = {
  1403. "startAction": False,
  1404. "logicalCode": redpack.logicalCode
  1405. }
  1406. return JsonResponse(
  1407. {
  1408. 'result': 1,
  1409. 'description': '',
  1410. 'payload': payload
  1411. }
  1412. )
  1413. else:
  1414. return JsonResponse(
  1415. {
  1416. 'result': 1,
  1417. 'description': '',
  1418. 'payload': {'startAction': False}
  1419. }
  1420. )
  1421. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  1422. @permission_required(ROLE.myuser)
  1423. def submitFeedback(request):
  1424. # type: (WSGIRequest)->JsonResponse
  1425. """
  1426. 用户提交反馈
  1427. :param request:
  1428. :return:
  1429. """
  1430. openId = request.user.openId
  1431. with memcache_lock(key="{openId}.submitFeedBack".format(openId=openId), value='1', expire=60) as acquired:
  1432. if acquired:
  1433. try:
  1434. payload = feedbackSchema(json.loads(request.body))
  1435. except MultipleInvalid as e:
  1436. logger.exception(e)
  1437. return JsonErrorResponse(description = u"信息不完整,请补充信息或尝试重新扫码")
  1438. dev = Device.get_dev_by_logicalCode(payload['detailInfo']['logicalCode']) # type: DeviceDict
  1439. if not dev:
  1440. return JsonErrorResponse(description = u"当前设备不存在,请重新扫码")
  1441. if not dev.is_registered:
  1442. return JsonErrorResponse(description = u'当前设备已经被运营商解绑定(1001)')
  1443. group = dev.group # type: GroupDict
  1444. if group is None:
  1445. logger.error('[submitFeedback] failed to get group, device\'s logicalCode=%s groupId=%s'
  1446. % (dev['logicalCode'], dev['groupId']))
  1447. return JsonErrorResponse(description = u"当前设备已经被运营商解绑定(1002)")
  1448. feedbackPayload = {
  1449. 'openId': openId,
  1450. 'ownerId': dev.ownerId,
  1451. 'nickname': request.user.nickname,
  1452. 'description': payload['description'],
  1453. 'phone': payload['phone'],
  1454. 'feedType': payload['feedType'],
  1455. 'imgList': payload['imgList'],
  1456. 'isRead': True
  1457. }
  1458. detail_info = payload.pop('detailInfo')
  1459. if payload['feedType'] == 'netpay':
  1460. detail_info = {
  1461. 'orderNo': detail_info['orderNo']
  1462. }
  1463. detail_info.update(dev.identity_info)
  1464. feedbackPayload['detailInfo'] = detail_info
  1465. feedback = FeedBack(**feedbackPayload).save()
  1466. if bool(payload.get('orderNo')) and not feedbackPayload['feedType'] == 'fault':
  1467. order = ConsumeRecord.objects(
  1468. ownerId = dev.ownerId,
  1469. orderNo = feedbackPayload['consumeRecordOrderNo']
  1470. ).first() # type: ConsumeRecord
  1471. if not order:
  1472. return JsonErrorResponse(description = u'您选择的订单不存在,请重新选择。')
  1473. if order.feedbackId:
  1474. return JsonErrorResponse(description = u'您选择的订单已有投诉反馈,请等待设备运营商处理。')
  1475. updated = order.update(feedbackId = ObjectId(feedback.id))
  1476. if not updated:
  1477. logger.info('failed to update ConsumeRecord feedbackId = %s' % (str(feedback.id),))
  1478. dealer = Dealer.objects(id = str(dev['ownerId'])).first()
  1479. if dealer is None:
  1480. logger.error('[submitFeedback] cannot get dealer by id = %s' % (str(dev['ownerId']),))
  1481. return JsonOkResponse()
  1482. agent = Agent.objects(id = str(dealer.agentId)).first()
  1483. if agent is None:
  1484. logger.error('[submitFeedback] cannot get agent by id = %s' % (str(dealer.agentId),))
  1485. return JsonOkResponse()
  1486. if payload['feedType'] == 'fault':
  1487. msgType = u'设备故障'
  1488. else:
  1489. msgType = u'订单投诉'
  1490. msg = u'尊敬的%s用户%s,您的客户刚才给您报告了一条【%s】的信息,请您登录后台,从【用户反馈】查看详情' \
  1491. % (agent.productName, dealer.nickname, msgType)
  1492. task_caller('report_feedback_to_dealer_via_wechat', dealerId = str(dealer.id),
  1493. msg = msg,
  1494. nickname = request.user.nickname,
  1495. feedbackTime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
  1496. return JsonOkResponse()
  1497. else:
  1498. return JsonErrorResponse(description = u'您已正在提交')
  1499. @error_tolerate(nil = JsonErrorResponse(description = u'获取反馈失败'), logger = logger)
  1500. @permission_required(ROLE.myuser)
  1501. def getFeedbackList(request):
  1502. # type: (WSGIRequest)->JsonResponse
  1503. """
  1504. 用户提交反馈
  1505. :param request:
  1506. :return:
  1507. """
  1508. openId = request.user.openId
  1509. pageIndex = int(request.GET.get('pageIndex', 1))
  1510. pageSize = int(request.GET.get('pageSize', 10))
  1511. dealerIds = MyUser.get_dealer_ids(openId, request.user.productAgentId)
  1512. feedbacks = FeedBack.objects(openId = openId, ownerId__in = dealerIds) \
  1513. .order_by('-createTime') \
  1514. .paginate(pageIndex, pageSize) # type: CustomQuerySet
  1515. total = feedbacks.count()
  1516. items = []
  1517. for item in feedbacks: # type: FeedBack
  1518. items.append(item.summary)
  1519. return JsonResponse(
  1520. {
  1521. 'result': 1,
  1522. 'description': "",
  1523. 'payload': {
  1524. 'total': total,
  1525. 'dataList': items
  1526. }
  1527. }
  1528. )
  1529. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  1530. @permission_required(ROLE.myuser)
  1531. def getFeedbackDetail(request):
  1532. id_ = request.GET.get('id')
  1533. feedback = FeedBack.objects(id = id_).first() # type: FeedBack
  1534. if not feedback:
  1535. return JsonErrorResponse(description = u'没有找到反馈单,请刷新试试')
  1536. else:
  1537. if not feedback.isRead:
  1538. feedback.isRead = True
  1539. feedback.save()
  1540. return JsonResponse({'result': 1, 'description': '', 'payload': feedback.detail})
  1541. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  1542. @permission_required(ROLE.myuser)
  1543. def getFeedbackConfigs(request):
  1544. # type: (WSGIRequest)->JsonResponse
  1545. """
  1546. :param request:
  1547. :return:
  1548. """
  1549. logicalCode = request.GET.get('logicalCode')
  1550. # if not logicalCode:
  1551. # return JsonErrorResponse(description = u'找不到设备编号')
  1552. dev = Device.get_dev_by_l(logicalCode) or dict()
  1553. #: 暂时只是显示充电桩的端口
  1554. devTypeName = dev.get("devType", dict()).get("name", "")
  1555. if re.match(ur"充电桩", devTypeName):
  1556. payload = {"port": [str(_) for _ in range(1, 21)]}
  1557. else:
  1558. payload = {}
  1559. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  1560. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  1561. @permission_required(ROLE.myuser)
  1562. def getConsumeRecordsForFeedback(request):
  1563. # type: (WSGIRequest)->JsonResponse
  1564. """
  1565. :param request:
  1566. :return:
  1567. """
  1568. pageIndex = int(request.GET.get('pageIndex', 1))
  1569. pageSize = int(request.GET.get('pageSize', 10))
  1570. skip = (pageIndex - 1) * pageSize
  1571. logicalCode = request.GET.get('logicalCode', None)
  1572. if logicalCode:
  1573. device = Device.get_dev_by_logicalCode(logicalCode)
  1574. if not device:
  1575. return JsonErrorResponse(description = u'设备不存在,请重新扫码')
  1576. ownerIds = [device.ownerId]
  1577. else:
  1578. ownerIds = MyUser.get_dealer_ids(request.user.openId, request.user.productAgentId)
  1579. records = ConsumeRecord.objects(
  1580. ownerId__in = ownerIds,
  1581. openId = request.user.openId,
  1582. dateTimeAdded__gte = (datetime.datetime.now() - datetime.timedelta(days = 30)),
  1583. feedbackId__exists = 0).order_by("-dateTimeAdded") # type: CustomQuerySet
  1584. dataList = []
  1585. for record in records.skip(skip).limit(pageSize): # type: ConsumeRecord
  1586. dataList.append(record.info_for_feedback)
  1587. return JsonResponse(
  1588. {
  1589. 'result': 1,
  1590. 'description': '',
  1591. 'payload': {'total': records.count(), 'dataList': dataList}
  1592. })
  1593. def getNearbyDevicesFromDB(lng, lat, pageIndex, pageSize, maxDistance, agentId, devTypeName, groupId = None):
  1594. def hav(theta):
  1595. s = sin(theta / 2)
  1596. return s * s
  1597. def get_distance_hav(lat0, lng0, lat1, lng1):
  1598. if lat1 == 360 or lng1 == 360:
  1599. return -1
  1600. EARTH_RADIUS = 6371000
  1601. lat0 = radians(lat0)
  1602. lat1 = radians(lat1)
  1603. lng0 = radians(lng0)
  1604. lng1 = radians(lng1)
  1605. dlng = fabs(lng0 - lng1)
  1606. dlat = fabs(lat0 - lat1)
  1607. h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlng)
  1608. return int(2 * EARTH_RADIUS * asin(sqrt(h)))
  1609. def formatDeviceInfo(dev, devTypeName):
  1610. # type: (DeviceDict, basestring)->Optional[Dict]
  1611. logger.debug('try to format device<l={}, devNo={}> info.'.format(dev.logicalCode, dev.devNo))
  1612. distance = get_distance_hav(lat, lng, float(dev['lat']), float(dev['lng']))
  1613. group = Group.get_group(dev['groupId'])
  1614. if group is None:
  1615. return None
  1616. package = [
  1617. {
  1618. 'name': rule.get('name', ''),
  1619. 'coins': rule['coins'],
  1620. 'price': rule.get('price', rule['coins']),
  1621. 'time': rule.get('time', 20),
  1622. 'unit': rule.get('unit', u'分钟')
  1623. } for packageId, rule in dev['washConfig'].items()]
  1624. return {
  1625. 'devNo': dev.devNo,
  1626. 'type': devTypeName,
  1627. 'logicalCode': dev.logicalCode,
  1628. 'groupName': group['groupName'],
  1629. 'groupNumber': dev['groupNumber'],
  1630. 'groupId': dev.groupId,
  1631. 'address': group['address'],
  1632. 'online': dev.online,
  1633. 'status': dev.status,
  1634. 'signal': dev.signal,
  1635. 'remarks': dev['remarks'],
  1636. 'distance': distance,
  1637. 'lng': float(dev.lng),
  1638. 'lat': float(dev.lat),
  1639. 'often': False,
  1640. 'beingUsed': False,
  1641. 'package': package,
  1642. 'devTypeCode': dev.devType['code']
  1643. }
  1644. if not agentId:
  1645. logger.error('agent is null.')
  1646. return {
  1647. 'total': 0,
  1648. 'items': []
  1649. }
  1650. dealers = Dealer.get_dealers(agentId)
  1651. if not dealers:
  1652. return {
  1653. 'total': 0,
  1654. 'items': []
  1655. }
  1656. if groupId:
  1657. devices = Device.get_collection().find({'groupId': groupId})
  1658. else:
  1659. if devTypeName:
  1660. devices = Device.get_collection().find(
  1661. {
  1662. 'ownerId': {'$in': dealers},
  1663. '$where': 'this.devType != null && this.devType.name == "%s"' % devTypeName,
  1664. 'isFault': False,
  1665. 'location': {
  1666. '$near': {'$geometry': {'type': 'Point', 'coordinates': [lng, lat]},
  1667. '$maxDistance': maxDistance}}})
  1668. else:
  1669. devices = Device.get_collection().find(
  1670. {
  1671. 'ownerId': {'$in': dealers},
  1672. 'isFault': False,
  1673. 'location': {
  1674. '$near': {'$geometry': {'type': 'Point', 'coordinates': [lng, lat]},
  1675. '$maxDistance': maxDistance}}})
  1676. items = []
  1677. for dev in devices:
  1678. dev = DeviceDict(dev) # type: DeviceDict
  1679. if dev is None or not dev.lbs:
  1680. continue
  1681. try:
  1682. devInfo = formatDeviceInfo(dev, dev.devType.get('name', '')) # type: Dict
  1683. except Exception as e:
  1684. logger.exception(e)
  1685. continue
  1686. if devInfo is None:
  1687. continue
  1688. items.append(devInfo)
  1689. return_items = items[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  1690. dev_ctrl_map = Device.get_many_dev_control_cache([item['devNo'] for item in return_items])
  1691. for item in return_items:
  1692. # 换电柜的端口显示可用电池数量
  1693. if item['devTypeCode'] in [Const.DEVICE_TYPE_CODE_CHARGING_AQKJ, Const.DEVICE_TYPE_CODE_CHARGING_AQKJ_NEW]:
  1694. dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {})
  1695. item["canUseBattery"] = dev_ctrl_info.get("canUseBattery", 0)
  1696. elif Const.DEVICE_TYPE_CODE_CHARGING_KYXN <= item['devTypeCode'] < Const.DEVICE_TYPE_CODE_WASHER_BASE:
  1697. dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {})
  1698. item['allPorts'] = dev_ctrl_info.get('allPorts', 10)
  1699. item['usedPorts'] = dev_ctrl_info.get('usedPorts', 0)
  1700. item['usePorts'] = dev_ctrl_info.get('usePorts', 10)
  1701. if 'power' in dev_ctrl_info:
  1702. item['power'] = dev_ctrl_info['power']
  1703. payload = {
  1704. 'total': len(items),
  1705. 'items': return_items
  1706. }
  1707. return payload
  1708. @permission_required(ROLE.myuser)
  1709. def getNearbyGroups(request):
  1710. # type: (WSGIRequest)->JsonResponse
  1711. try:
  1712. lng = float(request.GET.get('lng'))
  1713. lat = float(request.GET.get('lat'))
  1714. maxDistance = int(request.GET.get('distance', 3000))
  1715. logger.debug('now location. lat = %s; lng = %s' % (lat, lng))
  1716. if maxDistance > Const.NEAR_BY_MAX_DISTANCE:
  1717. maxDistance = Const.NEAR_BY_MAX_DISTANCE
  1718. if lng == 360 or lat == 360 or isnan(lng) or isnan(lat):
  1719. return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'})
  1720. payload = getNearbyDevicesFromDB(lng, lat, 1, 1000, maxDistance, request.user.agentId,
  1721. request.GET.get('type', None))
  1722. groupDict = {}
  1723. for dev in payload['items']:
  1724. if groupDict.has_key(dev['groupId']):
  1725. groupDict[dev['groupId']]['allDevices'] += 1
  1726. if dev['status'] == Const.DEV_WORK_STATUS_IDLE:
  1727. groupDict[dev['groupId']]['idleDevices'] += 1
  1728. else:
  1729. newValue = {
  1730. 'distance': dev['distance'],
  1731. 'lng': float(dev['lng']),
  1732. 'lat': float(dev['lat']),
  1733. 'address': dev['address'],
  1734. 'groupName': dev['groupName'],
  1735. 'groupId': dev['groupId'],
  1736. 'allDevices': 1,
  1737. 'idleDevices': 1 if dev['status'] == Const.DEV_WORK_STATUS_IDLE else 0
  1738. }
  1739. groupDict[dev['groupId']] = newValue
  1740. payload = {'total': len(groupDict.values()), 'items': groupDict.values()}
  1741. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  1742. except Exception as e:
  1743. logger.exception(e)
  1744. return JsonResponse({'result': 0, 'description': u'获取附近设备失败'})
  1745. @permission_required(ROLE.myuser)
  1746. def getNearbyDevices(request):
  1747. # type: (WSGIRequest)->JsonResponse
  1748. try:
  1749. groupId = request.GET.get('groupId', None)
  1750. lng = float(request.GET.get('lng'))
  1751. lat = float(request.GET.get('lat'))
  1752. maxDistance = int(request.GET.get('distance', 3000))
  1753. logger.debug('now location. lat = %s; lng = %s' % (lat, lng))
  1754. if maxDistance > Const.NEAR_BY_MAX_DISTANCE:
  1755. maxDistance = Const.NEAR_BY_MAX_DISTANCE
  1756. if lng == 360 or lat == 360 or isnan(lng) or isnan(lat):
  1757. return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'})
  1758. pageIndex = int(request.GET.get('pageIndex', 0))
  1759. pageSize = int(request.GET.get('pageSize', 10))
  1760. payload = getNearbyDevicesFromDB(lng, lat, pageIndex, pageSize, maxDistance,
  1761. getattr(request.user, 'productAgentId', ''),
  1762. request.GET.get('type', None), groupId)
  1763. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  1764. except Exception as e:
  1765. logger.exception(e)
  1766. return JsonResponse({'result': 0, 'description': u'获取附近设备失败'})
  1767. @permission_required(ROLE.manager)
  1768. def getEndUserDetailList(request):
  1769. # type: (WSGIRequest)->JsonResponse
  1770. """
  1771. :param request:
  1772. :return:
  1773. """
  1774. mid = str(request.user.id)
  1775. pageIndex = int(request.GET.get('pageIndex', 1))
  1776. pageSize = int(request.GET.get('pageSize', 10))
  1777. searchKey = request.GET.get('searchKey', None)
  1778. agentIds = [str(agent['_id']) for agent in Agent.get_collection().find({'managerId': mid}, {'_id': True})]
  1779. dealerIds = [str(dealer['_id']) for dealer in
  1780. Dealer.get_collection().find({'agentId': {'$in': agentIds}}, {'_id': True})]
  1781. groupIds = [str(group['_id']) for group in
  1782. Group.get_collection().find({'ownerId': {'$in': dealerIds}}, {'_id': True})]
  1783. skip = (pageIndex - 1) * pageSize
  1784. dataList = []
  1785. users = MyUser.search(searchKey).filter(groupId__in = groupIds)
  1786. for u in users.skip(skip).limit(pageSize):
  1787. item = {
  1788. 'id': str(u.id),
  1789. 'nickname': u.nickname,
  1790. 'openId': u.openId,
  1791. 'sex': u.sex,
  1792. 'country': u.country,
  1793. 'province': u.province,
  1794. 'city': u.city,
  1795. 'balance': u.balance,
  1796. 'groupName': '',
  1797. 'gateway': u.gateway
  1798. }
  1799. group = Group.get_group(u.groupId)
  1800. if group:
  1801. item.update({'groupName': group.get('groupName')})
  1802. dataList.append(item)
  1803. total = users.count()
  1804. return JsonResponse({
  1805. 'result': 1,
  1806. 'description': '',
  1807. 'payload': {
  1808. 'total': total,
  1809. 'dataList': dataList
  1810. }
  1811. })
  1812. @error_tolerate(nil = JsonErrorResponse(description = u'获取消费记录失败'), logger = logger)
  1813. @permission_required(ROLE.manager)
  1814. def getEndUserConsumeRecords(request):
  1815. # type: (WSGIRequest)->JsonResponse
  1816. """
  1817. :param request:
  1818. :return:
  1819. """
  1820. pageIndex = int(request.GET.get('pageIndex', 1))
  1821. pageSize = int(request.GET.get('pageSize', 10))
  1822. userId = request.GET.get('id', None)
  1823. if not userId:
  1824. return JsonErrorResponse(description = u'用户id为空')
  1825. else:
  1826. startTime = request.GET.get('startTime', Const.QUERY_START_DATE)
  1827. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  1828. user = MyUser.objects(id = str(userId)).get()
  1829. group = Group.get_group(user.groupId)
  1830. cursor = ClientConsumeModelProxy.get_data_list(
  1831. startTime = startTime,
  1832. endTime = endTime,
  1833. ownerId = group['ownerId'],
  1834. openId = user.openId,
  1835. groupId = user.groupId) # type: QuerySetProxy
  1836. total = cursor.count()
  1837. records = [
  1838. {
  1839. "orderNo": r.orderNo,
  1840. "time": r.time,
  1841. "coins": r.coin,
  1842. "devNo": r.devNo,
  1843. "devType": r.dev_type_name,
  1844. "groupName": r.groupName
  1845. }
  1846. for r in cursor.paginate(pageIndex, pageSize)
  1847. ]
  1848. return JsonResponse({'result': 1, 'description': '', 'payload': {'total': total, 'dataList': records}})
  1849. @error_tolerate(nil = JsonErrorResponse(description = u'获取充值记录失败'), logger = logger)
  1850. @permission_required(ROLE.manager)
  1851. def getEndUserRechargeRecords(request):
  1852. # type: (WSGIRequest)->JsonResponse
  1853. """
  1854. :param request:
  1855. :return:
  1856. """
  1857. pageIndex = int(request.GET.get('pageIndex', 1))
  1858. pageSize = int(request.GET.get('pageSize', 10))
  1859. userId = request.GET.get('id', None)
  1860. if not userId:
  1861. return JsonErrorResponse(description = u'用户id为空')
  1862. else:
  1863. startTime = request.GET.get('startTime', Const.QUERY_START_DATE)
  1864. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  1865. user = MyUser.objects(id = str(userId)).get()
  1866. group = Group.get_group(user.groupId)
  1867. cursor = ClientRechargeModelProxy.get_data_list(startTime = startTime,
  1868. endTime = endTime,
  1869. ownerId = group['ownerId'],
  1870. openId = user.openId,
  1871. groupId = user.groupId,
  1872. hint = [('openId', 1)]) # type: QuerySetProxy
  1873. total = cursor.count()
  1874. records = [
  1875. {
  1876. "orderNo": r.orderNo,
  1877. "time": r.to_js_timestamp(r.dateTimeAdded),
  1878. "money": r.money,
  1879. "coins": r.coins,
  1880. "devNo": r.devNo,
  1881. "devType": r.dev_type_name,
  1882. "groupName": r.groupName,
  1883. "gateway": r.gateway
  1884. } for r in cursor.paginate(pageIndex, pageSize)]
  1885. return JsonResponse({'result': 1, 'description': '', 'payload': {'total': total, 'dataList': records}})
  1886. def wxconfig(request):
  1887. url = request.GET.get('href')
  1888. if not url:
  1889. return JsonResponse({'result': 0, 'description': u'参数错误', 'payload': {}})
  1890. current_user = request.user # type: MyUser
  1891. wxconfig = get_wx_config(current_user, url)
  1892. return JsonOkResponse(payload = {'wxconfig': wxconfig})
  1893. # 用于前台界面时间计时用
  1894. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  1895. @permission_required(ROLE.myuser)
  1896. def countDown(request):
  1897. # type: (WSGIRequest)->JsonResponse
  1898. openId = str(request.user.openId)
  1899. devNo = str(request.GET.get('devNo', ''))
  1900. portStr = request.GET.get('chargeIndex', None)
  1901. if portStr is not None:
  1902. port = int(portStr)
  1903. else:
  1904. port = None
  1905. dev = Device.get_dev(devNo)
  1906. logicalCode = dev['logicalCode']
  1907. group = Group.get_group(dev['groupId'])
  1908. devType = dev.get('devType')
  1909. dealer = Dealer.objects.get(id = dev['ownerId'])
  1910. agent = Agent.objects.get(id = dealer.agentId)
  1911. # 判断是否是摩丫丫的设备 判断是否是烘干机设备
  1912. if (agent.features != [] and 'moyaya666' in agent.features) or (
  1913. dealer.features != [] and 'dryer' in dealer.features):
  1914. last_time_cache = serviceCache.get(user_last_time_use_ended_cache(openId, logicalCode), '')
  1915. if last_time_cache == '':
  1916. serviceCache.set(user_last_time_use_ended_cache(openId, logicalCode), datetime.datetime.now(), 3600)
  1917. elif last_time_cache != '':
  1918. if datetime.datetime.now() > last_time_cache + datetime.timedelta(hours = 1):
  1919. serviceCache.set(user_last_time_use_ended_cache(openId, logicalCode), datetime.datetime.now(), 3600)
  1920. ctrInfo = Device.get_dev_control_cache(devNo)
  1921. if ctrInfo:
  1922. lastOpenId = ctrInfo.get('openId', '')
  1923. else:
  1924. lastOpenId = ''
  1925. box = ActionDeviceBuilder.create_action_device(dev)
  1926. try:
  1927. response = box.count_down(request, dev, agent, group, devType, lastOpenId, port)
  1928. if response is None:
  1929. return JsonErrorResponse(description = u'系统不支持此操作哦')
  1930. return response
  1931. except ServiceException as e:
  1932. logger.error('get count_down error=%s' % e.result['description'].encode('utf-8'))
  1933. return JsonErrorResponse(description = e.result['description'])
  1934. except Exception, e:
  1935. logger.error('device(%s) get count_down error=%s' % (devNo, e))
  1936. return JsonErrorResponse(description = u'系统异常,请重新刷新页面')
  1937. # 只要有回调过来,说明一定是登录成功了,就直接送金币,然后跳转到控制页面即可。暂时不考虑authCode的鉴定以防止伪造URL。
  1938. @error_tolerate(nil = ErrorResponseRedirect(error = cn(u'系统开小差了哦,真是抱歉呀,请您刷新页面试试哦')))
  1939. @permission_required(ROLE.myuser)
  1940. def huaweiAccess(request):
  1941. # type: (WSGIRequest)->HttpResponseRedirect
  1942. openId = request.user.openId
  1943. devNo = request.COOKIES.get('devNo', None)
  1944. groupId = request.COOKIES.get('groupId', None)
  1945. if openId is None or devNo is None or groupId is None:
  1946. return ErrorResponseRedirect(error = cn(u'系统开小差了哦,真是抱歉呀,请您重新扫码试试哦'))
  1947. dev = Device.get_dev(devNo)
  1948. ads = AdRecord.objects.filter(openId = openId, adId = 0)
  1949. if ads.count() > 0:
  1950. return NetDeviceResponseRedirect(l = dev.logicalCode)
  1951. newRcd = AdRecord(converted = True, adId = 0, openId = openId, groupId = groupId, devNo = devNo)
  1952. newRcd.save()
  1953. user = MyUser.objects.get(openId = openId, groupId = groupId)
  1954. user.balance += 1
  1955. user.save()
  1956. return NetDeviceResponseRedirect(l = dev.logicalCode)
  1957. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  1958. def getCardStatus(request):
  1959. # type: (WSGIRequest)->JsonResponse
  1960. lc = request.GET.get('logicalCode')
  1961. devNo = Device.get_devNo_by_logicalCode(lc)
  1962. cardInfo = Card.get_dev_cur_card(devNo)
  1963. if cardInfo is None:
  1964. return JsonResponse(
  1965. {
  1966. "result": 0,
  1967. "description": u'刷卡区没有检测到卡,请您先把卡放到读卡区,这样才能开始充值哦',
  1968. "para": None
  1969. }
  1970. )
  1971. return JsonResponse(
  1972. {
  1973. "result": 1,
  1974. "description": None,
  1975. "para": {
  1976. "ready": True,
  1977. "cardId": cardInfo['cardNo'],
  1978. "money": cardInfo["money"]
  1979. }
  1980. }
  1981. )
  1982. @permission_required(ROLE.myuser)
  1983. def pollBtInfo(request):
  1984. # type: (WSGIRequest)->JsonResponse
  1985. payload = json.loads(request.body)
  1986. device = Device.get_dev_by_logicalCode(payload.get('logicalCode'))
  1987. if not device:
  1988. return JsonResponse({'result': 0, 'description': u'设备不存在', 'payload': {}})
  1989. code = Const.BT_DEVICE_TYPE_CODE_MAP[int(payload.get('code'))]
  1990. actionBox = ActionBtDeviceBuilder.create(code, device)
  1991. major = int(payload.get('major'))
  1992. minor = int(payload.get('minor'))
  1993. notify_payload = payload.get('payload', None)
  1994. if not notify_payload:
  1995. notify_payload = payload.get('advertisData', None)
  1996. if notify_payload:
  1997. result, description = actionBox.poll_notify(notify_payload, **{'major': major, 'minor': minor})
  1998. return JsonResponse({'result': result, 'description': description, 'payload': {}})
  1999. else:
  2000. return JsonResponse({'result': 1, 'description': 'empty', 'payload': {}})
  2001. @error_tolerate(nil=JsonErrorResponse(description=u'显示用户信息错误'), logger=logger)
  2002. @permission_required(ROLE.myuser)
  2003. @request_limit_by_user(operation='userInfo', limit=50, logger=logger)
  2004. def userInfo(request):
  2005. # type: (WSGIRequest)->JsonResponse
  2006. logger.info('receive userInfo')
  2007. user = request.user # type: MyUser
  2008. agentId = user.agentId
  2009. payload = {
  2010. 'nickname': user.nickname,
  2011. 'balance': user.total_balance,
  2012. 'agentId': agentId,
  2013. 'domain': settings.MY_DOMAIN,
  2014. 'avatarUrl': request.user.avatar if request.user.avatar else settings.DEFAULT_AVATAR_URL,
  2015. 'noVirtualCard': False,
  2016. 'noRechargeCard': False,
  2017. 'noRecharge': False,
  2018. 'userId': ''
  2019. }
  2020. agent = Agent.objects(id = agentId).first() # type: Optional[Agent]
  2021. if agent:
  2022. payload['agentFeatures'] = agent.features
  2023. if 'hideRechargeCardForUser' in agent.features:
  2024. payload.update({'noRechargeCard': True})
  2025. # if 'ledgerAfterFinished' in agent.features:
  2026. # payload.update({
  2027. # 'noVirtualCard': True,
  2028. # 'noRechargeCard': True,
  2029. # 'noRecharge': True
  2030. # })
  2031. # 校验是否要绑定用户的手机号码
  2032. if 'telVerify' in agent.features:
  2033. needTelVerify = check_user_tel(user)
  2034. payload.update({
  2035. "needTelVerify": needTelVerify
  2036. })
  2037. # 检查是否支持一卡多用
  2038. if 'card_multi_use' in agent.features:
  2039. payload.update({'card_multi_use': True})
  2040. user_id = user.user_id
  2041. if user_id:
  2042. payload.update({'userId': user_id})
  2043. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  2044. @error_tolerate(nil = JsonErrorResponse(description = u'获取组失败'), logger = logger)
  2045. @permission_required(ROLE.myuser)
  2046. def getRecentlyGroup(request):
  2047. # type: (WSGIRequest)->JsonResponse
  2048. my_product_agent_id = request.user.productAgentId
  2049. # 是否是查询卡卷
  2050. hasCoupon = request.GET.get('hasCoupon', False)
  2051. openId = request.user.openId
  2052. rcds = ConsumeRecord.objects.filter(openId = openId, isNormal = True).order_by('-dateTimeAdded')
  2053. devNoList = list(set([rcd.devNo for rcd in rcds[0:100]]))
  2054. dataList = []
  2055. groupIdList = []
  2056. dealerIdList = []
  2057. map_dealer_product = {}
  2058. for devNo in devNoList:
  2059. dev = Device.get_dev(devNo)
  2060. if (dev is None) or (not dev.has_key('groupId')):
  2061. continue
  2062. group = Group.get_group(dev['groupId'])
  2063. if not group:
  2064. continue
  2065. dealer_id = str(dev['ownerId'])
  2066. if not dealer_id:
  2067. logger.error('dealer is null. id = %s' % dealer_id)
  2068. continue
  2069. try:
  2070. dealer = Dealer.objects(id = dealer_id).first()
  2071. if not dealer:
  2072. logger.error('dealer is null. id = %s' % dealer_id)
  2073. continue
  2074. except Exception as e:
  2075. logger.error('dealerId = {}; exception = {}'.format(dealer_id, str(e)))
  2076. if dealer_id not in map_dealer_product:
  2077. try:
  2078. product_agent = get_user_manager_agent(dealer) # type:Agent
  2079. except Exception as e:
  2080. logger.exception(e)
  2081. product_agent = None
  2082. if not product_agent:
  2083. logger.error('get product agent failure. devNo = {}; dealer id = {}'.format(dev['devNo'], dealer_id))
  2084. continue
  2085. map_dealer_product[dealer_id] = str(product_agent.id)
  2086. if map_dealer_product[dealer_id] != my_product_agent_id:
  2087. logger.debug('{} is not equal agent({})'.format(repr(dev), my_product_agent_id))
  2088. continue
  2089. if dev['groupId'] not in groupIdList:
  2090. if (not group.has_key('address')) or (not group.has_key('groupName')):
  2091. continue
  2092. dataList.append({'address': group['address'],
  2093. 'groupName': group['groupName'],
  2094. 'groupId': dev['groupId'],
  2095. 'devType': dev.get('devType', {}).get('name', ''),
  2096. 'logicalCode': dev['logicalCode'],
  2097. 'ownerId': dev['ownerId']}
  2098. )
  2099. groupIdList.append(dev['groupId'])
  2100. dealerIdList.append(dev['ownerId'])
  2101. if not hasCoupon:
  2102. return JsonResponse({"result": 1, "description": "", "payload": {"total": len(dataList), "dataList": dataList}})
  2103. # 查询下地址下的已经发布的虚拟卡
  2104. dealerIdList = list(set(dealerIdList))
  2105. vCards = VirtualCard.objects.filter(ownerId__in = dealerIdList, status = 1)
  2106. dataList1 = []
  2107. for data in dataList:
  2108. match = False
  2109. for card in vCards:
  2110. if data['ownerId'] == card.ownerId and ('*' in card.groupIds or data['groupId'] in card.groupIds):
  2111. match = True
  2112. break
  2113. if match:
  2114. dataList1.append(data)
  2115. return JsonResponse({"result": 1, "description": "", "payload": {"total": len(dataList1), "dataList": dataList1}})
  2116. @error_tolerate(nil = JsonErrorResponse(description = u'获取卡列表失败'), logger = logger)
  2117. @permission_required(ROLE.myuser)
  2118. def getCardList(request):
  2119. # type: (WSGIRequest)->JsonResponse
  2120. """
  2121. :param request:
  2122. :return:
  2123. """
  2124. pageIndex = int(request.GET.get('pageIndex', 1))
  2125. pageSize = int(request.GET.get('pageSize', 10))
  2126. searchKey = request.GET.get('searchKey', None)
  2127. openId = request.user.openId
  2128. agentId = request.user.agentId # zjl user.agentId -> user.productAgentId
  2129. agent = Agent.objects.get(id = agentId)
  2130. manager = Manager.objects(id = agent.managerId).get() # zjl delete
  2131. agent_id_list = [str(item.id) for item in Agent.objects(managerId = str(manager.id))] # zjl delete
  2132. hideMenu = True if 'hideCardMenu' in agent.features else False
  2133. skip = (pageIndex - 1) * pageSize
  2134. cards = Card.objects.filter(openId = openId, # zjl delete
  2135. agentId__in = agent_id_list).search(searchKey) # zjl delete
  2136. # cards = Card.objects.filter(openId=openId, # zjl new
  2137. # agentId=agentId).search(searchKey) # zjl new
  2138. dataList = []
  2139. for card in cards.skip(skip).limit(pageSize):
  2140. hide = ['orderRecord', 'rechargeRecord', 'backRecord', 'frozen'] if (card.cardType == 'IC' and hideMenu) else []
  2141. if card.devNo:
  2142. dev = Device.get_dev(card.devNo) or dict()
  2143. devType = dev.get('devType', {})
  2144. if devType.has_key('id'):
  2145. try:
  2146. devType = DeviceType.objects.get(id = devType['id'])
  2147. if not devType.supportIcCardcharge:
  2148. hide.append('cardCharge')
  2149. except Exception, e:
  2150. pass
  2151. # 分以下三种情况处理
  2152. # 1 有groupId, 但是没有dealerId, 这个查数据目前没有。 这个情况下dealerId设置为group对应的, 如果没有dealer, 全部清空
  2153. # 2 有dealerId, 没有groupId, 这种情况下, 直接取dealer的第一个groupId, 没有全部取空
  2154. # 3 两个都没有的情况下, 直接取设备对应的group和dealerId
  2155. if not card.groupId:
  2156. if card.dealerId:
  2157. group = Group.get_default_group(card.dealerId) # type: GroupDict
  2158. if group:
  2159. card.groupId = group.groupId
  2160. else:
  2161. card.groupId = ''
  2162. card.dealerId = ''
  2163. card.save()
  2164. else:
  2165. # 不处理. 这个用户自己去绑定
  2166. pass
  2167. else:
  2168. if not card.dealerId:
  2169. group = Group.get_group(card.groupId) # type: GroupDict
  2170. if not group:
  2171. card.groupId = ''
  2172. card.dealerId = ''
  2173. else:
  2174. card.dealerId = group.ownerId
  2175. card.save()
  2176. group = Group.get_group(card.groupId) # type: GroupDict
  2177. dataList.append(
  2178. {
  2179. 'cardId': str(card.id),
  2180. 'cardNo': card.cardNo,
  2181. 'cardType': card.cardType,
  2182. 'cardName': card.cardName,
  2183. 'phone': card.phone,
  2184. 'groupId': card.groupId,
  2185. 'groupName': group.groupName if group else '',
  2186. 'dealerId': card.dealerId,
  2187. 'balance': card.balance,
  2188. 'isHaveBalance': card.isHaveBalance,
  2189. 'remarks': card.remarks,
  2190. 'status': card.status,
  2191. 'frozen': False if card.frozen is None else card.frozen,
  2192. 'hide': hide,
  2193. 'boundVirtualCardId': card.boundVirtualCardId
  2194. }
  2195. )
  2196. total = cards.count()
  2197. return JsonResponse(
  2198. {
  2199. 'result': 1,
  2200. 'description': '',
  2201. 'payload':
  2202. {
  2203. 'total': total, "dataList": dataList
  2204. }
  2205. }
  2206. )
  2207. @error_tolerate(nil = JsonOkResponse(description = u"获取卡信息失败"), logger = logger)
  2208. @permission_required(ROLE.myuser)
  2209. def getCard(request):
  2210. """
  2211. 获取单一的卡信息
  2212. :param request:
  2213. :return:
  2214. """
  2215. cardId = request.GET.get("cardId", "")
  2216. try:
  2217. card = Card.objects.get(id = cardId)
  2218. except DoesNotExist:
  2219. return JsonErrorResponse(description = u"获取卡信息失败,请刷新页面试试")
  2220. agentId = request.user.agentId
  2221. agent = Agent.objects.get(id = agentId)
  2222. hideMenu = True if 'hideCardMenu' in agent.features else False
  2223. hide = ['orderRecord', 'rechargeRecord', 'backRecord', 'frozen'] if (card.cardType == 'IC' and hideMenu) else []
  2224. if card.devNo:
  2225. dev = Device.get_dev(card.devNo) or dict()
  2226. devType = dev.get('devType', {})
  2227. if devType.has_key('id'):
  2228. try:
  2229. devType = DeviceType.objects.get(id = devType['id'])
  2230. if not devType.supportIcCardcharge:
  2231. hide.append('cardCharge')
  2232. except Exception as e:
  2233. logger.exception(e)
  2234. group = Group.get_group(card.groupId)
  2235. data = {
  2236. 'cardId': str(card.id),
  2237. 'cardNo': card.cardNo,
  2238. 'cardType': card.cardType,
  2239. 'cardName': card.cardName,
  2240. 'phone': card.phone,
  2241. 'groupId': card.groupId,
  2242. 'groupName': group.groupName if group else '',
  2243. 'dealerId': card.dealerId,
  2244. 'balance': card.balance,
  2245. 'isHaveBalance': card.isHaveBalance,
  2246. 'remarks': card.remarks,
  2247. 'status': card.status,
  2248. 'frozen': False if card.frozen is None else card.frozen,
  2249. 'hide': hide,
  2250. }
  2251. return JsonOkResponse(payload = data)
  2252. @error_tolerate(nil = JsonErrorResponse(description = u"查询卡信息失败"), logger = logger)
  2253. @permission_required(ROLE.myuser)
  2254. def queryCard(request):
  2255. """
  2256. 根据前台提供的cardNo 以及 groupId 返回该卡的所有信息
  2257. :param request:
  2258. :return:
  2259. """
  2260. # 获取参数 参数校验
  2261. cardNo = request.GET.get("cardNo")
  2262. groupId = request.GET.get("groupId")
  2263. if not all([cardNo, groupId]):
  2264. return JsonErrorResponse(description = u"参数不全,请输入卡号获取扫描设备获取绑定地址")
  2265. group = Group.get_group(groupId) # type: GroupDict
  2266. if not group:
  2267. return JsonErrorResponse(description = u"开卡地址不存在,请重新扫描设备获取绑定地址或联系发卡经销商(1001)")
  2268. dealer = Dealer.objects(id = str(group.ownerId)).first() # type: Dealer
  2269. if not dealer:
  2270. return JsonErrorResponse(description = u"开卡地址不存在,请重新扫描设备获取绑定地址或联系发卡经销商(1002)")
  2271. agent = Agent.objects(id = str(dealer.agentId)).first()
  2272. if not agent:
  2273. return JsonErrorResponse(description = u"代理商不存在,请刷新页面后重试(1001)")
  2274. productAgent = get_user_manager_agent(agent)
  2275. if str(productAgent.id) != request.user.productAgentId:
  2276. return JsonErrorResponse(description = u"不是该平台下的地址,请换个设备编号扫码试试(1001)")
  2277. # 鉴别卡相应信息
  2278. try:
  2279. card = Card.objects.get(cardNo=cardNo, agentId=str(agent.id))
  2280. except DoesNotExist:
  2281. # 没有找到卡的情况下 如果代理商规定了经销商必须要先录入卡
  2282. dealerBindCard = True if "dealerBindCard" in agent.features else False
  2283. if dealerBindCard:
  2284. return JsonErrorResponse(description=u"无效的卡号,该卡号未被录入,请联系发卡方")
  2285. return JsonResponse(
  2286. {
  2287. "result": 1,
  2288. "description": u"",
  2289. "payload": {
  2290. "cardNo": cardNo,
  2291. "groupId": group.groupId,
  2292. "groupName": group.groupName,
  2293. }
  2294. }
  2295. )
  2296. # 卡已经被被别人绑定了
  2297. if card.openId and card.openId != request.user.openId and card.openId != Const.DEFAULT_CARD_OPENID:
  2298. return JsonResponse(
  2299. {
  2300. "result": ErrorCode.CARD_BIND_BY_OTHER,
  2301. "description": u"{} 卡片已经被其他用户使用,请检查卡号是否正确或联系相应的经销商".format(cardNo),
  2302. "payload": {}
  2303. }
  2304. )
  2305. if group.groupId != card.groupId:
  2306. card_bind_group = Group.get_group(card.groupId)
  2307. else:
  2308. card_bind_group = group
  2309. if not card_bind_group:
  2310. card_bind_dealer = None
  2311. else:
  2312. card_bind_dealer = Dealer.objects(id = str(card_bind_group.ownerId)).first()
  2313. # 卡綁定的組和經銷商只要有一個無效, 就走增加的流程
  2314. if not card_bind_group or not card_bind_dealer:
  2315. return JsonResponse(
  2316. {
  2317. "result": 1,
  2318. "description": u"",
  2319. "payload": {
  2320. "cardNo": cardNo,
  2321. "groupId": group.groupId,
  2322. "groupName": group.groupName,
  2323. }
  2324. }
  2325. )
  2326. # 该卡已经被自己绑定
  2327. if card.openId and card.openId != Const.DEFAULT_CARD_OPENID:
  2328. return JsonResponse(
  2329. {
  2330. "result": ErrorCode.CARD_BIND_BY_SELF,
  2331. "description": u"{} 卡片已经存在于您的卡包中,是否进入编辑界面编辑该卡的相应信息".format(cardNo),
  2332. "payload": {
  2333. "cardId": str(card.id),
  2334. "cardNo": cardNo,
  2335. "cardName": card.cardName,
  2336. "groupId": card_bind_group.groupId,
  2337. "groupName": card_bind_group.groupName,
  2338. "phone": card.phone
  2339. }
  2340. }
  2341. )
  2342. # 该卡没有被绑定, 但是经销商信息已经绑定, 直接走绑定流程
  2343. if not card.openId or card.openId == Const.DEFAULT_CARD_OPENID:
  2344. return JsonResponse(
  2345. {
  2346. "result": ErrorCode.CARD_FORBID_CHARGE_GROUP,
  2347. "description": u"该卡已经被经销商录入,是否进入卡绑定界面绑定卡{}".format(cardNo),
  2348. "payload": {
  2349. "cardId": str(card.id),
  2350. "cardNo": cardNo,
  2351. "cardName": card.cardName,
  2352. "groupId": card_bind_group.groupId,
  2353. "groupName": card_bind_group.groupName,
  2354. "phone": card.phone
  2355. }
  2356. }
  2357. )
  2358. @error_tolerate(nil = JsonErrorResponse(description = u"添加卡失败"), logger = logger)
  2359. @permission_required(ROLE.myuser)
  2360. def addCard(request):
  2361. """
  2362. 添加卡 之前已经做过校验了
  2363. :param request:
  2364. :return:
  2365. """
  2366. payload = json.loads(request.body)
  2367. cardNo = payload.get("cardNo")
  2368. cardName = payload.get("cardName")
  2369. phone = payload.get("phone")
  2370. logicalCode = payload.get("logicalCode")
  2371. cardId = payload.get("cardId")
  2372. cardType = payload.get('cardType', '')
  2373. # 参数校验
  2374. if cardNo.isdigit():
  2375. cardNo = str(int(cardNo))
  2376. if not Card.check_card_no(cardNo):
  2377. return JsonErrorResponse(description = u"激活失败,无效的卡号,卡号长度不能超过32位")
  2378. if cardName and not check_entity_name(cardName):
  2379. return JsonErrorResponse(description = u"请输入正确的持卡人昵称(2-20位)")
  2380. if phone and not check_phone_number(phone):
  2381. return JsonErrorResponse(description = u"手机号码输入错误")
  2382. # 绑定设备和经销商的关系校验
  2383. device = Device.get_dev_by_l(logicalCode)
  2384. if not device:
  2385. return JsonErrorResponse(description = u"错误的设备二维码,请重新扫描设备二维码")
  2386. group = Group.get_group(device.get("groupId"))
  2387. if not group:
  2388. return JsonErrorResponse(description = u"未找到设备组,请刷新页面重试")
  2389. dealer = Dealer.objects.filter(id = group.get("ownerId")).first()
  2390. if not dealer:
  2391. return JsonErrorResponse(description = u"未找到经销商,请刷新页面重试")
  2392. agent = Agent.objects.filter(id = str(dealer.agentId)).first()
  2393. if not agent:
  2394. return JsonErrorResponse(description = u"未找到代理商,请刷新页面重试")
  2395. productAgent = get_user_manager_agent(agent)
  2396. if str(productAgent.id) != request.user.productAgentId:
  2397. return JsonErrorResponse(description = u"不是该平台下的用户,不能绑定该平台的实体卡")
  2398. if not cardId:
  2399. # 是否允许办理多张实体卡
  2400. onlyOneCard = True if "onlyOneCard" in agent.features and not request.user.many_cards else False
  2401. if onlyOneCard and request.user.cards_num > 0:
  2402. return JsonErrorResponse(description = u"您只能绑定一张实体卡,请联系经销商了解相应的规则")
  2403. # 卡存在校验
  2404. try:
  2405. card = Card.objects.get(Q(agentId=str(agent.id)) | Q(agentId=str(agent.id)), cardNo=cardNo)
  2406. except DoesNotExist:
  2407. # 没有找到卡的情况下 如果代理商规定了经销商必须要先录入卡
  2408. dealerBindCard = True if "dealerBindCard" in agent.features else False
  2409. if dealerBindCard:
  2410. return JsonErrorResponse(description=u"无效的卡号,该卡号未被录入,请联系发卡方")
  2411. card = Card(
  2412. cardNo = cardNo,
  2413. openId = request.user.openId,
  2414. cardName = cardName,
  2415. groupId = device.get("groupId"),
  2416. phone = phone,
  2417. nickName = request.user.nickname,
  2418. agentId = str(agent.id),
  2419. dealerId = str(dealer.id),
  2420. productAgentId = request.user.productAgentId,
  2421. managerialAppId = request.user.managerialAppId,
  2422. managerialOpenId = request.user.managerialOpenId,
  2423. cardType = cardType
  2424. )
  2425. card.save()
  2426. return JsonOkResponse(u"添加成功", payload = {"cardId": str(card.id)})
  2427. # 优先判断dealerId是否允许,在判断绑定关系
  2428. if card.dealerId and card.dealerId != device.get("ownerId"):
  2429. return JsonErrorResponse(description = u"该卡已被其他经销商录入,请确认卡号无误后联系您的发卡经销商")
  2430. if card.openId and card.openId != request.user.openId and card.openId != Const.DEFAULT_CARD_OPENID:
  2431. return JsonErrorResponse(description = u"该卡已被其他用户绑定,请确认卡号无误后联系您的发卡经销商")
  2432. card.openId = request.user.openId
  2433. card.cardName = cardName
  2434. card.phone = phone
  2435. card.nickName = request.user.nickname
  2436. card.groupId = device.get("groupId")
  2437. card.dealerId = str(dealer.id)
  2438. card.agentId = str(agent.id)
  2439. card.productAgentId = request.user.productAgentId
  2440. card.managerialAppId = request.user.managerialAppId
  2441. card.managerialOpenId = request.user.managerialOpenId
  2442. card.save()
  2443. return JsonOkResponse(u"添加成功", payload = {"cardId": str(card.id)})
  2444. # 1003 ErrorCode 过来的
  2445. else:
  2446. try:
  2447. card = Card.objects.get(id = cardId)
  2448. except DoesNotExist:
  2449. return JsonErrorResponse(description = u"未找到实体卡,请刷新页面后重试")
  2450. card.openId = request.user.openId
  2451. card.groupId = group.groupId
  2452. card.dealerId = group.ownerId
  2453. card.agentId = str(agent.id)
  2454. if cardName != card.cardName:
  2455. card.cardName = cardName
  2456. if phone != card.phone:
  2457. card.phone = phone
  2458. card.nickName = request.user.nickname
  2459. card.productAgentId = request.user.productAgentId
  2460. card.managerialAppId = request.user.managerialAppId
  2461. card.managerialOpenId = request.user.managerialOpenId
  2462. card.save()
  2463. return JsonOkResponse(u"添加成功", payload = {"cardId": str(card.id)})
  2464. @error_tolerate(nil = JsonErrorResponse(description = u"编辑卡失败"), logger = logger)
  2465. @permission_required(ROLE.myuser)
  2466. def editCard(request):
  2467. """
  2468. 卡编辑
  2469. :param request:
  2470. :return:
  2471. """
  2472. payload = json.loads(request.body)
  2473. cardName = payload.get("cardName")
  2474. if cardName and not check_entity_name(cardName):
  2475. return JsonErrorResponse(description = u"请输入正确的持卡人昵称(2-20位)")
  2476. phone = payload.get("phone")
  2477. if phone and not check_phone_number(phone):
  2478. return JsonErrorResponse(description = u"手机号码输入错误")
  2479. card = Card.objects(id = str(payload.get("cardId"))).first()
  2480. if not card:
  2481. return JsonErrorResponse(description = u"未找到可编辑的卡片,请刷新页面重试")
  2482. card.cardName = cardName
  2483. card.phone = phone
  2484. card.save()
  2485. return JsonOkResponse(description = u"修改成功")
  2486. @error_tolerate(nil = JsonErrorResponse(description = u"补卡失败"), logger = logger)
  2487. @permission_required(ROLE.myuser)
  2488. def swapCardNo(request):
  2489. """
  2490. 用户补卡 其实就是换个卡号
  2491. :param request:
  2492. :return:
  2493. """
  2494. payload = json.loads(request.body)
  2495. cardNo = payload.get("cardNo", "")
  2496. cardId = payload.get("cardId")
  2497. # 卡号前置去0
  2498. if cardNo.isdigit():
  2499. cardNo = str(int(cardNo))
  2500. openId = str(request.user.openId)
  2501. if not Card.check_card_no(cardNo):
  2502. return JsonErrorResponse(description = u"无效的卡号,卡号长度不能超过32位")
  2503. try:
  2504. oldCard = Card.objects.get(id = cardId)
  2505. except DoesNotExist:
  2506. return JsonErrorResponse(description = u"查询旧卡失败")
  2507. # 没有找到卡的情况下 如果代理商规定了经销商必须要先录入卡
  2508. agent = Agent.objects.get(id=oldCard.productAgentId)
  2509. dealerBindCard = True if "dealerBindCard" in agent.features else False
  2510. if dealerBindCard:
  2511. return JsonErrorResponse(description=u"无效的卡号,该卡号未被录入,请联系发卡方")
  2512. if oldCard.cardNo == cardNo:
  2513. return JsonErrorResponse(description = u"卡号一致无需修改")
  2514. if oldCard.openId != openId:
  2515. return JsonErrorResponse(description = u"不是您的卡号,无权修改")
  2516. checkStatus, checkMsg = Card.check_swap_card_no(cardNo, oldCard.dealerId, oldCard.agentId)
  2517. if not checkStatus:
  2518. return JsonErrorResponse(description = checkMsg)
  2519. # 直接将卡号更新掉,然后新建一条换卡记录
  2520. oldCard.update(cardNo = cardNo)
  2521. SwapCardRecord.add_record(oldCard.cardNo, cardNo, oldCard.agentId, str(request.user.id))
  2522. return JsonOkResponse(description = u"卡号修改成功")
  2523. @error_tolerate(nil = JsonErrorResponse(description = u"绑定失败"), logger = logger)
  2524. def bindCard(request):
  2525. """
  2526. 用户通过经销商分享的链接进来绑定实体卡
  2527. :param request:
  2528. :return:
  2529. """
  2530. openId = request.user.openId
  2531. payload = json.loads(request.body)
  2532. cardName = payload.get("cardName")
  2533. if not check_entity_name(cardName):
  2534. return JsonErrorResponse(description = u"请输入正确的持卡人昵称(2-20位)")
  2535. phone = payload.get("phone")
  2536. if not check_phone_number(phone):
  2537. return JsonErrorResponse(description = u"手机号码输入错误")
  2538. cardId = payload.get('cardId')
  2539. card = Card.objects(id = cardId).first() # type: Card
  2540. if not card:
  2541. return JsonErrorResponse(u"该实体卡不存在,请联系经销商获取正确的绑定二维码")
  2542. group = Group.get_group(card.groupId) # type: GroupDict
  2543. if not group:
  2544. return JsonErrorResponse(u'开卡地址无效,请联系经销商获取正确的绑定二维码(1001)')
  2545. dealer = Dealer.objects(id = str(group.ownerId)).first() # type: Dealer
  2546. if not dealer:
  2547. return JsonErrorResponse(u'开卡地址无效,请联系经销商获取正确的绑定二维码(1002)')
  2548. if str(dealer.id) != card.dealerId:
  2549. return JsonErrorResponse(u'开卡地址无效,请联系经销商获取正确的绑定二维码(1003)')
  2550. agent = Agent.objects(id = str(dealer.agentId)).first()
  2551. if not agent:
  2552. return JsonErrorResponse(description = u'代理商不存在,请刷新页面后重试(1002)')
  2553. productAgent = get_user_manager_agent(agent)
  2554. if str(productAgent.id) != request.user.productAgentId:
  2555. return JsonErrorResponse(description = u"不是该平台下的用户,不能绑定该平台的实体卡")
  2556. # 和卡相关的特性的获取
  2557. onlyOneCard = True if "onlyOneCard" in agent.features and not request.user.many_cards else False
  2558. if onlyOneCard and request.user.cards_num > 0:
  2559. return JsonErrorResponse(description = u"您只能绑定一张实体卡,请联系经销商了解相应的规则")
  2560. card.openId = openId
  2561. card.cardName = cardName
  2562. card.phone = phone
  2563. card.nickName = request.user.nickname
  2564. card.productAgentId = request.user.productAgentId
  2565. card.managerialAppId = request.user.managerialAppId
  2566. card.managerialOpenId = request.user.managerialOpenId
  2567. card.save()
  2568. return JsonOkResponse(description = u"添加成功", payload = {"cardId": str(card.id)})
  2569. @error_tolerate(nil = JsonErrorResponse(description = u'解绑卡失败'), logger = logger)
  2570. @record_operation_behavior()
  2571. @permission_required(ROLE.myuser)
  2572. def unbindCard(request):
  2573. # type: (WSGIRequest)->JsonResponse
  2574. openId = request.user.openId
  2575. payload = json.loads(request.body)
  2576. cardId = payload.get('id', None)
  2577. card = Card.objects(id = cardId, openId = openId).first()
  2578. if not card:
  2579. return JsonErrorResponse(description = u'找不到该卡')
  2580. updated = card.clear_card()
  2581. if not updated:
  2582. return JsonErrorResponse(description = u'变更状态失败')
  2583. return JsonResponse({"result": 1, "description": "", "payload": {}})
  2584. @error_tolerate(nil = JsonErrorResponse(description = u'获取正在使用失败'), logger = logger)
  2585. @permission_required(ROLE.myuser)
  2586. def getCurrentUse(request):
  2587. # type: (WSGIRequest)->JsonResponse
  2588. openId = request.user.openId
  2589. filters = {
  2590. "open_id": openId,
  2591. "isFinished": False,
  2592. "port": {"$ne": -1}
  2593. }
  2594. # 后付费流程中,扫码的时候会将 跳转到用户的正在服务 这个地方不要受其他设备类型的干扰
  2595. orderId = request.GET.get("orderId")
  2596. if orderId:
  2597. consumeOrder = ClientConsumeModelProxy.get_one(id=orderId)
  2598. device = Device.get_dev(consumeOrder.devNo)
  2599. if not device.owner: # 经销商此时解绑了
  2600. return JsonResponse({"result": 1, "description": "", "payload": {"total": 0, "dataList": []}})
  2601. # 下面的可以恢复正常流程
  2602. if device.devTypeCode in support_policy_device:
  2603. filters = {
  2604. "open_id": openId,
  2605. "device_imei": device.devNo,
  2606. "consumeOrder.consumeRecordId": orderId,
  2607. }
  2608. pageIndex = int(request.GET.get('pageIndex', 1))
  2609. pageSize = int(request.GET.get('pageSize', 10))
  2610. dataList = []
  2611. for item in ServiceProgress.get_collection().find(filters):
  2612. if int(time.time()) > item['finished_time']:
  2613. continue
  2614. else:
  2615. try:
  2616. devNo = item['device_imei']
  2617. device = Device.get_dev(devNo) # type: DeviceDict
  2618. smartBox = ActionDeviceBuilder.create_action_device(device)
  2619. group = Group.get_group(device['groupId'])
  2620. nowTime = int(time.time())
  2621. data = {
  2622. 'startTime': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(item['start_time'])),
  2623. 'order': item['consumeOrder'],
  2624. 'address': group.get('address', ''),
  2625. 'groupName': group.get('groupName', ''),
  2626. 'devType': device['devType'].get('name'),
  2627. 'devTypeCode': device['devType'].get('code'),
  2628. 'logicalCode': device['logicalCode'],
  2629. 'status': Const.DEV_WORK_STATUS_WORKING,
  2630. 'devNo': devNo,
  2631. 'majorDeviceType': device.majorDeviceType
  2632. }
  2633. if 'show_PG_to_user' in device.owner.features and device.support_power_graph and item.get("port"):
  2634. data.update({'showPG': True, 'port': item.get("port")})
  2635. if device['devType']['code'] in support_policy_weifule:
  2636. orderInfoList = smartBox.get_current_use(base_data=data, spDict=item)
  2637. dataList.extend(orderInfoList)
  2638. continue
  2639. needTime = item.get('consumeOrder', {}).get('needTime', None)
  2640. unit = item.get('consumeOrder', {}).get('unit', None)
  2641. if needTime and unit in [u'分钟', u'小时', u'天',
  2642. u'秒']: # 数据库里面记录的都是归为分钟(建议后续全部统一为秒).这里计算的时间是以设备为准,不是以端口为准的,实际如果有端口,应该以端口为准
  2643. if needTime == 999: # 特殊表示充满自停
  2644. data.update({'needTime': u'充满自停'})
  2645. else:
  2646. data.update({'needTime': u'%s分钟' % needTime,
  2647. 'leftTime': round(int(item['finished_time'] - nowTime) / 60.0, 1)})
  2648. if item.get('port', -2) in [0, -1]:
  2649. dataList.append(data)
  2650. continue
  2651. else:
  2652. data.update({"port": item["port"]})
  2653. ctrInfo = Device.get_dev_control_cache(devNo)
  2654. _coin = data.get("order", dict()).get("coin")
  2655. if _coin:
  2656. data["order"].update({"coin": "{}{}".format(_coin, smartBox.show_pay_unit)})
  2657. try:
  2658. curInfo = device.deviceAdapter.get_port_using_detail(item['port'], ctrInfo)
  2659. if curInfo.has_key('startTime'): # 微付乐自己的单板会上报startTime上来,和这里的startTime有冲突,所以,需要以订单的startTime为准
  2660. curInfo.pop('startTime')
  2661. if device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_HAINIAO:
  2662. curInfo['port'] = str(int(curInfo['port']) + 1)
  2663. if 'orderNo' in curInfo:
  2664. if data['order']['orderNo'] == curInfo['orderNo']: # 说明此单正处于运行中,数据可以直接用
  2665. data.update(curInfo)
  2666. else:
  2667. data.update({
  2668. 'orderNo': data['order']['orderNo'],
  2669. 'desc': u'此订单已经下发到设备上,上一单运行完毕就会自动运行此订单',
  2670. })
  2671. data.pop('leftTime', None)
  2672. data.pop('leftElec', None)
  2673. else:
  2674. data.update(curInfo)
  2675. # 正在服务显示按钮
  2676. data.update(DeviceType.get_services_button(device['devType']['id']))
  2677. try:
  2678. data.update({'actualNeedTime': data['usedTime'] + data['leftTime']})
  2679. except Exception as e:
  2680. pass
  2681. dealer = Dealer.get_dealer(device.ownerId)
  2682. if dealer:
  2683. agent = Agent.objects(id = dealer['agentId']).first() # type: Agent
  2684. if agent:
  2685. agentFeatures = agent.features
  2686. if 'show_elec_data_for_user' not in agentFeatures:
  2687. data.pop('elec', None)
  2688. data.pop('needElec', None)
  2689. data.pop('power', None)
  2690. data.pop("leftElec", None)
  2691. data.pop("usedElec",None)
  2692. if not device.is_auto_refund and "hide_refund_data_for_user" in agentFeatures:
  2693. data.pop("consumeMoney", None)
  2694. data.pop("leftMoney", None)
  2695. data.pop("usedTime", None)
  2696. data.pop("leftTime", None)
  2697. if 'hide_consume_coin_data' in device.devTypeFeatures:
  2698. data.pop('consumeMoney', None)
  2699. data.pop('leftMoney', None)
  2700. if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHARGING_HONGZHUO]:
  2701. data.pop('actualNeedTime',None)
  2702. data['power'] = data['powerNow']
  2703. if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_BL_TEN,
  2704. Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE]:
  2705. data.pop('actualNeedTime',None)
  2706. # 这里需要反过来做一次校验,因为网络不稳定,可能造成丢包,没有刷新状态。
  2707. # 如果出来的状态是空闲的,那就说明服务已经结束
  2708. # zjl 充电柜的临时跳过 下个版本会对这个function进行彻底的拆分
  2709. if device.devTypeCode not in [
  2710. Const.DEVICE_TYPE_CODE_CABINET_NEW,
  2711. Const.DEVICE_TYPE_CODE_CABINET,
  2712. Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING,
  2713. Const.DEVICE_TYPE_CODE_CHANGING_BL_TEN,
  2714. Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE,] + support_policy_device:
  2715. isFinished = False
  2716. if curInfo.has_key('power') and curInfo.has_key('leftTime'):
  2717. if curInfo['power'] == 0 and curInfo['leftTime'] in [0, u'(线路空载)']:
  2718. isFinished = True
  2719. else:
  2720. if (curInfo.has_key('power') and curInfo['power'] == 0) or (
  2721. curInfo.has_key('leftTime') and curInfo['leftTime'] in [0, u'(线路空载)']):
  2722. isFinished = True
  2723. if isFinished:
  2724. try:
  2725. ServiceProgress.get_collection().update_many(
  2726. {
  2727. 'open_id': openId,
  2728. 'isFinished': False,
  2729. 'device_imei': devNo,
  2730. 'port': item['port']
  2731. }, {
  2732. '$set':
  2733. {
  2734. 'isFinished': True,
  2735. 'expireAt': datetime.datetime.now()
  2736. }
  2737. })
  2738. data['leftTime'] = 0
  2739. except Exception as e:
  2740. logger.error('update service progress e=%s' % e)
  2741. except Exception as e:
  2742. logger.exception('get cur info=%s' % e)
  2743. dataList.append(data)
  2744. except Exception as e:
  2745. logger.exception(e)
  2746. # 返回数据之前 将数据再次过滤一遍
  2747. count = len(dataList)
  2748. dataList = dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  2749. newDataList = list()
  2750. for _consumeDict in dataList:
  2751. if "devNo" in _consumeDict:
  2752. dev = Device.get_dev(_consumeDict["devNo"])
  2753. newDataList.append(UserConsumeFilter(dev.owner, _consumeDict).filter())
  2754. else:
  2755. newDataList.append(_consumeDict)
  2756. return JsonResponse({
  2757. "result": 1,
  2758. "description": "",
  2759. "payload": {
  2760. "total": count,
  2761. "dataList": newDataList
  2762. }
  2763. })
  2764. @error_tolerate(nil=JsonErrorResponse(description = u'获取计数失败'), logger = logger)
  2765. @permission_required(ROLE.myuser)
  2766. def getUserCenterCount(request):
  2767. # type: (WSGIRequest)->JsonResponse
  2768. openId = request.user.openId
  2769. # 统计正在使用
  2770. currentUse = ConsumeRecord.objects.filter(
  2771. openId=openId,
  2772. status__in=[
  2773. ConsumeRecord.Status.RUNNING, ConsumeRecord.Status.END
  2774. ]
  2775. ).count()
  2776. # 统计反馈消息
  2777. dealerIds = MyUser.get_dealer_ids(openId, request.user.productAgentId)
  2778. newMessage = FeedBack.objects.filter(openId=openId, ownerId__in=dealerIds, isRead=False)
  2779. return JsonResponse(
  2780. {
  2781. "result": 1,
  2782. "description": "",
  2783. "payload": {
  2784. "currentUse": currentUse, "newMessage": newMessage.count()
  2785. }
  2786. })
  2787. @error_tolerate(nil = JsonErrorResponse(description = u'获取卡记录失败'), logger = logger)
  2788. @permission_required(ROLE.myuser)
  2789. def getUserCardRecord(request):
  2790. # type: (WSGIRequest)->JsonResponse
  2791. pageIndex = int(request.GET.get('pageIndex', 1))
  2792. pageSize = int(request.GET.get('pageSize', 10))
  2793. startTime = request.GET.get('startTime', 10)
  2794. endTime = request.GET.get('endTime', 10)
  2795. cardId = request.GET.get('cardId', None)
  2796. type = request.GET.get('type', None)
  2797. card = Card.objects.get(id = cardId)
  2798. if type == "chargeCard":
  2799. dataList = []
  2800. for item in CardRechargeRecord.get_collection().find(
  2801. {
  2802. 'cardId': cardId,
  2803. 'dateTimeAdded':
  2804. {
  2805. '$gte': to_datetime(startTime + " 00:00:00"),
  2806. '$lte': to_datetime(endTime + " 23:59:59")
  2807. },
  2808. "remarks": {
  2809. "$ne": u"退币"
  2810. }
  2811. }
  2812. ).sort("dateTimeAdded", -1):
  2813. data = {
  2814. "cardId": str(item['_id']),
  2815. "cardNo": card.cardNo,
  2816. "via": "chargeCard",
  2817. "amount": item['money'],
  2818. "coins": item.get('coins', item['money']),
  2819. "address": item['address'],
  2820. "groupName": item['groupName'],
  2821. "balance": item['balance'],
  2822. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S')
  2823. }
  2824. if item.has_key('preBalance'):
  2825. data.update({'preBalance': item['preBalance']})
  2826. dataList.append(data)
  2827. elif type == "consume":
  2828. dataList = []
  2829. rcds = CardConsumeRecord.get_collection().find({'cardId': cardId,
  2830. 'dateTimeAdded': {
  2831. '$gte': to_datetime(startTime + " 00:00:00"),
  2832. '$lte': to_datetime(endTime + " 23:59:59")}}).sort(
  2833. "dateTimeAdded", -1)
  2834. for item in rcds:
  2835. newData = {
  2836. "cardId": str(cardId),
  2837. "cardNo": card.cardNo,
  2838. "via": "consume",
  2839. "devType": item['devType'],
  2840. "amount": item['money'],
  2841. "logicalCode": item['logicalCode'],
  2842. "address": item['address'],
  2843. "groupName": item['groupName'],
  2844. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S')
  2845. }
  2846. newData.update(item.get('servicedInfo', {}))
  2847. dataList.append(newData)
  2848. elif type == 'order':
  2849. dataList = [
  2850. {
  2851. "via": "order",
  2852. "amount": item['money'],
  2853. "coins": item.get('coins', item['money']),
  2854. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'),
  2855. "status": u'等待刷卡充值' if item['status'] == 'finishedPay' else u'充值完成',
  2856. "desc": item['remarks']
  2857. }
  2858. for item in CardRechargeOrder.get_collection().find({
  2859. 'cardId': cardId,
  2860. 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  2861. '$lte': to_datetime(endTime + " 23:59:59")}})
  2862. .sort("dateTimeAdded", -1)]
  2863. elif type == "refund":
  2864. dataList = []
  2865. for item in CardRechargeRecord.get_collection().find(
  2866. {
  2867. 'cardId': cardId,
  2868. 'dateTimeAdded':
  2869. {
  2870. '$gte': to_datetime(startTime + " 00:00:00"),
  2871. '$lte': to_datetime(endTime + " 23:59:59")
  2872. },
  2873. "remarks": u"退币"
  2874. }
  2875. ).sort("dateTimeAdded", -1):
  2876. data = {
  2877. "cardId": str(item['_id']),
  2878. "cardNo": card.cardNo,
  2879. "via": "refund",
  2880. "amount": item['money'],
  2881. "coins": item.get('coins', item['money']),
  2882. "address": item['address'],
  2883. "groupName": item['groupName'],
  2884. "balance": item['balance'],
  2885. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S')
  2886. }
  2887. if item.has_key('preBalance'):
  2888. data.update({'preBalance': item['preBalance']})
  2889. dataList.append(data)
  2890. elif type == "frozen":
  2891. dataList = []
  2892. for item in getattr(card, 'ongoingList', []):
  2893. order = ConsumeRecord.objects.filter(id = item['transaction_id']).first()
  2894. data = {
  2895. "amount": order.coin.mongo_amount,
  2896. "createdTime": order.startTime.strftime(Const.DATETIME_FMT),
  2897. "via": "consume",
  2898. "devType": order.dev_type_name,
  2899. "chargeIndex": order.used_port,
  2900. "logicalCode": order.logicalCode,
  2901. "address": order.address,
  2902. "groupName": order.groupName,
  2903. "balance": card.balance.mongo_amount,
  2904. "spendMoney": order.coin.mongo_amount,
  2905. }
  2906. dataList.append(data)
  2907. else:
  2908. return JsonResponse({"result": 0, "description": u"查询类型错误", "payload": {}})
  2909. return JsonResponse({"result": 1, "description": "", "payload": {"total": len(dataList), "dataList": dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]}})
  2910. @permission_required(ROLE.myuser)
  2911. def freezeCard(request):
  2912. # type: (WSGIRequest)->JsonResponse
  2913. payload = json.loads(request.body)
  2914. isFrozen = payload.get('frozen')
  2915. cardId = payload.get('id', '')
  2916. try:
  2917. card = Card.objects.get(id = cardId)
  2918. card.frozen = isFrozen
  2919. card.status = 'deactive'
  2920. card.save()
  2921. except Exception as e:
  2922. logger.exception(e.message)
  2923. return JsonResponse({"result": 0, "description": u'系统错误', "payload": {}})
  2924. # 如果是淋浴器,如果卡正在使用,直接把设备停掉,发指令过去
  2925. return JsonResponse({"result": 1, "description": '', "payload": {}})
  2926. @permission_required(ROLE.myuser)
  2927. def bindVirtualCardToRechargeIDCard(request):
  2928. # type: (WSGIRequest)->JsonResponse
  2929. # TODO zjl 这个地方最好加上虚拟卡的绑定记录
  2930. payload = json.loads(request.body)
  2931. virtualCardId = payload.get('virtualCardId')
  2932. rechargeIDCardId = payload.get('rechargeIDCardId')
  2933. if virtualCardId is None:
  2934. return JsonErrorResponse(description = u'未找到虚拟卡ID')
  2935. if rechargeIDCardId is None:
  2936. return JsonErrorResponse(description = u'未找到ID实体卡')
  2937. card = Card.objects(id = rechargeIDCardId).first()
  2938. if card is None:
  2939. return JsonErrorResponse(description = u'未找到ID实体卡')
  2940. if card.cardType != RECHARGE_CARD_TYPE.ID:
  2941. return JsonErrorResponse(description = u'该卡不是ID卡')
  2942. virtualCard = UserVirtualCard.objects(id = virtualCardId).first()
  2943. if virtualCard is None:
  2944. return JsonErrorResponse(description = u'未找到虚拟卡')
  2945. updated = card.bind_virtual_card(virtualCard)
  2946. if updated:
  2947. return JsonOkResponse()
  2948. else:
  2949. return JsonErrorResponse(description = u'绑定失败')
  2950. def unbindVirtualCardToRechargeIDCard(request):
  2951. # type: (WSGIRequest)->JsonResponse
  2952. payload = json.loads(request.body)
  2953. virtualCardId = payload.get('virtualCardId')
  2954. rechargeIDCardId = payload.get('rechargeIDCardId')
  2955. if virtualCardId is None:
  2956. return JsonErrorResponse(description = u'未找到虚拟卡ID')
  2957. if rechargeIDCardId is None:
  2958. return JsonErrorResponse(description = u'未找到ID实体卡')
  2959. card = Card.objects(id = rechargeIDCardId).first()
  2960. if card is None:
  2961. return JsonErrorResponse(description = u'未找到ID实体卡')
  2962. if card.cardType != RECHARGE_CARD_TYPE.ID:
  2963. return JsonErrorResponse(description = u'该卡不是ID卡')
  2964. virtualCard = UserVirtualCard.objects(id = virtualCardId).first()
  2965. if virtualCard is None:
  2966. return JsonErrorResponse(description = u'未找到虚拟卡')
  2967. updated = card.unbind_virtual_card(virtualCard)
  2968. if updated:
  2969. return JsonOkResponse()
  2970. else:
  2971. return JsonErrorResponse(description = u'解绑失败')
  2972. @permission_required(ROLE.myuser)
  2973. def cardDiscountList(request):
  2974. # type: (WSGIRequest)->JsonResponse
  2975. """
  2976. 获取用户实体卡套餐.
  2977. 获取的方式有两种:
  2978. 1、实体卡管理里面,直接选择卡,进入套餐界面。传入cardId参数;
  2979. 2、在扫码的充卡界面,直接输入卡号,进入套餐界面,传入扫码的设备号;
  2980. :param request:
  2981. :return:
  2982. """
  2983. def user_center_recharge(card_id):
  2984. card = Card.objects(id = str(card_id)).first() # type: Card
  2985. if not card:
  2986. logger.error('can not find the cardId = %s' % request.GET.get('cardId'))
  2987. return JsonResponse({'result': 0, 'description': u'没有找到对应的卡,请您刷新页面重试', 'payload': {}})
  2988. if not card.dealerId or not card.groupId:
  2989. return JsonResponse({
  2990. 'result': ErrorCode.CARD_NEED_BIND_GROUP,
  2991. 'description': u'此卡没有绑定开卡地址',
  2992. 'payload': {
  2993. 'cardId': str(card.id),
  2994. 'cardNo': card.cardNo,
  2995. 'phone': card.phone,
  2996. 'cardName': card.cardName
  2997. }})
  2998. group = Group.get_group(card.groupId) # type: GroupDict
  2999. card_rule_list = group.card_rule_list
  3000. card_rule_list = filter(lambda x: (float(x["coins"]) + float(card.balance)) < 5000, card_rule_list)
  3001. return JsonResponse({
  3002. 'result': 1, 'description': 'SUCCESS', 'payload': {'groupId': card.groupId, 'ruleList': card_rule_list}})
  3003. def device_type_card_charge(devCache):
  3004. """
  3005. 从套餐页面的充卡按钮进入的卡充值页面。
  3006. 不同设备类型进入不同的判断,后续有新的设备类型特有的需求增加新的判断分支。
  3007. """
  3008. if devCache.devTypeCode == Const.DEVICE_TYPE_CODE_WASHCAR_LANGUANG:
  3009. box = ActionDeviceBuilder.create_action_device(devCache)
  3010. devStatus = box.get_dev_status()
  3011. if devStatus.get('xf_status') == '0x0001':
  3012. allowCardCharge = True
  3013. else:
  3014. allowCardCharge = False
  3015. return allowCardCharge
  3016. return True
  3017. if 'cardId' in request.GET:
  3018. return user_center_recharge(request.GET.get('cardId'))
  3019. else:
  3020. if 'devNo' in request.GET and request.GET.get('devNo'):
  3021. dev = Device.get_dev(request.GET.get('devNo')) # type: Optional[DeviceDict]
  3022. elif 'logicalCode' in request.GET and request.GET.get('logicalCode'):
  3023. dev = Device.get_dev_by_logicalCode(request.GET.get('logicalCode')) # type: Optional[DeviceDict]
  3024. else:
  3025. dev = None # type: Optional[DeviceDict]
  3026. if not dev:
  3027. return JsonErrorResponse(description = u'参数错误,请刷新重试(1001)')
  3028. if device_type_card_charge(dev) is False:
  3029. return JsonErrorResponse(description = u'暂不支持卡充值,请联系经销商检查设备或重试一下')
  3030. group = Group.get_group(dev.groupId) # type: GroupDict
  3031. return JsonResponse({'result': 1, 'description': 'SUCCESS',
  3032. 'payload': {'groupId': dev.groupId, 'ruleList': group.card_rule_list}})
  3033. @error_tolerate(nil = JsonErrorResponse(description = u'未知错误'))
  3034. def getAgentQRCode(request):
  3035. # type: (WSGIRequest)->JsonResponse
  3036. agentId = request.GET.get('agentId', None)
  3037. if agentId is None:
  3038. return JsonErrorResponse(description = u'页面过期,请您重新扫码重试')
  3039. try:
  3040. agent = Agent.objects.get(id = agentId)
  3041. if agent.gzhServiceQrcodeUrl == '':
  3042. return JsonErrorResponse(description = u'没有提供公众号的二维码,需要先配置好公众号的二维码')
  3043. else:
  3044. return JsonOkResponse(
  3045. payload = {'url': agent.gzhServiceQrcodeUrl, 'linkUrl': agent.gzhServiceLinkUrl, 'title': agent.title,
  3046. 'desc': agent.desc})
  3047. except DoesNotExist:
  3048. logger.exception('could not find agent by agentId={0}'.format(agentId))
  3049. return JsonErrorResponse(description = u'没有找到对应的代理商,请您检查数据是否正确')
  3050. @permission_required(ROLE.myuser)
  3051. def reportEndUserLocation(request):
  3052. # type: (WSGIRequest)->JsonResponse
  3053. """
  3054. 上报终端用户的地理信息
  3055. `sample request`
  3056. {
  3057. 'logicalCode': '111',
  3058. 'lng': 12323.23
  3059. 'lat': 1232123.22,
  3060. 'type': 'gcj02'
  3061. }
  3062. :param request:
  3063. :return:
  3064. """
  3065. currentUser = request.user # type: cast(MyUser)
  3066. payload = json.loads(request.body)
  3067. logger.debug('end user location is: %s' % payload)
  3068. try:
  3069. GPS_TYPE.lookupByValue(payload['type'])
  3070. except ValueError:
  3071. return JsonErrorResponse(u'无效的GPS类型')
  3072. pointPair = (float(payload.get('lng', 360)), float(payload.get('lat', 360))) # type: Tuple[float, float]
  3073. if any(map(lambda _: _ == 360 or isnan(_), pointPair)):
  3074. return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'})
  3075. if pointPair in [_.coordinates for _ in currentUser.locations]:
  3076. logger.debug('user{0!r} location point{1} duplicates'.format(currentUser, pointPair))
  3077. return JsonResponse({'result': 1, 'description': ''})
  3078. location = EndUserLocation(logicalCode = payload['logicalCode'],
  3079. point = pointPair,
  3080. type = payload['type'])
  3081. updated = currentUser.update(add_to_set__locations = location)
  3082. if not updated:
  3083. logger.info(u'记录终端用户地址失败 user({0!r}) payload={1}'.format(currentUser, payload))
  3084. return JsonResponse({'result': 1, 'description': ''})
  3085. @permission_required(ROLE.myuser)
  3086. def getOnsale(request):
  3087. # type: (WSGIRequest)->JsonResponse
  3088. """
  3089. 用户侧 进入之前获取营销活动的流程
  3090. :param request:
  3091. :return:
  3092. """
  3093. lc = request.GET.get('logicalCode')
  3094. showSite = int(request.GET.get('showSite'))
  3095. dev = Device.get_dev_by_logicalCode(lc)
  3096. nowTime = datetime.datetime.now()
  3097. onsales = OnSale.objects.filter(status = 'start', showSite = showSite, dealerId = dev['ownerId'],
  3098. logicalCodeList = lc, startTime__lte = nowTime, endTime__gte = nowTime)
  3099. if onsales.count() <= 0:
  3100. return JsonOkResponse()
  3101. onsaleList = []
  3102. # 查询是否已经参加了活动, 如果已经参加 并且活动描述仅仅只能参加一次 不在展示该活动
  3103. for onsale in onsales:
  3104. if OnSaleRecord.objects.filter(onsaleId = str(onsale['id']), userId__in = [str(request.user.id),
  3105. request.user.openId]).count() and onsale.showType == "onlyOne":
  3106. continue
  3107. onsaleList.append(onsale)
  3108. if not onsaleList:
  3109. return JsonOkResponse()
  3110. # TODO 这个活动为什么是随机的 ??? 这个 shuffle 也很有问题
  3111. # random.shuffle(onsaleList)
  3112. # onsale = onsaleList[0]
  3113. onsale = random.choice(onsaleList)
  3114. return JsonResponse({
  3115. "result": 1, "description": '',
  3116. "payload": {
  3117. 'onsaleId': str(onsale.id),
  3118. 'img': onsale.img,
  3119. 'desc': onsale.desc,
  3120. 'onClickUrl': onsale.onClickUrl,
  3121. 'showType': onsale.showType
  3122. }
  3123. })
  3124. @permission_required(ROLE.myuser)
  3125. def getPromotionalCoins(request):
  3126. # type: (WSGIRequest)->JsonResponse
  3127. """
  3128. 营销活动,用户获币
  3129. :param request:
  3130. :return:
  3131. """
  3132. lc = request.GET.get('logicalCode')
  3133. onsaleId = request.GET.get('onsaleId')
  3134. # 先检查这个用户是否有领取过,如果领取过,就不允许领取
  3135. if not onsaleId:
  3136. return JsonErrorResponse(description = u'找不到营销活动ID')
  3137. if not lc:
  3138. return JsonErrorResponse(description = u'找不到设备')
  3139. user = request.user # type: MyUser
  3140. userId = str(user.id)
  3141. key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId)
  3142. with memcache_lock(key = key, value = '1', expire = 60) as acquired:
  3143. if acquired:
  3144. count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = userId).count()
  3145. if count > 0:
  3146. return JsonErrorResponse(description = u'您已经领取过金币了哦,不能再领了哦')
  3147. onsale = OnSale.objects(id = onsaleId).first() # type: Optional[OnSale]
  3148. if not onsale:
  3149. return JsonErrorResponse(description = u'推广活动不存在')
  3150. if onsale.status == 'stop':
  3151. return JsonErrorResponse(description = u'推广活动已经下架,无法领取了哦')
  3152. coins = int(onsale.detailDict.get('coins', 0))
  3153. updated = user.incr_balance(VirtualCoin(coins))
  3154. if not updated:
  3155. return JsonErrorResponse(description = u'获币失败')
  3156. # 添加一条充值记录
  3157. orderNo = str(uuid.uuid1())
  3158. dev = Device.get_dev_by_logicalCode(lc)
  3159. group = Group.get_group(dev['groupId'])
  3160. try:
  3161. newRcd = RechargeRecord(orderNo = orderNo,
  3162. coins = coins, money = 0.00, openId = request.user.openId,
  3163. groupId = dev['groupId'],
  3164. devNo = dev['devNo'], logicalCode = lc,
  3165. ownerId = dev['ownerId'], groupName = group['groupName'],
  3166. groupNumber = dev['groupNumber'], address = group['address'],
  3167. wxOrderNo = u'活动赠币',
  3168. devTypeName = dev.devTypeName, nickname = '',
  3169. result = 'success', via = 'onsaleSendCoins')
  3170. newRcd.save()
  3171. except Exception as e:
  3172. logger.exception('update record for feedback coins error=%s,orderNo=%s' % (e, orderNo))
  3173. # 增加一条活动
  3174. try:
  3175. newRcd = OnSaleRecord(
  3176. onsaleId = onsaleId,
  3177. userId = userId,
  3178. nickName = request.user.nickname,
  3179. addedTime = datetime.datetime.now(),
  3180. onsaleDetail = {'coins': coins}
  3181. )
  3182. newRcd.save()
  3183. except Exception as e:
  3184. logger.exception('update record for onsale record error=%s,orderNo=%s' % e)
  3185. return JsonOkResponse(description = u'赠送成功!您可以直接使用金币!')
  3186. else:
  3187. return JsonErrorResponse(description = u'您已正在领取')
  3188. @permission_required(ROLE.myuser)
  3189. def getPromotionalDuration(request):
  3190. # type: (WSGIRequest)->JsonResponse
  3191. """
  3192. :param request:
  3193. :return:
  3194. """
  3195. lc = request.GET.get('logicalCode')
  3196. onsaleId = request.GET.get('onsaleId')
  3197. # 先检查这个用户是否有领取过,如果领取过,就不允许领取
  3198. if not onsaleId:
  3199. return JsonErrorResponse(description = u'找不到营销活动ID')
  3200. if not lc:
  3201. return JsonErrorResponse(description = u'找不到设备')
  3202. userId = str(request.user.id)
  3203. key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId)
  3204. with memcache_lock(key = key, value = '1', expire = 60) as acquired:
  3205. if acquired:
  3206. # 先检查这个用户是否有领取过,如果领取过,就不允许领取
  3207. count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = userId).count()
  3208. if count > 0:
  3209. return JsonErrorResponse(description = u'您已经免费体验过了哦,不能再免费体验了哦,您可以试试充值消费哦')
  3210. onsale = OnSale.objects(id = onsaleId).first() # type: Optional[OnSale]
  3211. if not onsale:
  3212. return JsonErrorResponse(description = u'该活动不存在')
  3213. if onsale.status == 'stop':
  3214. return JsonErrorResponse(description = u'推广活动已经下架,无法体验了哦')
  3215. duration = int(onsale.detailDict.get('duration')) * 60
  3216. dev = Device.get_dev_by_logicalCode(lc) # type: DeviceDict
  3217. box = ActionDeviceBuilder.create_action_device(dev)
  3218. try:
  3219. box.send_dev_runtime(request.user.openId, duration)
  3220. except ServiceException, e:
  3221. return JsonErrorResponse(description = e.result.get('description'))
  3222. except Exception, e:
  3223. return JsonErrorResponse(description = u'系统异常,请您重试')
  3224. # 增加一条活动
  3225. try:
  3226. OnSaleRecord(
  3227. onsaleId = onsaleId,
  3228. userId = str(request.user.id),
  3229. nickName = request.user.nickname,
  3230. addedTime = datetime.datetime.now(),
  3231. onsaleDetail = {'duration': int(onsale.detailDict.get('duration'))}
  3232. ).save()
  3233. except Exception as e:
  3234. logger.exception('update record for onsale record error=%s' % (e,))
  3235. return JsonOkResponse(description = u'服务开始啦!您可以体验啦')
  3236. else:
  3237. return JsonErrorResponse(description = u'您已领取福利')
  3238. @permission_required(ROLE.myuser)
  3239. def getBannerList(request):
  3240. # type: (WSGIRequest)->JsonResponse
  3241. """
  3242. :param request:
  3243. :return:
  3244. """
  3245. lc = request.GET.get('logicalCode')
  3246. dev = Device.get_dev_by_logicalCode(lc)
  3247. dealer = Dealer.objects.get(id = dev['ownerId'])
  3248. agent = Agent.objects.get(id = dealer.agentId)
  3249. aBannerList = agent.bannerList
  3250. if not aBannerList or dealer.isShowBanner is False:
  3251. return JsonResponse({"result": 1, "description": '', "payload": {}})
  3252. return JsonResponse({"result": 1, "description": '', "payload": aBannerList})
  3253. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  3254. @permission_required(ROLE.myuser)
  3255. def submitComment(request):
  3256. # type: (WSGIRequest)->JsonResponse
  3257. """
  3258. :param request:
  3259. :return:
  3260. """
  3261. payload = json.loads(request.body)
  3262. lc = payload.get('logicalCode')
  3263. desc = payload.get('description')
  3264. dev = Device.get_dev_by_logicalCode(lc)
  3265. group = Group.get_group(dev['groupId'])
  3266. Comment(
  3267. devNo = dev['devNo'],
  3268. logicalCode = lc,
  3269. groupId = dev['groupId'],
  3270. groupNumber = dev['groupNumber'],
  3271. groupName = group['groupName'],
  3272. address = group['address'],
  3273. ownerId = dev['ownerId'],
  3274. openId = request.user.openId,
  3275. nickname = request.user.nickname,
  3276. ratingList = payload['rating'],
  3277. description = desc
  3278. ).save()
  3279. return JsonResponse({"result": 1, "description": '', "payload": {}})
  3280. @permission_required(ROLE.myuser)
  3281. def onsaleRecharge(request):
  3282. # type: (WSGIRequest)->JsonResponse
  3283. """
  3284. :param request:
  3285. :return:
  3286. """
  3287. user = request.user # type: MyUser
  3288. lc = request.GET.get('logicalCode')
  3289. if not lc:
  3290. return JsonResponse({"result": 0, "description": u'设备不存在,请刷新后重试(1001)', "payload": {}})
  3291. device = Device.get_dev_by_logicalCode(lc) # type: DeviceDict
  3292. if not device:
  3293. return JsonResponse({"result": 0, "description": u'设备不存在,请刷新后重试(1002)', "payload": {}})
  3294. onsaleId = request.GET.get('onsaleId')
  3295. if not onsaleId:
  3296. return JsonResponse({"result": 0, "description": u'活动ID错误,请刷新后重试', "payload": {}})
  3297. if user.groupId != device.groupId:
  3298. return JsonResponse({"result": 0, "description": u'请在扫码后点击活动页面去充值。点击其他方式的活动链接无效。', "payload": {}})
  3299. jumpUrl = concat_user_recharge_url(l = lc)
  3300. # 增加一条活动
  3301. try:
  3302. OnSaleRecord(
  3303. onsaleId = onsaleId,
  3304. userId = str(request.user.id),
  3305. nickName = request.user.nickname,
  3306. addedTime = datetime.datetime.now(),
  3307. onsaleDetail = {}
  3308. ).save()
  3309. except Exception as e:
  3310. logger.exception(e)
  3311. return JsonResponse({"result": 0, "description": u'系统异常,请重试', "payload": {}})
  3312. return JsonResponse({"result": 1, "description": '', "payload": {'url': jumpUrl}})
  3313. @permission_required(ROLE.myuser)
  3314. def onsaleTicketList(request):
  3315. # type: (WSGIRequest)->JsonResponse
  3316. """
  3317. :param request:
  3318. :return:
  3319. """
  3320. user = request.user # type: MyUser
  3321. lc = request.GET.get('logicalCode')
  3322. onsaleId = request.GET.get('onsaleId')
  3323. agentId = user.productAgentId
  3324. if agentId is None:
  3325. return JsonResponse({"result": 0, "description": '获取代理商错误', "payload": {}})
  3326. encodeUrl = concat_user_cardTicketList_entry_url(agentId = agentId, l = lc)
  3327. # 增加一条活动
  3328. try:
  3329. OnSaleRecord(
  3330. onsaleId = onsaleId,
  3331. userId = str(request.user.id),
  3332. nickName = request.user.nickname,
  3333. addedTime = datetime.datetime.now(),
  3334. onsaleDetail = {}
  3335. ).save()
  3336. except Exception as e:
  3337. logger.exception(e)
  3338. return JsonResponse({"result": 0, "description": u'系统异常,请重试', "payload": {}})
  3339. return JsonResponse({"result": 1, "description": '', "payload": {'url': encodeUrl}})
  3340. @permission_required(ROLE.myuser)
  3341. def sendCodeForVerify(request):
  3342. # type: (WSGIRequest)->JsonResponse
  3343. """
  3344. :param request:
  3345. :return:
  3346. """
  3347. payload = json.loads(request.body)
  3348. lc = payload.get('logicalCode')
  3349. onsaleId = payload.get('onsaleId')
  3350. userId = str(request.user.id)
  3351. key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId)
  3352. with memcache_lock(key = key, value = '1', expire = 60) as acquired:
  3353. if acquired:
  3354. count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = userId).count()
  3355. if count > 0:
  3356. return JsonErrorResponse(description = u'您已经免费体验过了哦,不能再免费体验了哦,您可以试试充值消费哦')
  3357. dev = Device.get_dev_by_logicalCode(lc) # type: DeviceDict
  3358. phoneNumber = payload.get('phoneNumber')
  3359. dealer = Dealer.get_dealer(dev['ownerId'])
  3360. agent = Agent.objects.get(id = dealer['agentId'])
  3361. status, msg = userMobileVerifySMSProvider.get(phoneNumber = phoneNumber,
  3362. productName = agent.productName,
  3363. vendor = SysParas.get_sms_vendor(request.user.smsVendor))
  3364. if not status:
  3365. return JsonErrorResponse(description = msg)
  3366. else:
  3367. return JsonOkResponse()
  3368. else:
  3369. return JsonErrorResponse(description = u'您已正在领取')
  3370. @permission_required(ROLE.myuser)
  3371. def mobileVerify(request):
  3372. # type: (WSGIRequest)->JsonResponse
  3373. """
  3374. :param request:
  3375. :return:
  3376. """
  3377. payload = json.loads(request.body)
  3378. lc = payload.get('logicalCode')
  3379. onsaleId = payload.get('onsaleId')
  3380. phoneNumber = payload.get('phoneNumber')
  3381. code = payload.get('code')
  3382. userId = str(request.user.id)
  3383. key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId)
  3384. with memcache_lock(key = key, value = '1', expire = 60) as acquired:
  3385. if acquired:
  3386. status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code)
  3387. if not status:
  3388. return JsonErrorResponse(description = msg)
  3389. count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = str(request.user.id)).count()
  3390. if count > 0:
  3391. return JsonResponse({"result": 0, "description": u'您已经免费体验过了哦,不能再免费体验了哦,您可以试试充值消费哦', "payload": {}})
  3392. try:
  3393. onsale = OnSale.objects.get(id = onsaleId)
  3394. except Exception as e:
  3395. logger.exception(e)
  3396. return JsonResponse({"result": 0, "description": u'推广活动已经下架,无法体验了哦', "payload": {}})
  3397. if onsale.status == 'stop':
  3398. return JsonResponse({"result": 0, "description": u'推广活动已经下架,无法体验了哦', "payload": {}})
  3399. duration = int(onsale.detailDict.get('duration')) * 60
  3400. dev = Device.get_dev_by_logicalCode(lc)
  3401. duration = int(onsale.detailDict.get('duration')) * 60
  3402. dev = Device.get_dev_by_logicalCode(lc) # type: DeviceDict
  3403. box = ActionDeviceBuilder.create_action_device(dev)
  3404. try:
  3405. box.send_dev_runtime(request.user.openId, duration)
  3406. except ServiceException, e:
  3407. return JsonErrorResponse(description = e.result.get('description'))
  3408. except Exception, e:
  3409. return JsonErrorResponse(description = u'系统异常,请您重试')
  3410. # 增加一条活动
  3411. try:
  3412. OnSaleRecord(
  3413. onsaleId = onsaleId,
  3414. userId = str(request.user.id),
  3415. nickName = request.user.nickname,
  3416. addedTime = datetime.datetime.now(),
  3417. onsaleDetail = {'duration': int(onsale.detailDict.get('duration')),
  3418. 'phoneNumber': phoneNumber}
  3419. ).save()
  3420. except Exception as e:
  3421. logger.exception('update record for onsale record error=%s' % (e,))
  3422. return JsonOkResponse(description = u'服务开始啦!您可以体验啦')
  3423. else:
  3424. return JsonErrorResponse(description = u'您已领取福利')
  3425. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  3426. def test(request):
  3427. return JsonOkResponse()
  3428. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  3429. def getCurrentOrder(request):
  3430. # type: (WSGIRequest)->JsonResponse
  3431. """
  3432. 获取目前用户目前订单的情况,给予用户下面操作的指示
  3433. :param request:
  3434. :return:
  3435. """
  3436. devNo = request.GET.get('devNo')
  3437. startKey = request.GET.get('startKey')
  3438. if not startKey:
  3439. return JsonErrorResponse(description = u'未找到启动key')
  3440. def get_response(orderProcessing, succeeded, desc = '', record = None):
  3441. record = {} if record is None else record
  3442. return JsonOkResponse(
  3443. payload = {
  3444. 'orderProcessing': orderProcessing,
  3445. 'succeeded': succeeded,
  3446. 'desc': desc,
  3447. 'record': record
  3448. }
  3449. )
  3450. #: 前台还需要发送请求轮询获取数据
  3451. not_yet = get_response(orderProcessing = True, succeeded = None)
  3452. #: 有错误或状态未知,前台可以停止轮询
  3453. stop_polling_unknown = get_response(orderProcessing = False, succeeded = False, desc = u'系统异常')
  3454. #: 确切知道启动成功
  3455. polling_finished_succeeded = lambda desc, record: get_response(orderProcessing = False,
  3456. succeeded = True,
  3457. desc = desc,
  3458. record = record)
  3459. #: 确切知道启动失败
  3460. polling_finished_failed = lambda desc, record: get_response(orderProcessing = False,
  3461. succeeded = False,
  3462. desc = desc,
  3463. record = record)
  3464. record = None
  3465. start_key_status = get_start_key_status(startKey) # type: dict
  3466. if start_key_status:
  3467. logger.debug('getCurrentOrder startKey = %s; status = %s; ts = %s' %
  3468. (startKey, start_key_status,
  3469. timestamp_to_dt(start_key_status['ts']).strftime(
  3470. '%Y-%m-%d %H:%M:%S') if 'ts' in start_key_status else ''))
  3471. state = start_key_status['state']
  3472. if state == START_DEVICE_STATUS.FAILURE or state == START_DEVICE_STATUS.TIMEOUT:
  3473. return polling_finished_failed(desc=start_key_status['reason'], record = None)
  3474. if state == START_DEVICE_STATUS.FINISHED:
  3475. if 'orderId' in start_key_status:
  3476. record = ConsumeRecord.objects(id = str(start_key_status['orderId'])).first() # type: ConsumeRecord
  3477. if not record:
  3478. logger.error('start key cache is not valid. value = {}'.format(str(start_key_status)))
  3479. return stop_polling_unknown
  3480. else:
  3481. logger.debug('start key status is {}'.format(state))
  3482. # 如果查过2分钟还没有结果,直接检查订单
  3483. exp = long(request.GET.get('exp', 0))
  3484. if exp < 2 * 60 * 1000:
  3485. return not_yet
  3486. else:
  3487. logger.debug('too long to get result. try to query record.')
  3488. if not record:
  3489. record = ConsumeRecord.objects(startKey = startKey).first() # type: Optional[ConsumeRecord]
  3490. if not record:
  3491. logger.error('cache and record are null, startKey = {}'.format(startKey))
  3492. return not_yet
  3493. if record.status in [ConsumeRecord.Status.WAITING, ConsumeRecord.Status.CREATED]:
  3494. return not_yet
  3495. dev = Device.get_dev(devNo) # type: DeviceDict
  3496. if not dev:
  3497. logger.error('cannot find device by devNo(%s))' % (devNo,))
  3498. return stop_polling_unknown
  3499. if record.isNormal:
  3500. #: 表明应用服务器并未发现异常,但是还是有可能实际场景失败,比如吃币,所以需要给用户良好的指导和要求其上传证据。并返回币数以便上分
  3501. return polling_finished_succeeded(
  3502. desc = u'您已成功启动设备。如果有疑问,请点击右下角"设备无反应"按钮',
  3503. record = {'coins': record.coin, 'detailLink': record.deail_link(dev), "isIns": record.insId}
  3504. )
  3505. else:
  3506. #: 设备服务器与设备连接失败(超时 etc,.)需要记录失败场景,同时保证用户不扣币,前台则给予提示其重试
  3507. return polling_finished_failed(
  3508. desc = record.errorDesc,
  3509. record = {'coins': record.coin, 'detailLink': record.deail_link(dev)}
  3510. )
  3511. @permission_required(ROLE.myuser)
  3512. def getOrderStatus(request):
  3513. # type: (WSGIRequest)->JsonResponse
  3514. """
  3515. 蓝牙获取订单状态
  3516. :param request:
  3517. :return:
  3518. """
  3519. payload = json.loads(request.body)
  3520. try:
  3521. order_id = str(payload.get('orderId'))
  3522. if OrderCacheMgr(order_id, cls_name = RechargeRecord.__name__).has_done():
  3523. record = RechargeRecord.objects(id = str(payload.get('orderId'))).first() # type: RechargeRecord
  3524. if record.is_success():
  3525. return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'success'}})
  3526. else:
  3527. return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'fail'}})
  3528. else:
  3529. return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'nop'}})
  3530. except Exception as e:
  3531. logger.exception(e)
  3532. return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'nop'}})
  3533. @permission_required(ROLE.myuser)
  3534. def pressButton(request):
  3535. # type: (WSGIRequest)->JsonResponse
  3536. payload = json.loads(request.body)
  3537. button_name = payload.get('button')
  3538. value = payload.get('value')
  3539. lc = payload.get('logicalCode')
  3540. dev = Device.get_dev_by_logicalCode(lc)
  3541. smartBox = ActionDeviceBuilder.create_action_device(dev)
  3542. try:
  3543. devInfo = smartBox.press_button(button_name, value)
  3544. except ServiceException as e:
  3545. return JsonErrorResponse(description = e.result.get('description'))
  3546. except Exception as e:
  3547. logger.exception('cannot get_port_status, error=%s' % (str(e),))
  3548. return JsonErrorResponse(description = u'未知错误')
  3549. return JsonResponse({"result": 1, "description": '', "payload": devInfo})
  3550. @permission_required(ROLE.myuser)
  3551. def changeVolume(request):
  3552. # type: (WSGIRequest)->JsonResponse
  3553. payload = json.loads(request.body)
  3554. logical_volume = payload.get('logicalCode')
  3555. volume = payload.get('value')
  3556. dev = Device.get_dev_by_logicalCode(logical_volume)
  3557. smart_box = ActionDeviceBuilder.create_action_device(dev)
  3558. try:
  3559. result = smart_box.changeVolume(volume)
  3560. return JsonResponse({"result": 1, "description": '', "payload": result})
  3561. except ServiceException as e:
  3562. return JsonErrorResponse(description = e.result.get('description'))
  3563. except AttributeError as e:
  3564. return JsonErrorResponse(description = u'暂时不支持该功能')
  3565. except Exception as e:
  3566. logger.exception('cannot changeVolume, error=%s' % (str(e),))
  3567. return JsonErrorResponse(description = u'未知错误')
  3568. @record_operation_behavior()
  3569. @permission_required(ROLE.myuser)
  3570. def stopCountDown(request):
  3571. # type: (WSGIRequest)->JsonResponse
  3572. openId = str(request.user.openId)
  3573. payload = json.loads(request.body)
  3574. port = payload.get('chargeIndex', None)
  3575. devNo = Device.get_devNo_by_logicalCode(logicalCode = payload['logicalCode'])
  3576. devCtrInfo = Device.get_dev_control_cache(devNo = devNo)
  3577. orderNo = payload.get("orderNo")
  3578. # 如果设备本身停止后,有停止时间上报,系统会在停止事件中处理退费、通知事宜。这里要做的就是直接停止而已.
  3579. dev = Device.get_dev(devNo = devNo) # type: DeviceDict
  3580. groupId = str(dev.get("groupId"))
  3581. group = Group.get_group(groupId)
  3582. box = ActionDeviceBuilder.create_action_device(dev)
  3583. if box.isHaveStopEvent:
  3584. try:
  3585. if dev.devType["code"] in [Const.DEVICE_TYPE_CODE_CHARGE_WEIFULE_CAR,
  3586. Const.DEVICE_TYPE_CODE_CAR_WEIFULE_CHARGING_DOUB,
  3587. Const.DEVICE_TYPE_CODE_CAR_WEIFULE_21KW,
  3588. Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,
  3589. Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG,
  3590. Const.DEVICE_TYPE_CODE_CHANGING_SOCKET,
  3591. Const.DEVICE_TYPE_CODE_WEIFULE_TOUCH_PAD,
  3592. Const.DEVICE_TYPE_CODE_WEIFULE_ANJIAN,
  3593. ] or dev.support_reliable:
  3594. box.stop_by_order(port, orderNo)
  3595. else:
  3596. box.stop(port)
  3597. except ServiceException, e:
  3598. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  3599. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  3600. # 没有停止事件的,需要在这里处理退费事宜
  3601. if port is None:
  3602. for ii in range(10):
  3603. try:
  3604. portInfo = devCtrInfo.get(str(ii + 1), None)
  3605. if portInfo is None:
  3606. continue
  3607. if portInfo.has_key('openId') and portInfo['openId'] == openId and portInfo['status'] in [
  3608. Const.DEV_WORK_STATUS_WORKING, Const.DEV_WORK_STATUS_PAUSE]:
  3609. port = str(ii + 1)
  3610. break
  3611. except Exception, e:
  3612. continue
  3613. with memcache_lock(key = start_device_lock_key(openId = openId), value = '1', expire = 360) as acquired:
  3614. if acquired:
  3615. if port is not None:
  3616. devCtrInfo = devCtrInfo.get(str(port), {})
  3617. totalFee = devCtrInfo.get('coins', None)
  3618. if totalFee is None:
  3619. logger.error('feedback coins error devNo=%s, totalFee=%s' % (devNo, totalFee))
  3620. return JsonResponse({"result": 0, "description": u'获取订购金额失败', "payload": {}})
  3621. totalTime = devCtrInfo.get('needTime', None)
  3622. if totalTime is None:
  3623. for _ in dev['washConfig'].values():
  3624. if totalFee == _['price']:
  3625. totalTime = int(_['time'])
  3626. try:
  3627. devInfo = box.stop(port)
  3628. except ServiceException, e:
  3629. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  3630. if 'remainder_time' not in devInfo: # 有些情况,是不需要根据时间退费的,比如云快充的充电桩,会根据事件,直接结算
  3631. return JsonResponse({"result": 1, "description": '', "payload": ''})
  3632. remainderTime = devInfo['remainder_time']
  3633. # 更新内存缓存状态
  3634. if port is None:
  3635. Device.invalid_device_control_cache(devNo)
  3636. else:
  3637. ctrInfo = Device.get_dev_control_cache(devNo)
  3638. ctrInfo.update({str(port): {}})
  3639. Device.update_dev_control_cache(devNo, ctrInfo)
  3640. refundFee = box.calc_stop_back_coins(totalFee, remainderTime, totalTime)
  3641. backCoins = VirtualCoin(refundFee)
  3642. desc = u'共付款:%s元,预定时间为:%s分钟,剩余时间:%s' % (
  3643. totalFee, totalTime, remainderTime)
  3644. # 通知完成
  3645. user = MyUser.objects(openId = openId, groupId = groupId).first()
  3646. task_caller('report_to_user_via_wechat', openId = user.managerialOpenId, dealerId = dev['ownerId'],
  3647. templateName = 'service_complete',
  3648. **{
  3649. 'title': u'订购总时间为:%s分钟,剩余时间:%s分钟' % (
  3650. totalTime,
  3651. remainderTime),
  3652. 'service': u'服务(设备编号:%s,地址:%s)' % (
  3653. payload['logicalCode'], group['address']),
  3654. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  3655. 'remark': u'谢谢您的支持'
  3656. })
  3657. # 如果需要退款,计算退款数据.
  3658. if not dev.is_auto_refund:
  3659. ServiceProgress.update_progress_and_consume_rcd(
  3660. dev['ownerId'],
  3661. {'open_id': openId, 'device_imei': devNo, 'isFinished': False},
  3662. {'leftTime': remainderTime,
  3663. 'needTime': u'扫码订购%s分钟' % totalTime,
  3664. 'duration': totalTime - remainderTime}
  3665. )
  3666. else:
  3667. # 扫码退钱, 退到个人账号
  3668. user.incr_balance(backCoins)
  3669. # 添加一条充值记录
  3670. orderNo = str(uuid.uuid4())
  3671. try:
  3672. newRcd = RechargeRecord(orderNo = orderNo,
  3673. coins = backCoins, openId = openId, groupId = str(request.user.groupId),
  3674. devNo = devNo, logicalCode = payload['logicalCode'],
  3675. ownerId = dev['ownerId'],
  3676. groupName = group['groupName'], groupNumber = dev['groupNumber'],
  3677. address = group['address'], wxOrderNo = u'设备退币',
  3678. devTypeName = dev.devTypeName, nickname = '',
  3679. result = 'success', via = 'refund')
  3680. newRcd.save()
  3681. except Exception as e:
  3682. logger.exception('update record for feedback coins error=%s,orderNo=%s' % (e, orderNo))
  3683. ServiceProgress.update_progress_and_consume_rcd(
  3684. dev['ownerId'],
  3685. {'open_id': openId, 'device_imei': devNo, 'isFinished': False},
  3686. {'leftTime': remainderTime,
  3687. 'needTime': u'扫码订购%s分钟' % totalTime,
  3688. 'duration': totalTime - remainderTime}
  3689. )
  3690. task_caller('report_to_user_via_wechat', openId = user.managerialOpenId, dealerId = dev['ownerId'],
  3691. templateName = 'refund_coins',
  3692. **{
  3693. 'title': desc,
  3694. 'backCount': u'金币:%s' % backCoins,
  3695. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  3696. })
  3697. return JsonResponse({"result": 1, "description": '', "payload": ''})
  3698. @error_tolerate(nil=JsonErrorResponse(u"获取虚拟卡列表失败"))
  3699. @permission_required(ROLE.myuser)
  3700. def getCardTicketList(request): # type: (WSGIRequest)->JsonResponse
  3701. """
  3702. 获取虚拟卡的列表
  3703. """
  3704. pageIndex = int(request.GET.get('pageIndex', 1))
  3705. pageSize = int(request.GET.get('pageSize', 10))
  3706. invalid = int(request.GET.get("invalid", 0))
  3707. openId = request.user.openId
  3708. now_time = datetime.datetime.now()
  3709. filters = {"openIds": openId}
  3710. if invalid:
  3711. filters.update({"expiredTime__lt": now_time})
  3712. else:
  3713. filters.update({"expiredTime__gte": now_time})
  3714. vCards = UserVirtualCard.objects.filter(**filters)
  3715. total = vCards.count()
  3716. dataList = list()
  3717. for _vcard in vCards.skip((pageIndex - 1) * pageSize).limit(pageSize):
  3718. data = _vcard.to_dict()
  3719. # 检查是否需要续费
  3720. isNeedRenew, days = is_need_renew(_vcard)
  3721. if isNeedRenew:
  3722. data.update({'needRenew': True})
  3723. # 添加是否是卡主
  3724. data.update({"isOwner": _vcard.isOwner(request.user.openId)})
  3725. dataList.append(data)
  3726. return JsonOkResponse(payload={
  3727. 'total': total, 'pageSize': pageSize, 'dataList': dataList
  3728. })
  3729. @error_tolerate(nil=JsonErrorResponse(u"获取虚拟卡详情失败"))
  3730. @permission_required(ROLE.myuser)
  3731. def getCardTicket(request):
  3732. cardId = request.GET.get("cardId")
  3733. try:
  3734. card = UserVirtualCard.objects.get(id=cardId)
  3735. except DoesNotExist:
  3736. return JsonErrorResponse(description=u"获取虚拟卡详情失败")
  3737. payload = card.to_detail()
  3738. isNeedRenew, days = is_need_renew(card)
  3739. if isNeedRenew:
  3740. payload.update({'needRenew': True})
  3741. payload.update({
  3742. "isOwner": card.isOwner(request.user.openId),
  3743. "agentId": request.user.productAgentId
  3744. })
  3745. return JsonOkResponse(payload=payload)
  3746. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  3747. @permission_required(ROLE.myuser)
  3748. def getUserVirtualCardByGroup(request):
  3749. """
  3750. 通过groupId查询该地址下有没有购买过虚拟卡
  3751. :param request:
  3752. :return:
  3753. """
  3754. groupId = request.GET.get("groupId")
  3755. if not groupId:
  3756. return JsonErrorResponse(u"查询错误")
  3757. # 如果没有通过地址数量的检查 则直接提示不能开卡
  3758. if not Group.check_virtual_card_number(groupId):
  3759. return JsonErrorResponse(description = u"该地址虚拟卡数量已经达到上限,请联系发卡经销商")
  3760. vCards = UserVirtualCard.objects.filter(
  3761. openIds__in = [request.user.openId],
  3762. groupIds__in = ['*', groupId],
  3763. expiredTime__gt = datetime.datetime.now()
  3764. )
  3765. vCardList = [str(vCard.cardNo) for vCard in vCards]
  3766. return JsonOkResponse(payload = {"vCardList": vCardList})
  3767. @permission_required(ROLE.myuser)
  3768. def getCardTicketTypeList(request):
  3769. # type: (WSGIRequest)->JsonResponse
  3770. groupId = request.GET.get('groupId', None)
  3771. if groupId is None:
  3772. return JsonErrorResponse(u'没有找到您的充值地址哦')
  3773. if not Group.check_virtual_card_number(groupId):
  3774. return JsonErrorResponse(description=u"该地址虚拟卡数量已经达到上限,请联系发卡经销商")
  3775. group = Group.get_group(groupId)
  3776. onlineCards = VirtualCard.objects.filter(
  3777. ownerId=group['ownerId'],
  3778. status=1,
  3779. groupIds__in=['*', groupId],
  3780. expiredTime__gt=datetime.datetime.now()
  3781. )
  3782. dataList = []
  3783. for obj in onlineCards:
  3784. data = obj.to_dict()
  3785. if '*' in obj.groupIds:
  3786. groups = [{'groupName': grp['groupName'], 'address': grp['address']} for grp in
  3787. Group.get_groups_by_group_ids(Group.get_group_ids_of_dealer(obj.ownerId)).values()]
  3788. else:
  3789. groups = [{'groupName': grp['groupName'], 'address': grp['address']} for grp in
  3790. Group.get_groups_by_group_ids(obj.groupIds).values()]
  3791. data["groups"] = groups
  3792. dataList.append(data)
  3793. return JsonOkResponse(payload={'dataList': dataList})
  3794. # 分享卡卷的链接
  3795. @permission_required(ROLE.myuser)
  3796. def getShareCardTicket(request):
  3797. # type: (WSGIRequest)->JsonResponse
  3798. vCardId = request.GET.get('cardId', None)
  3799. if vCardId is None:
  3800. return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被卡主注销,无法共享', "payload": None})
  3801. try:
  3802. vCard = UserVirtualCard.objects.get(id = vCardId)
  3803. except DoesNotExist as e:
  3804. return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被卡主注销,无法共享', "payload": None})
  3805. if len(vCard.openIds) > vCard.userLimit - 1:
  3806. return JsonResponse({"result": 0, "description": u'共享的人数已经达到卡的限制,您无法共享哦', "payload": None})
  3807. agentId = Dealer.get_dealer(vCard.dealerId).get('agentId', None)
  3808. if agentId is None:
  3809. return JsonResponse({"result": 0, "description": u'非法卡,您无法共享哦', "payload": None})
  3810. if request.user.agentId != agentId:
  3811. return JsonResponse({"result": 0, "description": u'非法卡,您无法共享哦', "payload": None})
  3812. if request.user.openId in vCard.openIds:
  3813. return JsonResponse({"result": 0, "description": u'您已经共享了此卡', "payload": None})
  3814. vCard.openIds.append(request.user.openId)
  3815. try:
  3816. vCard.save()
  3817. except Exception as e:
  3818. logger.info('save sharing card error=%s' % e)
  3819. return JsonResponse({"result": 0, "description": u'保存卡的信息异常,请您重试', "payload": None})
  3820. data = vCard.to_detail()
  3821. data.update({
  3822. "isOwner": vCard.isOwner(request.user.openId),
  3823. "agentId": request.user.productAgentId
  3824. })
  3825. return JsonResponse({"result": 1, "description": '', "payload": data})
  3826. @permission_required(ROLE.myuser)
  3827. def removeCardSharedMembers(request):
  3828. # type: (WSGIRequest)->JsonResponse
  3829. payload = json.loads(request.body)
  3830. vCardId = payload.get('cardId')
  3831. openId = payload.get('userId')
  3832. if vCardId is None:
  3833. return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被注销,请您刷新页面后再重试', "payload": None})
  3834. try:
  3835. vCard = UserVirtualCard.objects.get(id = vCardId)
  3836. except DoesNotExist:
  3837. return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被注销,请您刷新页面后再重试', "payload": None})
  3838. vCard.openIds.remove(openId)
  3839. try:
  3840. vCard.save()
  3841. except Exception as e:
  3842. logger.info('save sharing card error=%s' % e)
  3843. return JsonResponse({"result": 0, "description": u'保存卡的信息异常,请您重试', "payload": None})
  3844. return JsonResponse({"result": 1, "description": '', "payload": None})
  3845. @permission_required(ROLE.myuser)
  3846. def stopService(request):
  3847. # type: (WSGIRequest)->JsonResponse
  3848. payload = json.loads(request.body)
  3849. logicalCode = payload.get('logicalCode')
  3850. port = payload.get('port', None)
  3851. dev = Device.get_dev_by_l(logicalCode)
  3852. box = ActionDeviceBuilder.create_action_device(dev)
  3853. try:
  3854. box.stop(port)
  3855. except ServiceException, e:
  3856. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  3857. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  3858. @permission_required(ROLE.myuser)
  3859. def toggleDeviceStatus(request):
  3860. # type: (WSGIRequest)->JsonResponse
  3861. payload = json.loads(request.body)
  3862. logicalCode = payload.get('logicalCode')
  3863. port = payload.get('chargeIndex', None)
  3864. isContinue = False if payload.get('targetStatus', None) == 'pause' else True
  3865. dev = Device.get_dev_by_l(logicalCode)
  3866. box = ActionDeviceBuilder.create_action_device(dev)
  3867. try:
  3868. result = box.pause(request.user.openId, isContinue, port)
  3869. return JsonResponse({'result': 1, 'description': '', 'payload': result})
  3870. except ServiceException, e:
  3871. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  3872. @permission_required(ROLE.myuser)
  3873. def getDeviceSellItems(request):
  3874. payload = json.loads(request.body)
  3875. logicalCode = payload.get('logicalCode')
  3876. objs = Cell.objects.filter(logicalCode = logicalCode, itemStatus = 'full')
  3877. dataList = [{
  3878. 'cellNo': obj.cellNo, 'boardNo': obj.boardNo,
  3879. 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle,
  3880. 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl,
  3881. 'itemPrice': obj.itemPrice
  3882. } for obj in objs]
  3883. return JsonResponse({'result': 1, 'description': '', 'payload': {'dataList': dataList}})
  3884. @permission_required(ROLE.myuser)
  3885. def getDeviceCells(request):
  3886. logicalCode = request.GET.get('logicalCode')
  3887. objs = Cell.objects.filter(logicalCode = logicalCode)
  3888. dev = Device.get_dev_by_logicalCode(logicalCode)
  3889. box = ActionDeviceBuilder.create_action_device(dev)
  3890. lockStatusDict = box.get_all_lock_status()
  3891. dataList = [{'id': str(obj.id), 'cellNo': obj.cellNo, 'boardNo': obj.boardNo,
  3892. 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle,
  3893. 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl,
  3894. 'itemPrice': round(obj.itemPrice / 100.0, 2), 'lockStatus': lockStatusDict.get(obj.cellNo, 'close')}
  3895. for obj in objs if (lockStatusDict.get(obj.cellNo, 'close') == 'close' and obj.itemStatus != 'empty')]
  3896. return JsonResponse({'result': 1, 'description': '', 'payload': {'dataList': dataList}})
  3897. @permission_required(ROLE.myuser)
  3898. def updateUserActiveInfo(request):
  3899. """
  3900. 安骑换电用户 的身份信息上传接口
  3901. 需要信息 手机验证码 手机号码 身份验证信息 推荐人信息(非必须)
  3902. 推荐人
  3903. # 新添加了字段 phoneNumber
  3904. """
  3905. user = request.user # type: MyUser
  3906. if user.is_product_user():
  3907. return JsonErrorResponse(u"请先扫描设备")
  3908. active_info = MyUser.get_active_info(user.openId, agentId = user.agentId)
  3909. if active_info and active_info.get("isMember"):
  3910. return JsonErrorResponse(u"您已经完成实名认证,请勿重复")
  3911. payload = json.loads(request.body)
  3912. code = payload.get("code", "")
  3913. phoneNumber = payload.get("phoneNumber", "")
  3914. imgList = payload.get("imgList", [])
  3915. recommender = payload.get("recommender", "")
  3916. if phoneNumber:
  3917. if MyUser.objects.filter(
  3918. Q(phoneNumber = phoneNumber),
  3919. Q(agentId = request.user.agentId) | Q(productAgentId = request.user.productAgentId)
  3920. ):
  3921. return JsonErrorResponse(description = u"手机号码已经被注册!")
  3922. # 推荐人如果填写必须有效 并且非本人 并且激活
  3923. if recommender:
  3924. if not MyUser.objects.filter(
  3925. Q(phoneNumber = recommender),
  3926. Q(agentId = request.user.agentId) | Q(productAgentId = request.user.productAgentId)
  3927. ) or recommender == phoneNumber:
  3928. return JsonErrorResponse(u"无效的推荐人")
  3929. status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code)
  3930. if not status:
  3931. return JsonErrorResponse(msg)
  3932. MyUser.set_active_info(
  3933. {"phoneNumber": phoneNumber,
  3934. "imgList": imgList,
  3935. "recommender": recommender,
  3936. "status": 1,
  3937. "createdTime": datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S")
  3938. },
  3939. openId = user.openId,
  3940. agentId = user.agentId,
  3941. groupId = user.groupId
  3942. )
  3943. return JsonOkResponse()
  3944. @permission_required(ROLE.myuser)
  3945. def getUserActiveInfo(request):
  3946. user = request.user
  3947. active_info = MyUser.get_active_info(user.openId, agentId = user.agentId)
  3948. status = active_info.get("status", "")
  3949. payload = {
  3950. "id": user.id,
  3951. "identifyUrl": active_info.get("identifyUrl", ""),
  3952. "recommender": active_info.get("recommender", ""),
  3953. "phoneNumber": active_info.get("phoneNumber", ""),
  3954. "status": status if status else 0,
  3955. "remarks": active_info.get("remarks", "")
  3956. }
  3957. return JsonResponse({"result": 1, "description": '', "payload": payload})
  3958. @permission_required(ROLE.myuser)
  3959. def getTelVerifyInfo(request):
  3960. user = request.user
  3961. status = 1 if user.phone else 0
  3962. return JsonResponse({"result": 1, "description": "", "payload": {"status": status}})
  3963. @permission_required(ROLE.myuser)
  3964. def updateTelVerifyInfo(request):
  3965. """
  3966. 绑定手机号码. 手机号码只是做为属性, 谁能获取验证码, 手机号码就是谁的
  3967. """
  3968. user = request.user
  3969. jsonData = json.loads(request.body)
  3970. phoneNumber = jsonData.get("phoneNumber", "")
  3971. code = jsonData.get("code", "")
  3972. # 首先校验 短信验证码
  3973. status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code)
  3974. if not status:
  3975. return JsonErrorResponse(msg)
  3976. try:
  3977. user.phone = phoneNumber
  3978. except Exception as e:
  3979. logger.exception(e)
  3980. return JsonErrorResponse(description=u"手机号码绑定失败,请刷新重试")
  3981. return JsonOkResponse(description=u"绑定成功")
  3982. @permission_required(ROLE.myuser)
  3983. def sendActiveSmsCode(request):
  3984. """
  3985. 安骑换电用户 获取手机验证码 手机号码
  3986. """
  3987. user = request.user
  3988. payload = json.loads(request.body)
  3989. phoneNumber = payload.get("phoneNumber", "")
  3990. # phoneNumber 唯一
  3991. checkUser = MyUser.objects.filter(
  3992. Q(phoneNumber = phoneNumber),
  3993. Q(agentId = request.user.agentId) | Q(productAgentId = request.user.productAgentId)
  3994. ).first()
  3995. if checkUser and checkUser.gateway == user.gateway:
  3996. return JsonErrorResponse(u"该号码已经被注册")
  3997. agent = Agent.objects.get(id = user.agentId)
  3998. status, msg = userMobileVerifySMSProvider.get(phoneNumber = phoneNumber,
  3999. productName = agent.productName,
  4000. vendor = SysParas.get_sms_vendor(request.user.smsVendor),
  4001. openId = user.openId)
  4002. if not status:
  4003. return JsonErrorResponse(description = msg)
  4004. else:
  4005. return JsonOkResponse()
  4006. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'上传身份文件图片存储失败,请重新试试'))
  4007. @permission_required(ROLE.myuser)
  4008. def UploadIdentify(request):
  4009. """
  4010. 用户上传身份验证
  4011. """
  4012. files = request.FILES.getlist('file')
  4013. if not len(files):
  4014. return JsonResponse({'result': 0, 'description': u'未知的身份文件信息,请重新试试', 'payload': {}})
  4015. uploader = AliOssFileUploader(inputFile = request.FILES.getlist('file')[0], uploadType = 'identify')
  4016. logger.info('[uploadItemPic] %s is being used' % (repr(uploader),))
  4017. try:
  4018. outputUrl = uploader.upload()
  4019. return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl})
  4020. except InvalidFileSize, e:
  4021. logger.info(
  4022. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  4023. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  4024. except InvalidFileName, e:
  4025. logger.info(
  4026. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  4027. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  4028. @permission_required(ROLE.myuser)
  4029. def UserActiveIntercepter(request):
  4030. """
  4031. 安骑用户 拦截器 身份认证未通过的用户
  4032. """
  4033. user = request.user
  4034. active_info = MyUser.get_active_info(openId = user.openId, agentId = user.agentId)
  4035. isMember = active_info.get("isMember", False)
  4036. return JsonOkResponse(payload = {"isMember": int(isMember)})
  4037. @permission_required(ROLE.myuser)
  4038. def DeviceTrack(request):
  4039. """
  4040. 电池电压、位置信息 存在位置信息
  4041. """
  4042. # TODO 数据库分库整改
  4043. # 获取用户的最后一次serverProcess 从中获取用户电池的IMEI
  4044. # API查询电池信息
  4045. # 返回信息
  4046. user = request.user
  4047. active_info = MyUser.get_active_info(openId = user.openId, agentId = user.agentId)
  4048. status = active_info.get("status", 0)
  4049. if status != 2: # 完成身份认证的用户状态是2
  4050. return JsonErrorResponse(u"请先完成身份认证信息")
  4051. # 找出换电柜的使用记录 并且拿到的电池的编号不为-1
  4052. record = ConsumeRecord.objects.filter(
  4053. openId = user.openId,
  4054. servicedInfo__newBatteryImei__exists = True,
  4055. servicedInfo__newBatteryImei__ne = "-1"
  4056. ).order_by("-dateTimeAdded").first()
  4057. if not record:
  4058. return JsonErrorResponse(u"未获取到有效电池信息")
  4059. battery = record.servicedInfo.get("newBatteryImei")
  4060. try:
  4061. result = batteryInfo(battery)
  4062. except Exception as e:
  4063. logger.info("get battery info error ,reason is : %s" % e)
  4064. return JsonErrorResponse(u"网络故障,获取电池信息失败")
  4065. batInfo = result.get(battery)
  4066. if not batInfo:
  4067. return JsonErrorResponse(u"电池编号错误")
  4068. lng = batInfo.get("lng")
  4069. lat = batInfo.get("lat")
  4070. lng, lat = coordinateHandler(lng, lat)
  4071. payload = {
  4072. "total": 1,
  4073. "items": [
  4074. {
  4075. "lng": lng,
  4076. "lat": lat,
  4077. "remarks": u"当前电池电压信息是%s" % batInfo.get("voltage"),
  4078. }
  4079. ]
  4080. }
  4081. return JsonOkResponse(payload = payload)
  4082. @error_tolerate(logger=logger)
  4083. @permission_required(ROLE.myuser)
  4084. # @ServerSwitch.payment_switch('系统维护升级中,请稍后重试')
  4085. def payGateway(request):
  4086. # type: (WSGIRequest)->HttpResponse
  4087. """
  4088. 用户请求充值
  4089. 两层机制保证订单不被重复处理。
  4090. 1、用户订单创建后,在cache塞一个值为0的key;在收到回调或者查询到状态后,对这个key加1。如果返回新值为2则代表已经有处理过。
  4091. 2、如果cache失效,那么返回值为None。这个时候需要判断RechargeRecord的update结果,如果有修改,则代表没处理;否则已经处理过
  4092. :param request:
  4093. :return:
  4094. """
  4095. from apps.web.common.transaction.pay import PayPullUpFactoryIntf
  4096. class PayPullUpFactory(PayPullUpFactoryIntf):
  4097. @classmethod
  4098. def create_by_alipay(cls, payment_gateway, payParam, record):
  4099. current_user = payParam.curUser
  4100. open_id = current_user.get_bound_pay_openid(payment_gateway.bound_openid_key)
  4101. pull_up_cls = PayManager().get_pull_up(payment_gateway.pay_app_type)
  4102. return pull_up_cls(open_id, payment_gateway, record, **{
  4103. 'showAd': payParam.showAd,
  4104. 'notifyUrl': PAY_NOTIFY_URL.ALI_PAY_BACK
  4105. })
  4106. @classmethod
  4107. def create_by_wechat(cls, payment_gateway, payParam, record):
  4108. current_user = payParam.curUser
  4109. open_id = current_user.get_bound_pay_openid(payment_gateway.bound_openid_key)
  4110. from pprint import pprint
  4111. pprint(open_id)
  4112. pull_up_cls = PayManager().get_pull_up(payment_gateway.pay_app_type)
  4113. return pull_up_cls(open_id, payment_gateway, record, **{
  4114. 'showAd': payParam.showAd,
  4115. 'notifyUrl': PAY_NOTIFY_URL.WECHAT_PAY_BACK
  4116. })
  4117. @classmethod
  4118. def create(cls, payment_gateway, record, **payload):
  4119. payParam = payload.get('payParam')
  4120. if payment_gateway.pay_app_type == PayAppType.ALIPAY:
  4121. return cls.create_by_alipay(payment_gateway, payParam, record)
  4122. elif payment_gateway.pay_app_type == PayAppType.WECHAT:
  4123. return cls.create_by_wechat(payment_gateway, payParam, record)
  4124. else:
  4125. raise UserServerException(u'不支持的支付方式')
  4126. try:
  4127. logger.info('----{user} unified order----'.format(user=repr(request.user)))
  4128. payParam = PayParam(request) # type: PayParam
  4129. payParam.call_check()
  4130. payment_gateway = payParam.payGateway
  4131. if not payment_gateway:
  4132. raise UserServerException(u'第三方支付配置错误,请联系平台客服(1001)')
  4133. record = BUILDER_MAP.get(payParam.recordBuilderKey)(payParam) # type: RechargeRecord
  4134. from apps.web.common.transaction.pay import PayPullUp
  4135. pull_up = PayPullUp.create(PayPullUpFactory, payment_gateway, record, **{'payParam': payParam})
  4136. response = pull_up.do()
  4137. if 'startKey' in payParam.attachParas:
  4138. set_start_key_status(payParam.attachParas['startKey'], START_DEVICE_STATUS.PAYING)
  4139. return response
  4140. except InterceptException as e:
  4141. logger.debug(e.redirect)
  4142. return JsonResponse({
  4143. 'result': ErrorCode.LOGIN_VERIFY,
  4144. 'payload': {
  4145. 'redirect': e.redirect
  4146. }
  4147. })
  4148. except ServiceException as e:
  4149. logger.error(str(e))
  4150. return JsonResponse(e.result)
  4151. except UserServerException as e:
  4152. logger.error(e.message)
  4153. return JsonErrorResponse(e.message)
  4154. except AliException as e:
  4155. logger.error(str(e))
  4156. return JsonErrorResponse(description=e.message)
  4157. except Exception as e:
  4158. logger.exception(e)
  4159. return JsonErrorResponse(description=u'系统错误,请重试')
  4160. finally:
  4161. logger.info('----{user} unified order over----'.format(user=repr(request.user)))
  4162. @error_tolerate(logger = logger)
  4163. @permission_required(ROLE.myuser)
  4164. def setMyUserDetail(request):
  4165. user = request.user # type: MyUser
  4166. payload = json.loads(request.body)
  4167. ownerId = payload.pop('ownerId')
  4168. MyUserDetail.objects(openId = str(user.openId), dealerId = str(ownerId)).upsert_one(
  4169. openId = str(user.openId), dealerId = str(ownerId),
  4170. userName = payload.get('userName'), userPhone = payload.get('userPhone'),
  4171. userUnit = payload.get('userUnit'), userFloor = payload.get('userFloor'),
  4172. userRoom = payload.get('userRoom'))
  4173. return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': {}})
  4174. @error_tolerate(logger = logger)
  4175. def payNotify(request, pay_app_type):
  4176. # type: (WSGIRequest, str)->JsonResponse
  4177. if pay_app_type == PayAppType.ALIPAY:
  4178. payload = request.POST.dict()
  4179. if 'refund_fee' in payload and 'gmt_refund' in payload:
  4180. notifier_cls = RefundManager().get_notifier(pay_app_type)
  4181. return notifier_cls(request, lambda order_no: RefundMoneyRecord.get_record(order_no)).do(refund_post_pay)
  4182. recharge_cls_factory = lambda order_no: RechargeRecord
  4183. notifier_cls = PayManager().get_notifier(pay_app_type = pay_app_type)
  4184. return notifier_cls(request, recharge_cls_factory).do(post_pay)
  4185. @permission_required(ROLE.myuser)
  4186. def getFavoriteDevice(request):
  4187. pageIndex = int(request.GET.get('pageIndex', 1))
  4188. pageSize = int(request.GET.get('pageSize', 10))
  4189. devNoList = request.user.collectedDeviceList
  4190. devs = Device.get_dev_by_nos(devNoList, verbose = True)
  4191. dataList = []
  4192. for dev in devs.values():
  4193. dev.update({'type': dev['devType'].get('name', '')})
  4194. dataList.append(dev)
  4195. return JsonOkResponse(
  4196. payload = {'total': len(dataList), 'items': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]})
  4197. @permission_required(ROLE.myuser)
  4198. def deleteFavoriteDevice(request):
  4199. payload = json.loads(request.body)
  4200. lcCodes = payload['logicalCodeList']
  4201. removeList = set()
  4202. for lcCode in lcCodes:
  4203. devNo = Device.get_devNo_by_logicalCode(lcCode)
  4204. removeList.add(devNo)
  4205. devNolist = set(request.user.collectedDeviceList)
  4206. request.user.collectedDeviceList = list(devNolist - removeList)
  4207. return JsonOkResponse()
  4208. @permission_required(ROLE.myuser)
  4209. def addFavoriteDevice(request):
  4210. payload = json.loads(request.body)
  4211. isFavorite = payload['favorite']
  4212. lcCode = payload['logicalCode']
  4213. devNo = Device.get_devNo_by_logicalCode(lcCode)
  4214. collectedDeviceList = request.user.collectedDeviceList
  4215. if isFavorite:
  4216. if devNo not in collectedDeviceList:
  4217. collectedDeviceList.append(devNo)
  4218. request.user.collectedDeviceList = collectedDeviceList
  4219. else:
  4220. return JsonOkResponse(description = u'该设备已经收藏啦')
  4221. else:
  4222. if devNo in collectedDeviceList:
  4223. collectedDeviceList.remove(devNo)
  4224. request.user.collectedDeviceList = collectedDeviceList
  4225. else:
  4226. return JsonOkResponse(description = u'该设备已经取消收藏啦')
  4227. return JsonOkResponse()
  4228. # 检查是否需要弹出加粉界面。1、需要获取监督号的openId。2、检查是否需要弹出加粉界面
  4229. # 监督号的入口也需要调用此函数,目的是找到客户应该登录的agentId。
  4230. @permission_required(ROLE.myuser)
  4231. def moniUserAccess(request):
  4232. logger.info('receive moniUserAccess')
  4233. # 目前只支持微信加粉
  4234. try:
  4235. href = request.GET.get('redirect')
  4236. moniAppId = request.GET.get('moniAppId', None)
  4237. if moniAppId is None:
  4238. agent = Agent.objects.get(id = request.user.agentId)
  4239. moniApp = agent.get_online_moni_app()
  4240. if not moniApp:
  4241. return ErrorResponseRedirect(error = cn(u'请您刷新下页面,重新点击试试'))
  4242. else:
  4243. try:
  4244. moniApp = MoniApp.get_collection().find({'appId': moniAppId})[0]
  4245. except Exception, e:
  4246. return ErrorResponseRedirect(error = cn(u'建议您从扫码页面关注公众号,这样才可以使用此公众号的服务哦'))
  4247. # 返回跳转页面
  4248. state = MoniUserAuthState(appId = moniApp['appId'], openId = request.user.openId, href = href)
  4249. wechatApp = WechatAuthApp(appid = moniApp['appId'], secret = moniApp['secret'])
  4250. bridge = WechatAuthBridge(wechatApp)
  4251. return ExternalResponseRedirect(
  4252. bridge.generate_auth_url_base_scope(redirect_uri = USER_AUTH_REDIRECT_URL.MONI_BASE,
  4253. payload = state.encode()))
  4254. except Exception, e:
  4255. logger.exception(e)
  4256. return ErrorResponseRedirect(error = cn(u'系统开小差了~~~,请您刷新下页面,重新点击试试'))
  4257. @permission_required(ROLE.myuser)
  4258. def checkPoint(request):
  4259. logger.info('checkPoint,receive,user openId=%s' % request.user.openId)
  4260. # 目前只支持微信加粉
  4261. if (not detect_wechat_client(request)):
  4262. logger.info('checkPoint,it is not wechat client')
  4263. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4264. try:
  4265. point = request.GET.get('point')
  4266. logicalCode = request.GET.get('logicalCode')
  4267. dev = Device.get_dev_by_logicalCode(logicalCode)
  4268. dealer = Dealer.objects(id = dev['ownerId']).get()
  4269. logger.info('checkPoint,user openId=%s,logicalCode=%s' % (request.user.openId, logicalCode))
  4270. # 检查经销商和代理商的开关
  4271. if dealer.moniAppCheckPointDict.has_key(point) and (not dealer.moniAppCheckPointDict[point]):
  4272. logger.info('checkPoint,moniappcheck point dealer is off,point')
  4273. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4274. agent = Agent.objects(id = dealer.agentId).get()
  4275. if agent.moniAppCheckPointDict.has_key(point) and (not agent.moniAppCheckPointDict[point]):
  4276. logger.info('checkPoint,moniappcheck point agent is off')
  4277. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4278. moniApp = agent.get_online_moni_app()
  4279. if not moniApp:
  4280. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4281. rcds = MoniUser.objects.filter(openId = request.user.openId, moniAppId = moniApp['appId'])
  4282. if rcds.count() == 0: # 一条记录都没有是,说明没有拿到对应数据
  4283. logger.info('checkPoint,can not find moniuser')
  4284. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4285. else:
  4286. moniUser = rcds.first()
  4287. if moniUser.isSubscribe:
  4288. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4289. else: # 如果没关注,可能存在用户通过其他手段提前关注了,要多重检查下
  4290. app = WechatAuthApp(appid = moniApp['appId'], secret = moniApp['secret'])
  4291. proxy = WechatClientProxy(app)
  4292. isSubGzh = proxy.is_subscribe_gzh(moniUser['moniOpenId'])
  4293. if isSubGzh:
  4294. moniUser.isSubscribe = True
  4295. moniUser.subPoint = point
  4296. moniUser.subLogicalCode = logicalCode
  4297. moniUser.subDealerId = str(dealer.id)
  4298. moniUser.subAgentId = str(agent.id)
  4299. moniUser.save()
  4300. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4301. else:
  4302. moniUser.subPoint = point
  4303. moniUser.subLogicalCode = logicalCode
  4304. moniUser.subDealerId = str(dealer.id)
  4305. moniUser.subAgentId = str(agent.id)
  4306. moniUser.save()
  4307. return JsonOkResponse(
  4308. payload = {'addFans': True, 'qrCode': moniApp['qrCode'], 'title': moniApp['title'],
  4309. 'desc': moniApp['desc']})
  4310. except Exception, e:
  4311. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4312. @permission_required(ROLE.myuser)
  4313. def isNeedAccessMoniApp(request):
  4314. logger.info('receive isNeedAccessMoniApp')
  4315. if (not detect_wechat_client(request)):
  4316. return JsonOkResponse(payload = {'isNeed': False})
  4317. try:
  4318. agent = Agent.objects(id = request.user.agentId).get()
  4319. # 如果代理商支持强制关注公众号,而且用户一天内才创建进来,为了体验好一点,这次就不要弹窗了
  4320. if agent.forceFollowGzh and (datetime.datetime.now() - request.user.dateTimeAdded).total_seconds() < 24 * 60 * 60:
  4321. return JsonOkResponse(payload = {'isNeed': False})
  4322. # 如果这个用户已经订阅了某个监督号,就直接返回
  4323. moniApp = agent.get_online_moni_app()
  4324. if not moniApp:
  4325. return JsonOkResponse(payload = {'isNeed': False})
  4326. moniUserCount = MoniUser.objects.filter(openId = request.user.openId, moniAppId = moniApp['appId']).count()
  4327. if moniUserCount == 0:
  4328. return JsonOkResponse(payload = {'isNeed': True})
  4329. return JsonOkResponse(payload = {'isNeed': False})
  4330. except Exception, e:
  4331. return JsonOkResponse(payload = {'isNeed': False})
  4332. @permission_required(ROLE.myuser)
  4333. def getComplaintList(request):
  4334. pageIndex = int(request.GET.get('pageIndex', 1))
  4335. pageSize = int(request.GET.get('pageSize', 10))
  4336. objs = Complaint.objects.filter(openId = request.user.openId)
  4337. dataList = []
  4338. total = objs.count()
  4339. for obj in objs.paginate(pageIndex = pageIndex, pageSize = pageSize):
  4340. dataList.append({
  4341. 'id': str(obj.id),
  4342. 'logicalCode': obj.logicalCode,
  4343. 'createdTime': obj.dateTimeAdded.strftime(Const.DATETIME_FMT),
  4344. 'handledTime': obj.handledTime.strftime(Const.DATETIME_FMT),
  4345. 'handledStatus': obj.handledStatus,
  4346. 'groupName': obj.groupName,
  4347. 'reason': obj.reason
  4348. })
  4349. return JsonOkResponse(payload = {'total': total, 'dataList': dataList})
  4350. def submitComplaint(request):
  4351. payload = json.loads(request.body)
  4352. # 首先产生一条投诉记录
  4353. logicalCode = payload.get('logicalCode')
  4354. orderNo = payload.get('orderNo')
  4355. reason = payload.get('reason')
  4356. order = ConsumeRecord.objects.get(orderNo = orderNo)
  4357. if order.logicalCode != logicalCode:
  4358. return JsonErrorResponse(description = u'设备的编码填写错误,请您检查下哦')
  4359. if Complaint.objects.filter(orderNo = orderNo).count() > 0:
  4360. return JsonErrorResponse(description = u'该订单已经投诉成功,不需要您重复投诉了哦')
  4361. newObj = Complaint(
  4362. openId = request.user.openId,
  4363. logicalCode = logicalCode,
  4364. groupName = order.groupName,
  4365. orderNo = orderNo,
  4366. reason = reason
  4367. )
  4368. newObj.save()
  4369. # 然后通知经销商
  4370. newMsg = DealerMessage(
  4371. ownerId = order.ownerId,
  4372. fromUser = u'系统平台',
  4373. messageType = 'complaint',
  4374. title = u'客户投诉',
  4375. desc = u'平台收到客户的投诉,请您尽快处理,如果收到投诉过多,系统会提醒设备用户,甚至禁用此设备。地址:%s,设备:%s,投诉原因:%s' % (
  4376. order.groupName, logicalCode, reason),
  4377. relatedInfo = {'complaintId': str(newObj.id)}
  4378. )
  4379. newMsg.save()
  4380. return JsonOkResponse()
  4381. @permission_required(ROLE.myuser)
  4382. @request_limit_by_user(operation='queryServicePhone', limit=10, period=2 * 60 * 60, logger=None)
  4383. def queryServicePhone(request):
  4384. """
  4385. 根据订单查询客服电话
  4386. :param request:
  4387. :return:
  4388. """
  4389. logicalCode = request.GET.get('logicalCode')
  4390. dealerIds = MyUser.get_dealer_ids(openId = request.user.openId, productAgentId = request.user.productAgentId)
  4391. device = Device.get_dev_by_logicalCode(logicalCode) # type: DeviceDict
  4392. if not device or device.ownerId not in dealerIds:
  4393. return JsonOkResponse(payload={})
  4394. if not device.owner:
  4395. logger.error('dealer<id={}> not exists.'.format(device.ownerId))
  4396. return JsonOkResponse(payload={})
  4397. return JsonOkResponse(payload=({'phone': device.owner.service_phone}))
  4398. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  4399. @permission_required(ROLE.myuser)
  4400. def getAllFeature(request):
  4401. agent = Agent.objects.get(id = request.user.agentId)
  4402. if agent is None:
  4403. return JsonErrorResponse(description = u'代理商不存在')
  4404. else:
  4405. return JsonOkResponse(payload = {_: True for _ in agent.features})
  4406. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  4407. @permission_required(ROLE.myuser)
  4408. def queryCardNo(request):
  4409. logicalCode = request.GET.get('logicalCode')
  4410. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  4411. if devNo is None:
  4412. return JsonErrorResponse(description = u'未识别的设备编号')
  4413. cardNo = Card.get_dev_card_no(devNo)
  4414. if cardNo is None:
  4415. return JsonOkResponse(payload = {'cardNo': ''})
  4416. return JsonOkResponse(payload = {'cardNo': cardNo})
  4417. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  4418. @permission_required(ROLE.myuser)
  4419. def prepareScanCard(request):
  4420. logicalCode = request.GET.get('logicalCode')
  4421. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  4422. if devNo is None:
  4423. return JsonErrorResponse(description = u'未识别的设备编号')
  4424. Card.clear_dev_card_no(devNo)
  4425. return JsonOkResponse()
  4426. @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger)
  4427. @permission_required(ROLE.myuser)
  4428. def checkUserConsumeOrder(request):
  4429. logicalCode = request.GET.get("logicalCode")
  4430. dev = Device.get_dev_by_logicalCode(logicalCode)
  4431. if not dev:
  4432. return JsonErrorResponse(u"未找到设备,请扫码重试")
  4433. box = ActionDeviceBuilder.create_action_device(dev)
  4434. if not hasattr(box, "check_user_consume_order"):
  4435. return JsonOkResponse()
  4436. status = box.check_user_consume_order()
  4437. return JsonResponse({"result": status})
  4438. @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger)
  4439. @permission_required(ROLE.myuser)
  4440. def preJudgment(request):
  4441. """
  4442. 这个接口 无论如何不能抛出异常 前台规定
  4443. :param request:
  4444. :return:
  4445. """
  4446. logicalCode = request.GET.get("logicalCode")
  4447. dev = Device.get_dev_by_logicalCode(logicalCode)
  4448. if not dev:
  4449. return JsonErrorResponse(u"该设备不存在")
  4450. order = get_user_not_complete_order(request.user, dev.owner)
  4451. # 正常结果下的返回
  4452. if not order:
  4453. return JsonOkResponse()
  4454. if order.status == order.Status.RUNNING:
  4455. return JsonResponse({"result": ErrorCode.ORDER_RUNNING, "description": u"您有一笔正在进行的订单",
  4456. "payload": {'ownerId': order.ownerId, "orderId": str(order.id)}})
  4457. elif not order.isPaid:
  4458. return JsonResponse({"result": ErrorCode.ORDER_NEED_PAY, "description": u"你有一笔尚未支付的订单,请先完成支付,然后在使用设备",
  4459. "payload": {'ownerId': order.ownerId, "orderId": str(order.id)}})
  4460. # elif order.is_waitPay():
  4461. # return JsonResponse({"result": ErrorCode.ORDER_PAYING, "description": u"正在检查支付结果,请稍后",
  4462. # "payload": {'ownerId': order.ownerId, "orderId": str(order.id)}})
  4463. else:
  4464. return JsonResponse({"result": "2", "description": u"系统错误,请您稍后重试"})
  4465. @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger)
  4466. @permission_required(ROLE.myuser)
  4467. def getCardBindUserStatus(request):
  4468. user = request.user
  4469. status = 1 if user.extra.get('campus_user_num', '') else 0
  4470. return JsonResponse({"result": 1, "description": "", "payload": {"status": status}})
  4471. @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger)
  4472. @permission_required(ROLE.myuser)
  4473. def updateCardBindUserInfo(request):
  4474. user = request.user
  4475. jsonData = json.loads(request.body)
  4476. phoneNumber = str(jsonData.get("phoneNumber", "").strip())
  4477. code = jsonData.get("code", "")
  4478. campus_user_num = str(jsonData.get('userNo').strip())
  4479. userName = str(jsonData.get('userName').strip())
  4480. from apps.web.eventer.caiyi import config_dic
  4481. # 测试白名单
  4482. test_card = serviceCache.get('yc-num-{}'.format(campus_user_num))
  4483. if test_card:
  4484. userName = 'test'
  4485. campus_user_num = 'test001'
  4486. logger.debug('yc_test_card,to reg card!!!')
  4487. res = {'factoryFixId': '757996699'}
  4488. else:
  4489. # TODO 去服务器验证人员编号和手机号是否吻合
  4490. yc = YuChuanApi(**config_dic)
  4491. try:
  4492. res = yc.sql_get_user_info(campus_user_num)
  4493. user_phone = base64.encodestring(phoneNumber + '.00').strip()
  4494. if res['mobilePhone'] != user_phone or res['userName'] != userName:
  4495. return JsonErrorResponse(description = u'一卡通信息填写错误~,请您检查下哦')
  4496. except Exception as e:
  4497. return JsonErrorResponse(description = u'一卡通信息填写错误!!!,请您检查下哦')
  4498. card_no = str(res.get('factoryFixId')).replace('L', '')
  4499. if not card_no:
  4500. raise UserServerException(u'一卡通信息填写错误!!')
  4501. status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code)
  4502. if not status:
  4503. return JsonErrorResponse(msg)
  4504. dic = {
  4505. "card_dealer": "宇川智能平台一卡通",
  4506. "campus_user_num": campus_user_num,
  4507. }
  4508. card = Card.objects.filter(cardNo = card_no, cardType = 'YuChuanCard').first() or Card.objects.create(
  4509. cardNo = card_no, agentId = user.agentId, phone = phoneNumber, remarks = '宇川一卡通',
  4510. productAgentId = user.productAgentId, cardName = userName, attachParas = dic, cardType = 'YuChuanCard',
  4511. nickName = user.nickname, openId = user.openId)
  4512. if card.openId == card_no or card.openId != user.openId: # 判断是否为刷卡注册入库,或则换微信绑定
  4513. card.openId = user.openId
  4514. card.nickName = user.nickname
  4515. card.phone = phoneNumber
  4516. card.save()
  4517. dic['card_no'] = card_no
  4518. user.phoneNumber = phoneNumber
  4519. user.extra = dic
  4520. user.save()
  4521. return JsonResponse({"result": 1, "description": "", "payload": {"status": 1}})
  4522. @error_tolerate(logger = logger, nil = JsonErrorResponse(description = u"获取卡金额失败"))
  4523. @permission_required(ROLE.myuser)
  4524. def getRemoteCardBalance(request):
  4525. """
  4526. 获取远程充值卡的金额
  4527. :param request:
  4528. :return:
  4529. """
  4530. logicalCode = request.GET.get("logicalCode")
  4531. dev = Device.get_dev_by_l(logicalCode)
  4532. if not dev:
  4533. return JsonErrorResponse(description = u"请先扫描设备")
  4534. box = ActionDeviceBuilder.create_action_device(dev)
  4535. if not hasattr(box, "get_remote_card_balance"):
  4536. return JsonErrorResponse(description = u"当前设备暂不支持充值卡")
  4537. try:
  4538. result = box.get_remote_card_balance()
  4539. except ServiceException as e:
  4540. return JsonErrorResponse(description = e.message.get("description"))
  4541. res = result.get("res")
  4542. if res == "02":
  4543. return JsonErrorResponse(description = u"请先将卡片置于设备上")
  4544. # 这个地方将用户的信息塞入进去
  4545. user = request.user
  4546. result.update({
  4547. "avatarUrl": user.avatar,
  4548. "openId": user.openId
  4549. })
  4550. # 然后再次塞入设备信息
  4551. result.update({
  4552. "devNo": dev.devNo,
  4553. "groupId": dev.groupId
  4554. })
  4555. packages = dev.get("washConfig", dict())
  4556. newPackages = list()
  4557. for _id, item in packages.items():
  4558. switch = item.get("switch", True)
  4559. if not switch:
  4560. continue
  4561. newPackages.append({
  4562. "id": _id,
  4563. "payAmount": item.get("price"),
  4564. "coins": item.get("coins")
  4565. })
  4566. result.update({"packages": newPackages})
  4567. return JsonOkResponse(payload = result)
  4568. @error_tolerate(logger = logger, nil = JsonOkResponse())
  4569. @permission_required(ROLE.myuser)
  4570. def getUserDisclaimer(request):
  4571. """
  4572. 获取用户的免责声明
  4573. 用户 用户进入系统第一次的时候需要阅读此协议并且 明确表示阅读 否则展示界面给用户
  4574. :param request:
  4575. :return:
  4576. """
  4577. productAgentId = request.user.productAgentId
  4578. disclaimer = Agent.get_disclaimer(productAgentId)
  4579. # 当用户阅读的声明版本与当前免责代理商的版本不一致 并且代理商的免责声明内容不为空的时候 前台需要展示免责声明
  4580. payload = {
  4581. "version": disclaimer.version,
  4582. "content": disclaimer.content
  4583. }
  4584. if not disclaimer.content:
  4585. payload = {}
  4586. return JsonOkResponse(payload = payload)
  4587. @error_tolerate(logger = logger, nil = JsonOkResponse())
  4588. @permission_required(ROLE.myuser)
  4589. def pauseUsingDevice(request):
  4590. payload = json.loads(request.body)
  4591. logicalCode = payload.get('logicalCode', '')
  4592. if logicalCode == '':
  4593. return JsonErrorResponse(description = u'参数错误(没有逻辑码)')
  4594. port = payload.get('chargeIndex', '')
  4595. if port == '':
  4596. return JsonErrorResponse(description = u'参数错误(没有端口号)')
  4597. dev = Device.get_dev_by_l(logicalCode)
  4598. portCache = Device.get_dev_control_cache(dev['devNo'])[str(port)]
  4599. if dev['devType']['code'] in ['1002121', '1002122']:
  4600. if portCache.get('pausePort', False) is True:
  4601. oper = '01'
  4602. else:
  4603. oper = '02'
  4604. else:
  4605. oper = '00'
  4606. smartBox = ActionDeviceBuilder.create_action_device(dev)
  4607. try:
  4608. smartBox.pauseToUseDevice(port, oper)
  4609. except Exception as e:
  4610. return JsonErrorResponse(description = u'操作失败')
  4611. return JsonOkResponse()
  4612. @error_tolerate(logger = logger, nil = ErrorResponseRedirect(error = u'微信授权失败,请刷新后重试'))
  4613. @permission_required(ROLE.myuser)
  4614. def gatewayEntry(request):
  4615. """
  4616. 再发起支付之前 获取一次用户的 payOpenId 然后重定向到用户的支付详情页面 并直接访问payGateway
  4617. :param request:
  4618. :return:
  4619. """
  4620. def get_pay_gateway_redirect(pp, adLink):
  4621. redirect = pp._request.GET.get("redirect")
  4622. info = {
  4623. 'params': pp._request.GET.get("params"),
  4624. 'goodsInfo': json.dumps(pp.goodsInfo)
  4625. }
  4626. if adLink:
  4627. info.update({'adLink': adLink})
  4628. url = before_frag_add_query(redirect, info)
  4629. logger.debug('redirect to client url is: {}'.format(url))
  4630. return FrontEndResponseRedirect(url)
  4631. def get_auth_redirect(pp, bridge, adLink):
  4632. authCode = pp._request.GET.get(bridge.auth_code_key)
  4633. if not authCode:
  4634. redirect_uri = concat_server_end_url(
  4635. uri = add_query('/user/pay/gatewayEntry', {
  4636. 'params': pp._request.GET.get("params"),
  4637. 'redirect': pp._request.GET.get("redirect")
  4638. })
  4639. )
  4640. logger.debug('base scope auth url is:{}'.format(redirect_uri))
  4641. return ExternalResponseRedirect(
  4642. bridge.generate_auth_url_base_scope(
  4643. redirect_uri = redirect_uri,
  4644. payload = {}
  4645. )
  4646. )
  4647. else:
  4648. userPayOpenId = bridge.authorize(authCode)
  4649. if not userPayOpenId:
  4650. return ErrorResponseRedirect(error = u'微信授权失败,请刷新后重试')
  4651. else:
  4652. pp.curUser.set_bound_pay_openid(bridge.bound_openid_key, openId = userPayOpenId)
  4653. pp.curUser.save()
  4654. return get_pay_gateway_redirect(pp, adLink)
  4655. def RCU_process(payParam):
  4656. code = request.GET.get('code')
  4657. if not code:
  4658. redirect = payParam._request.GET.get("redirect")
  4659. redirect_uri = concat_server_end_url(
  4660. uri = add_query('/user/pay/gatewayEntry', {
  4661. 'params': payParam._request.GET.get("params"),
  4662. 'redirect': redirect
  4663. })
  4664. )
  4665. url = add_query(pay_gateway.app.authCodeUrl, {'authCallBackUrl': redirect_uri})
  4666. logger.debug('base scope auth url is:{}'.format(redirect_uri))
  4667. return FrontEndResponseRedirect(url)
  4668. else:
  4669. redirect = payParam._request.GET.get("redirect")
  4670. info = {
  4671. 'params': payParam._request.GET.get("params"),
  4672. 'code': code,
  4673. 'goodsInfo': json.dumps(payParam.goodsInfo),
  4674. }
  4675. if adLink:
  4676. info.update({'adLink': adLink})
  4677. url = before_frag_add_query(redirect, info)
  4678. logger.debug('redirect to client url is: {}'.format(url))
  4679. return FrontEndResponseRedirect(url)
  4680. payParam = PayParam(request)
  4681. curUser = payParam.curUser
  4682. pay_gateway = payParam.payGateway
  4683. adLink = request.GET.get('adLink', None)
  4684. # 首先判断登录的平台 只有微信扫码的需要获取其支付的openId
  4685. if detect_wechat_client(request):
  4686. if pay_gateway.pay_app_type == PayAppType.WECHAT:
  4687. authBridge = WechatAuthBridge(pay_gateway.app)
  4688. payOpenId = curUser.get_bound_pay_openid(authBridge.bound_openid_key)
  4689. if payOpenId:
  4690. return get_pay_gateway_redirect(payParam, adLink)
  4691. else:
  4692. return get_auth_redirect(payParam, authBridge, adLink)
  4693. else:
  4694. return JsonErrorResponse(description = u"平台配置错误,请稍后再试")
  4695. # 支付宝平台登录
  4696. elif detect_alipay_client(request):
  4697. return get_pay_gateway_redirect(payParam, adLink)
  4698. # 其他平台暂时不支持
  4699. else:
  4700. return NotSupportedPlatformResponseRedirect()
  4701. @error_tolerate(logger = logger, nil = JsonErrorResponse(u"套餐获取失败"))
  4702. @permission_required(ROLE.myuser)
  4703. def getMonthlyPackage(request):
  4704. """
  4705. 获取包月的套餐
  4706. :param request:
  4707. :return:
  4708. """
  4709. devNo = Device.get_dev_no_from_request(request)
  4710. cardNo = request.GET.get("cardNo")
  4711. device = Device.get_dev(devNo)
  4712. card = Card.objects.filter(cardNo = cardNo, openId = request.user.openId,
  4713. productAgentId = request.user.productAgentId).first()
  4714. if device:
  4715. group = Group.get_dealer_group(dealerId = device.ownerId, id = device.groupId)
  4716. elif card:
  4717. group = Group.get_dealer_group(dealerId = card.dealerId, id = card.groupId)
  4718. else:
  4719. return JsonErrorResponse(description = u"获取套餐失败(1000),请刷新重试")
  4720. if not group:
  4721. return JsonErrorResponse(description = u"套餐获取失败(1001),请刷新重试")
  4722. monthPackage = group.monthlyRule
  4723. if not monthPackage:
  4724. return JsonOkResponse()
  4725. return JsonOkResponse(payload = {"dataList": [monthPackage.to_dict()]})
  4726. @error_tolerate(nil = JsonErrorResponse(u"续费失败,请重新尝试"), logger = logger)
  4727. @permission_required(ROLE.myuser)
  4728. def checkVirtualCardRenew(request):
  4729. """
  4730. 检查当前的虚拟卡是否可以续费
  4731. :param request:
  4732. :return:
  4733. """
  4734. cardId = request.GET.get("cardId")
  4735. if not cardId:
  4736. return JsonErrorResponse(description = u"未找到相应虚拟卡,请重试")
  4737. vCard = UserVirtualCard.objects.get(id = cardId)
  4738. if not Group.check_virtual_card_number(groupId = vCard.groupId):
  4739. return JsonErrorResponse(description = u"该地址虚拟卡数量已经达到上限,请联系发卡经销商")
  4740. return JsonOkResponse()
  4741. @error_tolerate(nil = JsonErrorResponse(u"获取失败,请重试"), logger = logger)
  4742. @permission_required(ROLE.myuser)
  4743. def getUserMonthlyPackage(request):
  4744. """
  4745. 获取用户的 包月套餐
  4746. :param request:
  4747. :return:
  4748. """
  4749. openId = request.user.openId
  4750. monthlyPackages = MonthlyPackage.get_user_all(openId)
  4751. dataList = [_package.to_dict() for _package in monthlyPackages]
  4752. return JsonOkResponse(payload = {"dataList": dataList})
  4753. @error_tolerate(nil = JsonErrorResponse(u"获取失败,请重试"), logger = logger)
  4754. @permission_required(ROLE.myuser)
  4755. def getMonthlyPackageUseDetail(request):
  4756. """
  4757. 获取 用户的使用详情
  4758. :param request:
  4759. :return:
  4760. """
  4761. monthlyPackageId = request.GET.get("monthlyPackageId")
  4762. pageIndex = int(request.GET.get("pageIndex", 1))
  4763. pageSize = int(request.GET.get("pageSize", 10))
  4764. monthlyPackage = MonthlyPackage.objects.get(id = monthlyPackageId)
  4765. useDetail = monthlyPackage.get_used_detail()
  4766. # 获取使用的总的数量 添加上订单的ID 方便前台跳转
  4767. total = len(useDetail)
  4768. result = useDetail[pageSize * (pageIndex - 1): pageSize * pageIndex]
  4769. orderNos = [_item.get("orderNo") for _item in result]
  4770. consumeRecords = ConsumeRecord.objects.filter(openId = request.user.openId, orderNo__in = orderNos).only("openId",
  4771. "orderNo",
  4772. "id",
  4773. "dateTimeAdded")
  4774. dataList = [
  4775. {"id": consume.id, "orderNo": consume.orderNo, "orderTime": consume.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")}
  4776. for consume in consumeRecords
  4777. ]
  4778. return JsonOkResponse(payload = {"total": total, "dataList": dataList})
  4779. @error_tolerate(nil = JsonErrorResponse(u"获取失败,请重试"), logger = logger)
  4780. @permission_required(ROLE.myuser)
  4781. def supportPayment(request):
  4782. def get_dealer(request):
  4783. logicalCode = request.GET.get('logicalCode', None)
  4784. if logicalCode:
  4785. device = Device.get_dev_by_logicalCode(logicalCode)
  4786. if not device:
  4787. logger.info('can not find device. logicalCode={}'.format(logicalCode))
  4788. return None
  4789. else:
  4790. return device.owner
  4791. else:
  4792. groupId = request.GET.get('groupId', None)
  4793. if not groupId:
  4794. logger.info('can not find group. groupId={}'.format(groupId))
  4795. return None
  4796. else:
  4797. group = Group.get_group(groupId) # type: GroupDict
  4798. if not group:
  4799. logger.info('can not find group. groupId={}'.format(groupId))
  4800. return None
  4801. else:
  4802. return group.owner
  4803. dealer = get_dealer(request)
  4804. if dealer is None:
  4805. return JsonErrorResponse(description = u'该设备未注册,暂时无法使用支付宝或者微信支付, 请投币(1013)')
  4806. return JsonOkResponse(description = u'无商户配置')
  4807. @permission_required(ROLE.myuser)
  4808. def getAlipayAd(request):
  4809. """
  4810. 领取红包福利任务
  4811. :param request:
  4812. :return:
  4813. """
  4814. try:
  4815. user = request.user # type: MyUser
  4816. logicalCode = request.GET.get('logicalCode', '')
  4817. pageIndex = int(request.GET.get('pageIndex', 0))
  4818. pageSize = int(request.GET.get('pageSize', 10))
  4819. chargeIndex = request.GET.get('chargeIndex', '')
  4820. dev = Device.get_dev_by_l(logicalCode) # Type:DeviceDict
  4821. from apps.web.core.models import SystemSettings
  4822. if user.gateway != AppPlatformType.ALIPAY:
  4823. return JsonOkResponse(payload = {})
  4824. if not dev:
  4825. return JsonOkResponse(payload = {})
  4826. if not Redpack.can_use(dealer = dev.owner, devTypeCode = dev.devTypeCode):
  4827. return JsonOkResponse(payload = {})
  4828. if not DevRegToAli.objects.filter(logicalCode = logicalCode).first():
  4829. reg_result = DevRegToAli.reg_to_aliyun_v3(dev)
  4830. if not reg_result:
  4831. return JsonOkResponse()
  4832. if 'disable_alipay_ruhui' in dev.owner.features:
  4833. ruhui = {}
  4834. elif SystemSettings.disable_alipay_ruhui():
  4835. ruhui = {}
  4836. else:
  4837. # 判断是否为蓝牙. 蓝牙为老流程 串口充电桩为新流程
  4838. if dev.channelType == DeviceChannelType.Channel_BT:
  4839. showType = 'pop'
  4840. else:
  4841. # 1 确认显示方式
  4842. showType = 'footerTopRedpack'
  4843. group = dev.group
  4844. if group.get('beforeCharge'):
  4845. showType = 'pop'
  4846. if 'show_pop_ruhui' in dev.owner.features:
  4847. showType = 'pop'
  4848. elif 'show_top_ruhui' in dev.owner.features:
  4849. showType = 'top'
  4850. elif 'show_buttun_ruhui' in dev.owner.features:
  4851. showType = 'buttun'
  4852. # 2 请求 请求权益 创建红报
  4853. ruhui = RedpackBuilder.get_alipay_cpa_by_ruhui_v3(openId = user.openId, logicalCode = logicalCode,
  4854. chargeIndex = chargeIndex, showType = showType)
  4855. if ruhui:
  4856. # 地址组启动强制充值, 后面的页面需要弹窗 比较复杂直接改为弹窗流程
  4857. group = dev.group
  4858. if group.get('beforeCharge'):
  4859. ruhui = {'url': ruhui['url'], 'money': ruhui['money'], 'showType': ruhui['showType'],
  4860. 'urlId': ruhui['urlId']}
  4861. else:
  4862. pass
  4863. if 'disable_alipay_laxin' in dev.owner.features:
  4864. laxin = {}
  4865. elif SystemSettings.disable_alipay_laxin():
  4866. laxin = {}
  4867. else:
  4868. # 拉新
  4869. dataList = RedpackBuilder.get_alipay_cpa_by_laxin(openId = user.openId)
  4870. total = len(dataList)
  4871. if dataList:
  4872. dataList = dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  4873. laxin = {'dataList': dataList, 'total': total}
  4874. return JsonOkResponse(payload = {'laxin': laxin, 'ruhui': ruhui})
  4875. except Exception as e:
  4876. logger.exception(e)
  4877. return JsonOkResponse()
  4878. @error_tolerate(u"获取权益失败", logger=logger)
  4879. @permission_required(ROLE.myuser)
  4880. def getAlipayAdResult(request):
  4881. """
  4882. 领取红包福利任务
  4883. :param request:
  4884. :return:
  4885. """
  4886. alipayOpenId = request.GET.get('alipayOpenId')
  4887. taskId = request.GET.get('taskId')
  4888. taskType = request.GET.get('taskType')
  4889. openId = request.GET.get('alipayOpenId')
  4890. logicalCode = request.GET.get('logicalCode')
  4891. dev = Device.get_dev_by_logicalCode(logicalCode)
  4892. # 拉新结果处理
  4893. if taskId and alipayOpenId:
  4894. if RedpackBuilder.query_cpa_laxin_task_status(taskId, alipayOpenId):
  4895. redpack = RedpackBuilder.create_cpa_laxin_redpack(dev, taskId, openId, taskType)
  4896. if redpack:
  4897. return JsonOkResponse(payload={'showAmount': redpack.money.mongo_amount})
  4898. # 入会结果处理
  4899. redpackInfo = RedpackBuilder._pop_alipay_key(request.user.openId)
  4900. if redpackInfo:
  4901. showType = redpackInfo.get('showType')
  4902. if showType == 'pop':
  4903. return JsonOkResponse(payload={'showAmount': redpackInfo.get('money')})
  4904. return JsonResponse({'payload': {}})
  4905. @error_tolerate(u"获取权益失败", logger=logger)
  4906. @permission_required(ROLE.myuser)
  4907. def getMyRedpackList(request):
  4908. user = request.user # type: MyUser
  4909. pageIndex = int(request.GET.get('pageIndex', 0))
  4910. pageSize = int(request.GET.get('pageSize', 10))
  4911. dataList = Redpack.show_redpack(openId=user.openId)
  4912. total = len(dataList)
  4913. dataList = dataList[(pageIndex-1) * pageSize: pageIndex * pageSize]
  4914. return JsonOkResponse(payload={'dataList':dataList, 'total':total})
  4915. @error_tolerate(nil = JsonErrorResponse(description = u'显示用户信息错误'), logger = logger)
  4916. @permission_required(ROLE.myuser)
  4917. def getCurrentFeePara(request):
  4918. devNo = request.GET.get('devNo', None)
  4919. devObj = Device.objects.get(devNo = devNo)
  4920. feeMode = devObj.otherConf.get('feeMode',{})
  4921. timeRateList = []
  4922. shiduan = feeMode.get('shiduan','000000000000000000000000000000000000000000000000')
  4923. nowTime = datetime.datetime.now().strftime('%H:%M')
  4924. curFeeIndex = 0
  4925. for ii in range(48):
  4926. startHour = 0 + ii/2
  4927. startMin = '00' if ii%2==0 else '30'
  4928. endHour = startHour if ii%2==0 else startHour + 1
  4929. endMin = '30' if ii%2==0 else '00'
  4930. startTime = '%02d:%s' % (startHour,startMin)
  4931. endTime = '%02d:%s' % (endHour,endMin)
  4932. timeRateList.append({'startTime':startTime,'endTime':endTime,'rate':shiduan[ii]})
  4933. if nowTime >= startTime and nowTime <= endTime:
  4934. curFeeIndex = shiduan[ii]
  4935. result = {'top_price_rate':feeMode.get('jianFee',0),
  4936. 'top_price_service_rate':feeMode.get('jianServe',0),
  4937. 'peak_price_rate':feeMode.get('fengFee',0),
  4938. 'peak_price_service_rate':feeMode.get('fengServe',0),
  4939. 'normal_price_rate':feeMode.get('pingFee',0),
  4940. 'normal_price_service_rate':feeMode.get('pingServe',0),
  4941. 'valley_price_rate':feeMode.get('guFee',0),
  4942. 'valley_price_service_rate':feeMode.get('guServe',0),
  4943. 'jishunScale':feeMode.get('jishunScale',0),
  4944. 'timeRateList':timeRateList,
  4945. 'curFeeIndex':curFeeIndex}
  4946. return JsonOkResponse( payload = result )
  4947. @permission_required(ROLE.myuser)
  4948. def getNearbyCarStation(request):
  4949. # type: (WSGIRequest)->JsonResponse
  4950. try:
  4951. lng = float(request.GET.get('lng'))
  4952. lat = float(request.GET.get('lat'))
  4953. pageIndex = int(request.GET.get('pageIndex',1))
  4954. pageSize = int(request.GET.get('pageSize',10))
  4955. maxDistance = int(request.GET.get('distance', 5000))
  4956. logger.debug('now location. lat = %s; lng = %s' % (lat, lng))
  4957. if maxDistance > Const.NEAR_BY_MAX_DISTANCE:
  4958. maxDistance = Const.NEAR_BY_MAX_DISTANCE
  4959. if lng == 360 or lat == 360 or isnan(lng) or isnan(lat):
  4960. return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'})
  4961. payload = getNearbyGroupsFromDB(lng, lat, pageIndex, pageSize, maxDistance, request.user.agentId,
  4962. request.GET.get('chargeType', 0))
  4963. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  4964. except Exception as e:
  4965. logger.exception(e)
  4966. return JsonResponse({'result': 0, 'description': u'获取附近设备失败'})
  4967. def getNearbyGroupsFromDB(lng, lat, pageIndex, pageSize, maxDistance, agentId, chargeType):
  4968. def hav(theta):
  4969. s = sin(theta / 2)
  4970. return s * s
  4971. def get_distance_hav(lat0, lng0, lat1, lng1):
  4972. if lat1 == 360 or lng1 == 360:
  4973. return -1
  4974. EARTH_RADIUS = 6371000
  4975. lat0 = radians(lat0)
  4976. lat1 = radians(lat1)
  4977. lng0 = radians(lng0)
  4978. lng1 = radians(lng1)
  4979. dlng = fabs(lng0 - lng1)
  4980. dlat = fabs(lat0 - lat1)
  4981. h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlng)
  4982. return int(2 * EARTH_RADIUS * asin(sqrt(h)))
  4983. if not agentId:
  4984. logger.error('agent is null.')
  4985. return {
  4986. 'total': 0,
  4987. 'items': []
  4988. }
  4989. dealers = Dealer.get_dealers(agentId)
  4990. if not dealers:
  4991. return {
  4992. 'total': 0,
  4993. 'items': []
  4994. }
  4995. queryDict = {
  4996. 'ownerId': {'$in': dealers},
  4997. 'StationStatus':50,# 站点状态必须是正常使用中的
  4998. 'location': {
  4999. '$near': {'$geometry': {'type': 'Point', 'coordinates': [lng, lat]},
  5000. '$maxDistance': maxDistance}}}
  5001. if chargeType != '0':
  5002. queryDict.update({'chargeType':int(chargeType)})
  5003. groups = SwapGroup.get_collection().find(queryDict)
  5004. items = []
  5005. for swapInfo in groups[(pageIndex - 1) * pageSize:pageIndex * pageSize]:
  5006. groupId = swapInfo['groupId']
  5007. group = Group.get_group(groupId)
  5008. if group is None:
  5009. continue
  5010. swaplng = float(swapInfo['location']['coordinates'][0])
  5011. swaplat = float(swapInfo['location']['coordinates'][1])
  5012. distance = get_distance_hav(lat, lng, swaplat, swaplng)
  5013. curFee = SwapGroup.get_cur_fee(swapInfo['PriceChargingInfo'])
  5014. if curFee is None:
  5015. continue
  5016. # 统计交流、直流端口的情况
  5017. statsDict = SwapGroup.get_stats(groupId)
  5018. info = {
  5019. 'lng': swaplng,
  5020. 'lat': swaplat,
  5021. 'Pictures':[{'IsCover':pic['IsCover'],'PicID':pic['PicID'],'Url':pic['Url'],'Title':pic['Title']} for pic in swapInfo.get('Pictures',[])],
  5022. 'PriceChargingInfo':[{'FeeTime':info['FeeTime'],'ElectricityFee':info['ElectricityFee'],'ServiceFee':info['ServiceFee']} for info in swapInfo['PriceChargingInfo']],
  5023. 'StationName':group['groupName'] if u'充电站' in group['groupName'] else u'%s充电站' % group['groupName'],
  5024. 'Address':group['address'],
  5025. 'Distance':distance,
  5026. 'BusineHours':swapInfo['BusineHours'],
  5027. 'acPortsSum':{'allPorts':statsDict['acAllPorts'],'usedPorts':statsDict['acUsedPorts'],'usePorts':statsDict['acUsePorts']},
  5028. 'dcPortsSum':{'allPorts':statsDict['dcAllPorts'],'usedPorts':statsDict['dcUsedPorts'],'usePorts':statsDict['dcUsePorts']},
  5029. 'exceptSum':{'offline':statsDict['offline'],'fault':statsDict['fault']},
  5030. 'curFee':{"curElecFee": curFee['curElecFee'], "curServiceFee": curFee['curServiceFee']},
  5031. 'ParkFee':swapInfo['ParkFee'],
  5032. 'tagDescList':SwapGroup.get_tag_desc_list_for_dict(swapInfo)
  5033. }
  5034. items.append(info)
  5035. payload = {
  5036. 'total': groups.count(),
  5037. 'items': items
  5038. }
  5039. return payload
  5040. @error_tolerate(logger = logger)
  5041. def refundOrderNotifier(request, pay_app_type):
  5042. """
  5043. 退款回调接口.
  5044. 微信和京东聚合单独指定回调
  5045. 支付宝支付和退款回调是一个
  5046. :param request:
  5047. :param pay_app_type:
  5048. :return:
  5049. """
  5050. assert pay_app_type in PayAppType.choices(), 'not support this pay app type({})'.format(pay_app_type)
  5051. notifier_cls = RefundManager().get_notifier(pay_app_type)
  5052. response = notifier_cls(request, lambda order_no: RefundMoneyRecord.get_record(order_no)).do(refund_post_pay)
  5053. return response
  5054. @error_tolerate(logger=logger)
  5055. @permission_required(ROLE.myuser)
  5056. def cancelWaitPay(request):
  5057. """
  5058. 后支付用户拉起支付后, 没有输入密码 点击恢复到end状态 用于再次支付
  5059. """
  5060. payload = json.loads(request.body)
  5061. ownerId = payload.get('ownerId')
  5062. consumeRecordId = payload.get('consumeRecordId')
  5063. if not ownerId or not consumeRecordId:
  5064. return JsonErrorResponse(description='参数缺失, 请刷新后重试..')
  5065. order = ConsumeRecord.objects.filter(
  5066. id=consumeRecordId,
  5067. ownerId=ownerId
  5068. ).first() # type: ConsumeRecord
  5069. if not order:
  5070. return JsonErrorResponse(description='没有找到该订单')
  5071. try:
  5072. if order.status == order.Status.WAIT_PAY and not order.isPaid:
  5073. order.status = order.Status.END
  5074. order.save()
  5075. except Exception as e:
  5076. logger.exception("[cancelWaitPay] error = {}".format(e))
  5077. return JsonErrorResponse(description='参数错误')
  5078. return JsonOkResponse(payload={})
  5079. @permission_required(ROLE.myuser)
  5080. def cancelRechargeRecord(request):
  5081. """
  5082. 用户取消订单
  5083. """
  5084. try:
  5085. payload = json.loads(request.body)
  5086. orderNo = payload.get('orderNo')
  5087. record = RechargeRecord.objects(orderNo = orderNo).first() # type: RechargeRecord
  5088. if not record:
  5089. logger.warning('has no recharge record<orderNo={}>'.format(orderNo))
  5090. else:
  5091. record.cancel()
  5092. except Exception as e:
  5093. logger.exception(e)
  5094. finally:
  5095. return JsonOkResponse()