views.py 250 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658
  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 asynTransactionRecordForChangyuan(request):
  1258. # type: (WSGIRequest)->JsonResponse
  1259. """
  1260. 用户消费记录
  1261. :param request:
  1262. :return: JsonResponse
  1263. """
  1264. pageIndex = int(request.GET.get('pageIndex', 1))
  1265. pageSize = int(request.GET.get('pageSize', 10))
  1266. startTime = request.GET.get('startTime', Const.QUERY_START_DATE)
  1267. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  1268. typeStrDict = {
  1269. 'wechat': u'微信支付',
  1270. 'alipay': u'支付宝支付',
  1271. }
  1272. if request.GET.has_key('cardTicketId') and request.GET.get('cardTicketId'):
  1273. _, dataList = VCardConsumeRecord.paginate(request.GET.get('cardTicketId'), pageIndex, pageSize)
  1274. else:
  1275. dealer_ids = MyUser.get_dealer_ids(openId = request.user.openId, productAgentId = request.user.productAgentId)
  1276. if len(dealer_ids) < 0:
  1277. return JsonResponse({'result': 1, 'description': '', 'payload': {'total': 0, 'dataList': []}})
  1278. query_set = ClientConsumeModelProxy.get_data_list(
  1279. ownerId__in = dealer_ids,
  1280. startTime = startTime,
  1281. endTime = endTime,
  1282. openId = request.user.openId,
  1283. isNormal = True,
  1284. ) # type: CustomQuerySet
  1285. rechargeIds = []
  1286. records = []
  1287. for _ in query_set.paginate(pageIndex, pageSize): # type: ConsumeRecord
  1288. records.append(_)
  1289. if _.recharge_record_id:
  1290. rechargeIds.append(ObjectId(_.recharge_record_id))
  1291. if not records:
  1292. return JsonResponse({'result': 1, 'description': '', 'payload': {'total': 0, 'dataList': []}})
  1293. if rechargeIds:
  1294. recharge_records = ClientRechargeModelProxy.get_data_list(
  1295. ownerId__in = dealer_ids,
  1296. id__in = rechargeIds
  1297. )
  1298. else:
  1299. recharge_records = list()
  1300. rechargeDict = {}
  1301. for _ in recharge_records: # type: RechargeRecord
  1302. rechargeDict[str(_.id)] = _
  1303. dataList = []
  1304. for record in records: # type: ConsumeRecord
  1305. if not record.recharge_record_id:
  1306. continue
  1307. rechargeRcd = rechargeDict.get(str(record.recharge_record_id), None)
  1308. if rechargeRcd is None and record.remarks != u'刷卡消费': # 如果没有记录充值ID,是属于刷卡数据记录
  1309. continue
  1310. newData = record.to_user_detail()
  1311. if rechargeRcd.gateway in typeStrDict.keys():
  1312. typeStr = typeStrDict.get(rechargeRcd.gateway)
  1313. else:
  1314. typeStr = u'刷卡支付'
  1315. newData.update({'payType': typeStr})
  1316. newData.pop('elec', None)
  1317. newData.pop('needElec', None)
  1318. dataList.append(newData)
  1319. # 充值记录添加 昌源的充值记录分为卡充值(单纯充值没有消费)和消费充值(使用现金支付,立即有消费记录)
  1320. refundIds = {str(refund.rechargeObjId): str(refund.money) for refund in
  1321. RefundMoneyRecord.objects.filter(openId = request.user.openId)}
  1322. query_set = ClientRechargeModelProxy.get_data_list(
  1323. ownerId__in = dealer_ids,
  1324. startTime = startTime,
  1325. endTime = endTime,
  1326. openId = request.user.openId,
  1327. result = "success",
  1328. via = "chargeCard",
  1329. hint = [('openId', 1)])
  1330. for cardRechargeRecord in query_set.paginate(pageIndex, pageSize):
  1331. if cardRechargeRecord.gateway in typeStrDict.keys():
  1332. typeStr = typeStrDict.get(cardRechargeRecord.gateway)
  1333. else:
  1334. continue
  1335. newData = {
  1336. "id": str(cardRechargeRecord.id),
  1337. "payType": typeStr,
  1338. "createdTime": cardRechargeRecord.dateTimeAdded,
  1339. "address": cardRechargeRecord.address,
  1340. "devNo": cardRechargeRecord.devNo if cardRechargeRecord.devNo else "",
  1341. "logicalCode": cardRechargeRecord.logicalCode if cardRechargeRecord.logicalCode else "",
  1342. 'groupNumber': cardRechargeRecord.groupNumber,
  1343. 'groupName': cardRechargeRecord.groupName,
  1344. 'devTypeName': cardRechargeRecord.dev_type_name,
  1345. "money": cardRechargeRecord.money,
  1346. "description": cardRechargeRecord.my_description,
  1347. "ownerId": cardRechargeRecord.ownerId,
  1348. "consumeType": u"cardRecharge"
  1349. }
  1350. if str(cardRechargeRecord.id) in refundIds.keys():
  1351. refundedMoney = refundIds.get(str(cardRechargeRecord.id))
  1352. newData.update({"refundedMoney": refundedMoney})
  1353. dataList.append(newData)
  1354. recharge_query_set = ClientRechargeModelProxy.get_data_list(
  1355. ownerId__in=dealer_ids,
  1356. startTime=startTime,
  1357. endTime=endTime,
  1358. openId=request.user.openId,
  1359. result="success",
  1360. via="recharge",
  1361. hint=[('openId', 1)])
  1362. for rechargeRcd in recharge_query_set.paginate(pageIndex, pageSize):
  1363. if rechargeRcd.attachParas.get('startKey', '') != '':
  1364. continue
  1365. if rechargeRcd.gateway in typeStrDict.keys():
  1366. typeStr = typeStrDict.get('gateway')
  1367. else:
  1368. continue
  1369. newData = {
  1370. "id": str(rechargeRcd.id),
  1371. "payType": typeStr,
  1372. "createdTime": rechargeRcd.dateTimeAdded,
  1373. "address": rechargeRcd.address,
  1374. "devNo": rechargeRcd.devNo if rechargeRcd.devNo else "",
  1375. "logicalCode": rechargeRcd.logicalCode if rechargeRcd.logicalCode else "",
  1376. 'groupNumber': rechargeRcd.groupNumber,
  1377. 'groupName': rechargeRcd.groupName,
  1378. 'devTypeName': rechargeRcd.dev_type_name,
  1379. "money": rechargeRcd.money,
  1380. "description": rechargeRcd.my_description,
  1381. "ownerId": rechargeRcd.ownerId,
  1382. "consumeType": u"rechargeCoins"
  1383. }
  1384. dataList.append(newData)
  1385. dataList.sort(key = lambda x: x.get("createdTime"), reverse = True)
  1386. return JsonResponse(
  1387. {
  1388. 'result': 1,
  1389. 'description': '',
  1390. 'payload': {'total': 10000, 'dataList': dataList}
  1391. })
  1392. @permission_required(ROLE.myuser)
  1393. def getChargeRecord(request):
  1394. # type: (WSGIRequest)->JsonResponse
  1395. """
  1396. 用户充值记录
  1397. :param request:
  1398. :return: JsonResponse
  1399. """
  1400. pageIndex = int(request.GET.get('pageIndex', 1))
  1401. pageSize = int(request.GET.get('pageSize', 10))
  1402. startTime = request.GET.get('startTime', Const.QUERY_START_DATE)
  1403. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  1404. openId = request.user.openId
  1405. if not openId:
  1406. return JsonErrorResponse(description = u'无法获取用户相关信息,请重新扫描二维码')
  1407. cardId = request.GET.get('cardTicketId', None)
  1408. if cardId:
  1409. orderNoList = VirtualCardRechargeRecord.get_link_orderNo_list(
  1410. cardId = cardId,
  1411. startTime = to_datetime(startTime, '%Y-%m-%d'),
  1412. endTime = to_datetime(endTime, '%Y-%m-%d'),
  1413. openId = openId)
  1414. queryFilter = {
  1415. 'orderNo__in': orderNoList,
  1416. 'hint': [("orderNo", 1)]
  1417. }
  1418. else:
  1419. queryFilter = {
  1420. 'ownerId__in': MyUser.get_dealer_ids(
  1421. openId = request.user.openId, productAgentId = request.user.productAgentId),
  1422. 'openId': openId,
  1423. 'result': 'success',
  1424. 'via__in': [
  1425. RechargeRecordVia.Balance,
  1426. RechargeRecordVia.Refund,
  1427. RechargeRecordVia.SendCoin,
  1428. RechargeRecordVia.Card,
  1429. RechargeRecordVia.VirtualCard,
  1430. RechargeRecordVia.MonthlyPackage,
  1431. RechargeRecordVia.RefundCash,
  1432. RechargeRecordVia.Cash
  1433. ],
  1434. 'hint': [('openId', 1)]
  1435. }
  1436. records = ClientRechargeModelProxy.get_data_list(
  1437. startTime = startTime, endTime = endTime, **queryFilter) # type: CustomQuerySet
  1438. if not records:
  1439. return JsonResponse({'result': 1, 'description': '', 'payload': {'total': 0, 'dataList': []}})
  1440. total = records.count()
  1441. dataList = []
  1442. for record in records.paginate(pageIndex, pageSize): # type: RechargeRecord
  1443. data = {
  1444. 'id': str(record.id),
  1445. 'createdTime': record.to_datetime_str(record.dateTimeAdded),
  1446. 'amount': record.my_amount,
  1447. 'groupName': record.groupName,
  1448. 'ownerId': record.ownerId,
  1449. 'via': record.via
  1450. }
  1451. dataList.append(data)
  1452. return JsonResponse(
  1453. {
  1454. 'result': 1,
  1455. 'description': '',
  1456. 'payload': {
  1457. 'total': total, 'dataList': dataList
  1458. }
  1459. }
  1460. )
  1461. @permission_required(ROLE.myuser)
  1462. def getChargeRecordDetail(request):
  1463. # type: (WSGIRequest)->JsonResponse
  1464. """
  1465. 用户充值详细记录
  1466. :param request:
  1467. :return: JsonResponse
  1468. """
  1469. _id = str(request.GET.get('id'))
  1470. ownerId = request.GET.get('ownerId')
  1471. record = ClientRechargeModelProxy.get_one(shard_filter = {'ownerId': ownerId}, id = _id) # type: RechargeRecord
  1472. if not record:
  1473. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  1474. payload = {
  1475. 'createdTime': record.dateTimeAdded,
  1476. 'orderNo': record.orderNo,
  1477. 'amount': record.my_amount,
  1478. 'groupName': record.groupName,
  1479. 'groupNumber': record.groupNumber,
  1480. 'address': record.address,
  1481. 'logicalCode': record.logicalCode,
  1482. 'devTypeName': record.dev_type_name,
  1483. 'via': record.via,
  1484. 'ownerId': record.ownerId
  1485. }
  1486. payload.update(record.extra_detail_info)
  1487. return JsonResponse(
  1488. {
  1489. 'result': 1,
  1490. 'description': '',
  1491. 'payload': payload
  1492. }
  1493. )
  1494. @permission_required(ROLE.myuser)
  1495. def hybridStartAction(request):
  1496. """
  1497. 此处有红包链接, 可以判断出往下走的流程是拉起支付还是直接启动
  1498. """
  1499. payload = json.loads(request.body)
  1500. urlId = payload.get('urlId')
  1501. dev = Device.get_dev(payload['devNo'])
  1502. if not dev:
  1503. return JsonErrorResponse(description= '设备参数缺失, 请重试')
  1504. if not urlId:
  1505. return JsonErrorResponse(description='传入参数有误, 请重试')
  1506. url = payload.pop('url', None)
  1507. payload = {
  1508. "packageId": payload['packageId'],
  1509. "groupId": dev.groupId,
  1510. "devNo": dev['devNo'],
  1511. "logicalCode": dev['logicalCode'],
  1512. "openId": payload['openId'],
  1513. "attachParas": payload['attachParas']
  1514. }
  1515. serviceCache.set('urlId_{}'.format(urlId), payload)
  1516. return JsonResponse(
  1517. {
  1518. 'result': 1,
  1519. 'description': '',
  1520. 'payload': {'url': url}
  1521. }
  1522. )
  1523. @permission_required(ROLE.myuser)
  1524. def getHybridStartActionInfo(request):
  1525. """
  1526. 返回缓存的参数 直接拉起支付
  1527. """
  1528. payload = json.loads(request.body)
  1529. urlId = payload.get('mktId')
  1530. openId = request.user.openId
  1531. redpack = Redpack.objects.filter(openId=openId, urlId=urlId).first()
  1532. if redpack:
  1533. if redpack.taskStatus != redpack.Result.FINISHED:
  1534. try:
  1535. # 去查询
  1536. ApiRequest = json.loads(redpack.extra.get('ApiRequest', ''))
  1537. clicklink = ApiRequest['Seatbid'][0]['Bid'][0]['Ads'][0]['Trackers']['Imps'][0]
  1538. adid = ApiRequest['Seatbid'][0]['Bid'][0]['Ads'][0]['Id']
  1539. from apps.thirdparties.aliyun import AlipayYunMaV3
  1540. resp = AlipayYunMaV3().query_task_status(
  1541. clicklink=clicklink,
  1542. openId=openId,
  1543. adid=adid,
  1544. )
  1545. if resp.body.success and resp.body.result.success:
  1546. redpack = Redpack.take_effect(openId=openId, urlId=urlId,
  1547. **{'ApiResult': json.dumps(resp.body.result.to_map(),
  1548. ensure_ascii=False)})
  1549. RedpackBuilder._set_alipay_key(openId, redpack.factoryCode, urlId, redpack.money.mongo_amount,
  1550. showType=redpack.showType)
  1551. else:
  1552. pass
  1553. except:
  1554. import traceback
  1555. logger.error(traceback.format_exc())
  1556. else:
  1557. pass
  1558. if redpack.taskStatus == redpack.Result.FINISHED:
  1559. cacheInfo = serviceCache.get('urlId_{}'.format(urlId))
  1560. serviceCache.delete('urlId_{}'.format(urlId))
  1561. if urlId and cacheInfo:
  1562. logicalCode = cacheInfo['logicalCode']
  1563. attachParas = cacheInfo['attachParas']
  1564. device = Device.get_dev_by_l(logicalCode)
  1565. if "isTempPackage" in attachParas and attachParas['isTempPackage'] is True:
  1566. washConfig = device["tempWashConfig"]
  1567. else:
  1568. washConfig = device["washConfig"]
  1569. package = washConfig.get(cacheInfo['packageId'])
  1570. if not package:
  1571. payload = {
  1572. "startAction": False,
  1573. "logicalCode": logicalCode
  1574. }
  1575. else:
  1576. showInfo = {
  1577. 'goodsInfo': {
  1578. 'name': '{}, {}'.format(device.majorDeviceType, device.logicalCode),
  1579. 'port': attachParas.get('chargeIndex'),
  1580. },
  1581. 'packageInfo': {
  1582. 'name': '{}{}'.format(package.get('time', ''), package.get('unit', '')),
  1583. 'coins': package['coins'],
  1584. 'price': package['price']
  1585. },
  1586. 'redPackInfo': {
  1587. 'price': min(redpack.money.amount, package['price']),
  1588. # 'coins': Redpack.pre_deducted_coins(str(redpack.id), package),
  1589. },
  1590. # 'checkoutInfo': {
  1591. # 'price': (RMB(package['price']) - redpack.money).mongo_amount,
  1592. # 'coins': RMB(package['coins'] - Redpack.pre_deducted_coins(str(redpack.id), package)).mongo_amount,
  1593. # },
  1594. }
  1595. attachParas['redpackId'] = str(redpack.id)
  1596. payload = {
  1597. "packageId": cacheInfo['packageId'],
  1598. "groupId": cacheInfo['groupId'],
  1599. "devNo": cacheInfo['devNo'],
  1600. "logicalCode": logicalCode,
  1601. "openId": cacheInfo['openId'],
  1602. "attachParas": attachParas,
  1603. "startAction": True,
  1604. 'showInfo': showInfo
  1605. }
  1606. else:
  1607. payload = {
  1608. "startAction": False,
  1609. "logicalCode": redpack.logicalCode
  1610. }
  1611. return JsonResponse(
  1612. {
  1613. 'result': 1,
  1614. 'description': '',
  1615. 'payload': payload
  1616. }
  1617. )
  1618. else:
  1619. return JsonResponse(
  1620. {
  1621. 'result': 1,
  1622. 'description': '',
  1623. 'payload': {'startAction': False}
  1624. }
  1625. )
  1626. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  1627. @permission_required(ROLE.myuser)
  1628. def submitFeedback(request):
  1629. # type: (WSGIRequest)->JsonResponse
  1630. """
  1631. 用户提交反馈
  1632. :param request:
  1633. :return:
  1634. """
  1635. openId = request.user.openId
  1636. with memcache_lock(key="{openId}.submitFeedBack".format(openId=openId), value='1', expire=60) as acquired:
  1637. if acquired:
  1638. try:
  1639. payload = feedbackSchema(json.loads(request.body))
  1640. except MultipleInvalid as e:
  1641. logger.exception(e)
  1642. return JsonErrorResponse(description = u"信息不完整,请补充信息或尝试重新扫码")
  1643. dev = Device.get_dev_by_logicalCode(payload['detailInfo']['logicalCode']) # type: DeviceDict
  1644. if not dev:
  1645. return JsonErrorResponse(description = u"当前设备不存在,请重新扫码")
  1646. if not dev.is_registered:
  1647. return JsonErrorResponse(description = u'当前设备已经被运营商解绑定(1001)')
  1648. group = dev.group # type: GroupDict
  1649. if group is None:
  1650. logger.error('[submitFeedback] failed to get group, device\'s logicalCode=%s groupId=%s'
  1651. % (dev['logicalCode'], dev['groupId']))
  1652. return JsonErrorResponse(description = u"当前设备已经被运营商解绑定(1002)")
  1653. feedbackPayload = {
  1654. 'openId': openId,
  1655. 'ownerId': dev.ownerId,
  1656. 'nickname': request.user.nickname,
  1657. 'description': payload['description'],
  1658. 'phone': payload['phone'],
  1659. 'feedType': payload['feedType'],
  1660. 'imgList': payload['imgList'],
  1661. 'isRead': True
  1662. }
  1663. detail_info = payload.pop('detailInfo')
  1664. if payload['feedType'] == 'netpay':
  1665. detail_info = {
  1666. 'orderNo': detail_info['orderNo']
  1667. }
  1668. detail_info.update(dev.identity_info)
  1669. feedbackPayload['detailInfo'] = detail_info
  1670. feedback = FeedBack(**feedbackPayload).save()
  1671. if bool(payload.get('orderNo')) and not feedbackPayload['feedType'] == 'fault':
  1672. order = ConsumeRecord.objects(
  1673. ownerId = dev.ownerId,
  1674. orderNo = feedbackPayload['consumeRecordOrderNo']
  1675. ).first() # type: ConsumeRecord
  1676. if not order:
  1677. return JsonErrorResponse(description = u'您选择的订单不存在,请重新选择。')
  1678. if order.feedbackId:
  1679. return JsonErrorResponse(description = u'您选择的订单已有投诉反馈,请等待设备运营商处理。')
  1680. updated = order.update(feedbackId = ObjectId(feedback.id))
  1681. if not updated:
  1682. logger.info('failed to update ConsumeRecord feedbackId = %s' % (str(feedback.id),))
  1683. dealer = Dealer.objects(id = str(dev['ownerId'])).first()
  1684. if dealer is None:
  1685. logger.error('[submitFeedback] cannot get dealer by id = %s' % (str(dev['ownerId']),))
  1686. return JsonOkResponse()
  1687. agent = Agent.objects(id = str(dealer.agentId)).first()
  1688. if agent is None:
  1689. logger.error('[submitFeedback] cannot get agent by id = %s' % (str(dealer.agentId),))
  1690. return JsonOkResponse()
  1691. if payload['feedType'] == 'fault':
  1692. msgType = u'设备故障'
  1693. else:
  1694. msgType = u'订单投诉'
  1695. msg = u'尊敬的%s用户%s,您的客户刚才给您报告了一条【%s】的信息,请您登录后台,从【用户反馈】查看详情' \
  1696. % (agent.productName, dealer.nickname, msgType)
  1697. task_caller('report_feedback_to_dealer_via_wechat', dealerId = str(dealer.id),
  1698. msg = msg,
  1699. nickname = request.user.nickname,
  1700. feedbackTime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
  1701. return JsonOkResponse()
  1702. else:
  1703. return JsonErrorResponse(description = u'您已正在提交')
  1704. @error_tolerate(nil = JsonErrorResponse(description = u'获取反馈失败'), logger = logger)
  1705. @permission_required(ROLE.myuser)
  1706. def getFeedbackList(request):
  1707. # type: (WSGIRequest)->JsonResponse
  1708. """
  1709. 用户提交反馈
  1710. :param request:
  1711. :return:
  1712. """
  1713. openId = request.user.openId
  1714. pageIndex = int(request.GET.get('pageIndex', 1))
  1715. pageSize = int(request.GET.get('pageSize', 10))
  1716. dealerIds = MyUser.get_dealer_ids(openId, request.user.productAgentId)
  1717. feedbacks = FeedBack.objects(openId = openId, ownerId__in = dealerIds) \
  1718. .order_by('-createTime') \
  1719. .paginate(pageIndex, pageSize) # type: CustomQuerySet
  1720. total = feedbacks.count()
  1721. items = []
  1722. for item in feedbacks: # type: FeedBack
  1723. items.append(item.summary)
  1724. return JsonResponse(
  1725. {
  1726. 'result': 1,
  1727. 'description': "",
  1728. 'payload': {
  1729. 'total': total,
  1730. 'dataList': items
  1731. }
  1732. }
  1733. )
  1734. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  1735. @permission_required(ROLE.myuser)
  1736. def getFeedbackDetail(request):
  1737. id_ = request.GET.get('id')
  1738. feedback = FeedBack.objects(id = id_).first() # type: FeedBack
  1739. if not feedback:
  1740. return JsonErrorResponse(description = u'没有找到反馈单,请刷新试试')
  1741. else:
  1742. if not feedback.isRead:
  1743. feedback.isRead = True
  1744. feedback.save()
  1745. return JsonResponse({'result': 1, 'description': '', 'payload': feedback.detail})
  1746. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  1747. @permission_required(ROLE.myuser)
  1748. def getFeedbackConfigs(request):
  1749. # type: (WSGIRequest)->JsonResponse
  1750. """
  1751. :param request:
  1752. :return:
  1753. """
  1754. logicalCode = request.GET.get('logicalCode')
  1755. # if not logicalCode:
  1756. # return JsonErrorResponse(description = u'找不到设备编号')
  1757. dev = Device.get_dev_by_l(logicalCode) or dict()
  1758. #: 暂时只是显示充电桩的端口
  1759. devTypeName = dev.get("devType", dict()).get("name", "")
  1760. if re.match(ur"充电桩", devTypeName):
  1761. payload = {"port": [str(_) for _ in range(1, 21)]}
  1762. else:
  1763. payload = {}
  1764. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  1765. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  1766. @permission_required(ROLE.myuser)
  1767. def getConsumeRecordsForFeedback(request):
  1768. # type: (WSGIRequest)->JsonResponse
  1769. """
  1770. :param request:
  1771. :return:
  1772. """
  1773. pageIndex = int(request.GET.get('pageIndex', 1))
  1774. pageSize = int(request.GET.get('pageSize', 10))
  1775. skip = (pageIndex - 1) * pageSize
  1776. logicalCode = request.GET.get('logicalCode', None)
  1777. if logicalCode:
  1778. device = Device.get_dev_by_logicalCode(logicalCode)
  1779. if not device:
  1780. return JsonErrorResponse(description = u'设备不存在,请重新扫码')
  1781. ownerIds = [device.ownerId]
  1782. else:
  1783. ownerIds = MyUser.get_dealer_ids(request.user.openId, request.user.productAgentId)
  1784. records = ConsumeRecord.objects(
  1785. ownerId__in = ownerIds,
  1786. openId = request.user.openId,
  1787. dateTimeAdded__gte = (datetime.datetime.now() - datetime.timedelta(days = 30)),
  1788. feedbackId__exists = 0).order_by("-dateTimeAdded") # type: CustomQuerySet
  1789. dataList = []
  1790. for record in records.skip(skip).limit(pageSize): # type: ConsumeRecord
  1791. dataList.append(record.info_for_feedback)
  1792. return JsonResponse(
  1793. {
  1794. 'result': 1,
  1795. 'description': '',
  1796. 'payload': {'total': records.count(), 'dataList': dataList}
  1797. })
  1798. def getNearbyDevicesFromDB(lng, lat, pageIndex, pageSize, maxDistance, agentId, devTypeName, groupId = None):
  1799. def hav(theta):
  1800. s = sin(theta / 2)
  1801. return s * s
  1802. def get_distance_hav(lat0, lng0, lat1, lng1):
  1803. if lat1 == 360 or lng1 == 360:
  1804. return -1
  1805. EARTH_RADIUS = 6371000
  1806. lat0 = radians(lat0)
  1807. lat1 = radians(lat1)
  1808. lng0 = radians(lng0)
  1809. lng1 = radians(lng1)
  1810. dlng = fabs(lng0 - lng1)
  1811. dlat = fabs(lat0 - lat1)
  1812. h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlng)
  1813. return int(2 * EARTH_RADIUS * asin(sqrt(h)))
  1814. def formatDeviceInfo(dev, devTypeName):
  1815. # type: (DeviceDict, basestring)->Optional[Dict]
  1816. logger.debug('try to format device<l={}, devNo={}> info.'.format(dev.logicalCode, dev.devNo))
  1817. distance = get_distance_hav(lat, lng, float(dev['lat']), float(dev['lng']))
  1818. group = Group.get_group(dev['groupId'])
  1819. if group is None:
  1820. return None
  1821. package = [
  1822. {
  1823. 'name': rule.get('name', ''),
  1824. 'coins': rule['coins'],
  1825. 'price': rule.get('price', rule['coins']),
  1826. 'time': rule.get('time', 20),
  1827. 'unit': rule.get('unit', u'分钟')
  1828. } for packageId, rule in dev['washConfig'].items()]
  1829. return {
  1830. 'devNo': dev.devNo,
  1831. 'type': devTypeName,
  1832. 'logicalCode': dev.logicalCode,
  1833. 'groupName': group['groupName'],
  1834. 'groupNumber': dev['groupNumber'],
  1835. 'groupId': dev.groupId,
  1836. 'address': group['address'],
  1837. 'online': dev.online,
  1838. 'status': dev.status,
  1839. 'signal': dev.signal,
  1840. 'remarks': dev['remarks'],
  1841. 'distance': distance,
  1842. 'lng': float(dev.lng),
  1843. 'lat': float(dev.lat),
  1844. 'often': False,
  1845. 'beingUsed': False,
  1846. 'package': package,
  1847. 'devTypeCode': dev.devType['code']
  1848. }
  1849. if not agentId:
  1850. logger.error('agent is null.')
  1851. return {
  1852. 'total': 0,
  1853. 'items': []
  1854. }
  1855. dealers = Dealer.get_dealers(agentId)
  1856. if not dealers:
  1857. return {
  1858. 'total': 0,
  1859. 'items': []
  1860. }
  1861. if groupId:
  1862. devices = Device.get_collection().find({'groupId': groupId})
  1863. else:
  1864. if devTypeName:
  1865. devices = Device.get_collection().find(
  1866. {
  1867. 'ownerId': {'$in': dealers},
  1868. '$where': 'this.devType != null && this.devType.name == "%s"' % devTypeName,
  1869. 'isFault': False,
  1870. 'location': {
  1871. '$near': {'$geometry': {'type': 'Point', 'coordinates': [lng, lat]},
  1872. '$maxDistance': maxDistance}}})
  1873. else:
  1874. devices = Device.get_collection().find(
  1875. {
  1876. 'ownerId': {'$in': dealers},
  1877. 'isFault': False,
  1878. 'location': {
  1879. '$near': {'$geometry': {'type': 'Point', 'coordinates': [lng, lat]},
  1880. '$maxDistance': maxDistance}}})
  1881. items = []
  1882. for dev in devices:
  1883. dev = DeviceDict(dev) # type: DeviceDict
  1884. if dev is None or not dev.lbs:
  1885. continue
  1886. try:
  1887. devInfo = formatDeviceInfo(dev, dev.devType.get('name', '')) # type: Dict
  1888. except Exception as e:
  1889. logger.exception(e)
  1890. continue
  1891. if devInfo is None:
  1892. continue
  1893. items.append(devInfo)
  1894. return_items = items[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  1895. dev_ctrl_map = Device.get_many_dev_control_cache([item['devNo'] for item in return_items])
  1896. for item in return_items:
  1897. # 换电柜的端口显示可用电池数量
  1898. if item['devTypeCode'] in [Const.DEVICE_TYPE_CODE_CHARGING_AQKJ, Const.DEVICE_TYPE_CODE_CHARGING_AQKJ_NEW]:
  1899. dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {})
  1900. item["canUseBattery"] = dev_ctrl_info.get("canUseBattery", 0)
  1901. elif Const.DEVICE_TYPE_CODE_CHARGING_KYXN <= item['devTypeCode'] < Const.DEVICE_TYPE_CODE_WASHER_BASE:
  1902. dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {})
  1903. item['allPorts'] = dev_ctrl_info.get('allPorts', 10)
  1904. item['usedPorts'] = dev_ctrl_info.get('usedPorts', 0)
  1905. item['usePorts'] = dev_ctrl_info.get('usePorts', 10)
  1906. if 'power' in dev_ctrl_info:
  1907. item['power'] = dev_ctrl_info['power']
  1908. payload = {
  1909. 'total': len(items),
  1910. 'items': return_items
  1911. }
  1912. return payload
  1913. @permission_required(ROLE.myuser)
  1914. def getNearbyGroups(request):
  1915. # type: (WSGIRequest)->JsonResponse
  1916. try:
  1917. lng = float(request.GET.get('lng'))
  1918. lat = float(request.GET.get('lat'))
  1919. maxDistance = int(request.GET.get('distance', 3000))
  1920. logger.debug('now location. lat = %s; lng = %s' % (lat, lng))
  1921. if maxDistance > Const.NEAR_BY_MAX_DISTANCE:
  1922. maxDistance = Const.NEAR_BY_MAX_DISTANCE
  1923. if lng == 360 or lat == 360 or isnan(lng) or isnan(lat):
  1924. return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'})
  1925. payload = getNearbyDevicesFromDB(lng, lat, 1, 1000, maxDistance, request.user.agentId,
  1926. request.GET.get('type', None))
  1927. groupDict = {}
  1928. for dev in payload['items']:
  1929. if groupDict.has_key(dev['groupId']):
  1930. groupDict[dev['groupId']]['allDevices'] += 1
  1931. if dev['status'] == Const.DEV_WORK_STATUS_IDLE:
  1932. groupDict[dev['groupId']]['idleDevices'] += 1
  1933. else:
  1934. newValue = {
  1935. 'distance': dev['distance'],
  1936. 'lng': float(dev['lng']),
  1937. 'lat': float(dev['lat']),
  1938. 'address': dev['address'],
  1939. 'groupName': dev['groupName'],
  1940. 'groupId': dev['groupId'],
  1941. 'allDevices': 1,
  1942. 'idleDevices': 1 if dev['status'] == Const.DEV_WORK_STATUS_IDLE else 0
  1943. }
  1944. groupDict[dev['groupId']] = newValue
  1945. payload = {'total': len(groupDict.values()), 'items': groupDict.values()}
  1946. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  1947. except Exception as e:
  1948. logger.exception(e)
  1949. return JsonResponse({'result': 0, 'description': u'获取附近设备失败'})
  1950. @permission_required(ROLE.myuser)
  1951. def getNearbyDevices(request):
  1952. # type: (WSGIRequest)->JsonResponse
  1953. try:
  1954. groupId = request.GET.get('groupId', None)
  1955. lng = float(request.GET.get('lng'))
  1956. lat = float(request.GET.get('lat'))
  1957. maxDistance = int(request.GET.get('distance', 3000))
  1958. logger.debug('now location. lat = %s; lng = %s' % (lat, lng))
  1959. if maxDistance > Const.NEAR_BY_MAX_DISTANCE:
  1960. maxDistance = Const.NEAR_BY_MAX_DISTANCE
  1961. if lng == 360 or lat == 360 or isnan(lng) or isnan(lat):
  1962. return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'})
  1963. pageIndex = int(request.GET.get('pageIndex', 0))
  1964. pageSize = int(request.GET.get('pageSize', 10))
  1965. payload = getNearbyDevicesFromDB(lng, lat, pageIndex, pageSize, maxDistance,
  1966. getattr(request.user, 'productAgentId', ''),
  1967. request.GET.get('type', None), groupId)
  1968. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  1969. except Exception as e:
  1970. logger.exception(e)
  1971. return JsonResponse({'result': 0, 'description': u'获取附近设备失败'})
  1972. @permission_required(ROLE.manager)
  1973. def getEndUserDetailList(request):
  1974. # type: (WSGIRequest)->JsonResponse
  1975. """
  1976. :param request:
  1977. :return:
  1978. """
  1979. mid = str(request.user.id)
  1980. pageIndex = int(request.GET.get('pageIndex', 1))
  1981. pageSize = int(request.GET.get('pageSize', 10))
  1982. searchKey = request.GET.get('searchKey', None)
  1983. agentIds = [str(agent['_id']) for agent in Agent.get_collection().find({'managerId': mid}, {'_id': True})]
  1984. dealerIds = [str(dealer['_id']) for dealer in
  1985. Dealer.get_collection().find({'agentId': {'$in': agentIds}}, {'_id': True})]
  1986. groupIds = [str(group['_id']) for group in
  1987. Group.get_collection().find({'ownerId': {'$in': dealerIds}}, {'_id': True})]
  1988. skip = (pageIndex - 1) * pageSize
  1989. dataList = []
  1990. users = MyUser.search(searchKey).filter(groupId__in = groupIds)
  1991. for u in users.skip(skip).limit(pageSize):
  1992. item = {
  1993. 'id': str(u.id),
  1994. 'nickname': u.nickname,
  1995. 'openId': u.openId,
  1996. 'sex': u.sex,
  1997. 'country': u.country,
  1998. 'province': u.province,
  1999. 'city': u.city,
  2000. 'balance': u.balance,
  2001. 'groupName': '',
  2002. 'gateway': u.gateway
  2003. }
  2004. group = Group.get_group(u.groupId)
  2005. if group:
  2006. item.update({'groupName': group.get('groupName')})
  2007. dataList.append(item)
  2008. total = users.count()
  2009. return JsonResponse({
  2010. 'result': 1,
  2011. 'description': '',
  2012. 'payload': {
  2013. 'total': total,
  2014. 'dataList': dataList
  2015. }
  2016. })
  2017. @error_tolerate(nil = JsonErrorResponse(description = u'获取消费记录失败'), logger = logger)
  2018. @permission_required(ROLE.manager)
  2019. def getEndUserConsumeRecords(request):
  2020. # type: (WSGIRequest)->JsonResponse
  2021. """
  2022. :param request:
  2023. :return:
  2024. """
  2025. pageIndex = int(request.GET.get('pageIndex', 1))
  2026. pageSize = int(request.GET.get('pageSize', 10))
  2027. userId = request.GET.get('id', None)
  2028. if not userId:
  2029. return JsonErrorResponse(description = u'用户id为空')
  2030. else:
  2031. startTime = request.GET.get('startTime', Const.QUERY_START_DATE)
  2032. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  2033. user = MyUser.objects(id = str(userId)).get()
  2034. group = Group.get_group(user.groupId)
  2035. cursor = ClientConsumeModelProxy.get_data_list(
  2036. startTime = startTime,
  2037. endTime = endTime,
  2038. ownerId = group['ownerId'],
  2039. openId = user.openId,
  2040. groupId = user.groupId) # type: QuerySetProxy
  2041. total = cursor.count()
  2042. records = [
  2043. {
  2044. "orderNo": r.orderNo,
  2045. "time": r.time,
  2046. "coins": r.coin,
  2047. "devNo": r.devNo,
  2048. "devType": r.dev_type_name,
  2049. "groupName": r.groupName
  2050. }
  2051. for r in cursor.paginate(pageIndex, pageSize)
  2052. ]
  2053. return JsonResponse({'result': 1, 'description': '', 'payload': {'total': total, 'dataList': records}})
  2054. @error_tolerate(nil = JsonErrorResponse(description = u'获取充值记录失败'), logger = logger)
  2055. @permission_required(ROLE.manager)
  2056. def getEndUserRechargeRecords(request):
  2057. # type: (WSGIRequest)->JsonResponse
  2058. """
  2059. :param request:
  2060. :return:
  2061. """
  2062. pageIndex = int(request.GET.get('pageIndex', 1))
  2063. pageSize = int(request.GET.get('pageSize', 10))
  2064. userId = request.GET.get('id', None)
  2065. if not userId:
  2066. return JsonErrorResponse(description = u'用户id为空')
  2067. else:
  2068. startTime = request.GET.get('startTime', Const.QUERY_START_DATE)
  2069. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  2070. user = MyUser.objects(id = str(userId)).get()
  2071. group = Group.get_group(user.groupId)
  2072. cursor = ClientRechargeModelProxy.get_data_list(startTime = startTime,
  2073. endTime = endTime,
  2074. ownerId = group['ownerId'],
  2075. openId = user.openId,
  2076. groupId = user.groupId,
  2077. hint = [('openId', 1)]) # type: QuerySetProxy
  2078. total = cursor.count()
  2079. records = [
  2080. {
  2081. "orderNo": r.orderNo,
  2082. "time": r.to_js_timestamp(r.dateTimeAdded),
  2083. "money": r.money,
  2084. "coins": r.coins,
  2085. "devNo": r.devNo,
  2086. "devType": r.dev_type_name,
  2087. "groupName": r.groupName,
  2088. "gateway": r.gateway
  2089. } for r in cursor.paginate(pageIndex, pageSize)]
  2090. return JsonResponse({'result': 1, 'description': '', 'payload': {'total': total, 'dataList': records}})
  2091. def wxconfig(request):
  2092. url = request.GET.get('href')
  2093. if not url:
  2094. return JsonResponse({'result': 0, 'description': u'参数错误', 'payload': {}})
  2095. current_user = request.user # type: MyUser
  2096. wxconfig = get_wx_config(current_user, url)
  2097. return JsonOkResponse(payload = {'wxconfig': wxconfig})
  2098. # 用于前台界面时间计时用
  2099. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  2100. @permission_required(ROLE.myuser)
  2101. def countDown(request):
  2102. # type: (WSGIRequest)->JsonResponse
  2103. openId = str(request.user.openId)
  2104. devNo = str(request.GET.get('devNo', ''))
  2105. portStr = request.GET.get('chargeIndex', None)
  2106. if portStr is not None:
  2107. port = int(portStr)
  2108. else:
  2109. port = None
  2110. dev = Device.get_dev(devNo)
  2111. logicalCode = dev['logicalCode']
  2112. group = Group.get_group(dev['groupId'])
  2113. devType = dev.get('devType')
  2114. dealer = Dealer.objects.get(id = dev['ownerId'])
  2115. agent = Agent.objects.get(id = dealer.agentId)
  2116. # 判断是否是摩丫丫的设备 判断是否是烘干机设备
  2117. if (agent.features != [] and 'moyaya666' in agent.features) or (
  2118. dealer.features != [] and 'dryer' in dealer.features):
  2119. last_time_cache = serviceCache.get(user_last_time_use_ended_cache(openId, logicalCode), '')
  2120. if last_time_cache == '':
  2121. serviceCache.set(user_last_time_use_ended_cache(openId, logicalCode), datetime.datetime.now(), 3600)
  2122. elif last_time_cache != '':
  2123. if datetime.datetime.now() > last_time_cache + datetime.timedelta(hours = 1):
  2124. serviceCache.set(user_last_time_use_ended_cache(openId, logicalCode), datetime.datetime.now(), 3600)
  2125. ctrInfo = Device.get_dev_control_cache(devNo)
  2126. if ctrInfo:
  2127. lastOpenId = ctrInfo.get('openId', '')
  2128. else:
  2129. lastOpenId = ''
  2130. box = ActionDeviceBuilder.create_action_device(dev)
  2131. try:
  2132. response = box.count_down(request, dev, agent, group, devType, lastOpenId, port)
  2133. if response is None:
  2134. return JsonErrorResponse(description = u'系统不支持此操作哦')
  2135. return response
  2136. except ServiceException as e:
  2137. logger.error('get count_down error=%s' % e.result['description'].encode('utf-8'))
  2138. return JsonErrorResponse(description = e.result['description'])
  2139. except Exception, e:
  2140. logger.error('device(%s) get count_down error=%s' % (devNo, e))
  2141. return JsonErrorResponse(description = u'系统异常,请重新刷新页面')
  2142. # 只要有回调过来,说明一定是登录成功了,就直接送金币,然后跳转到控制页面即可。暂时不考虑authCode的鉴定以防止伪造URL。
  2143. @error_tolerate(nil = ErrorResponseRedirect(error = cn(u'系统开小差了哦,真是抱歉呀,请您刷新页面试试哦')))
  2144. @permission_required(ROLE.myuser)
  2145. def huaweiAccess(request):
  2146. # type: (WSGIRequest)->HttpResponseRedirect
  2147. openId = request.user.openId
  2148. devNo = request.COOKIES.get('devNo', None)
  2149. groupId = request.COOKIES.get('groupId', None)
  2150. if openId is None or devNo is None or groupId is None:
  2151. return ErrorResponseRedirect(error = cn(u'系统开小差了哦,真是抱歉呀,请您重新扫码试试哦'))
  2152. dev = Device.get_dev(devNo)
  2153. ads = AdRecord.objects.filter(openId = openId, adId = 0)
  2154. if ads.count() > 0:
  2155. return NetDeviceResponseRedirect(l = dev.logicalCode)
  2156. newRcd = AdRecord(converted = True, adId = 0, openId = openId, groupId = groupId, devNo = devNo)
  2157. newRcd.save()
  2158. user = MyUser.objects.get(openId = openId, groupId = groupId)
  2159. user.balance += 1
  2160. user.save()
  2161. return NetDeviceResponseRedirect(l = dev.logicalCode)
  2162. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  2163. def getCardStatus(request):
  2164. # type: (WSGIRequest)->JsonResponse
  2165. lc = request.GET.get('logicalCode')
  2166. devNo = Device.get_devNo_by_logicalCode(lc)
  2167. cardInfo = Card.get_dev_cur_card(devNo)
  2168. if cardInfo is None:
  2169. return JsonResponse(
  2170. {
  2171. "result": 0,
  2172. "description": u'刷卡区没有检测到卡,请您先把卡放到读卡区,这样才能开始充值哦',
  2173. "para": None
  2174. }
  2175. )
  2176. return JsonResponse(
  2177. {
  2178. "result": 1,
  2179. "description": None,
  2180. "para": {
  2181. "ready": True,
  2182. "cardId": cardInfo['cardNo'],
  2183. "money": cardInfo["money"]
  2184. }
  2185. }
  2186. )
  2187. @permission_required(ROLE.myuser)
  2188. def pollBtInfo(request):
  2189. # type: (WSGIRequest)->JsonResponse
  2190. payload = json.loads(request.body)
  2191. device = Device.get_dev_by_logicalCode(payload.get('logicalCode'))
  2192. if not device:
  2193. return JsonResponse({'result': 0, 'description': u'设备不存在', 'payload': {}})
  2194. code = Const.BT_DEVICE_TYPE_CODE_MAP[int(payload.get('code'))]
  2195. actionBox = ActionBtDeviceBuilder.create(code, device)
  2196. major = int(payload.get('major'))
  2197. minor = int(payload.get('minor'))
  2198. notify_payload = payload.get('payload', None)
  2199. if not notify_payload:
  2200. notify_payload = payload.get('advertisData', None)
  2201. if notify_payload:
  2202. result, description = actionBox.poll_notify(notify_payload, **{'major': major, 'minor': minor})
  2203. return JsonResponse({'result': result, 'description': description, 'payload': {}})
  2204. else:
  2205. return JsonResponse({'result': 1, 'description': 'empty', 'payload': {}})
  2206. @error_tolerate(nil=JsonErrorResponse(description=u'显示用户信息错误'), logger=logger)
  2207. @permission_required(ROLE.myuser)
  2208. @request_limit_by_user(operation='userInfo', limit=50, logger=logger)
  2209. def userInfo(request):
  2210. # type: (WSGIRequest)->JsonResponse
  2211. logger.info('receive userInfo')
  2212. user = request.user # type: MyUser
  2213. agentId = user.agentId
  2214. payload = {
  2215. 'nickname': user.nickname,
  2216. 'balance': user.total_balance,
  2217. 'agentId': agentId,
  2218. 'domain': settings.MY_DOMAIN,
  2219. 'avatarUrl': request.user.avatar if request.user.avatar else settings.DEFAULT_AVATAR_URL,
  2220. 'noVirtualCard': False,
  2221. 'noRechargeCard': False,
  2222. 'noRecharge': False,
  2223. 'userId': ''
  2224. }
  2225. agent = Agent.objects(id = agentId).first() # type: Optional[Agent]
  2226. if agent:
  2227. payload['agentFeatures'] = agent.features
  2228. if 'hideRechargeCardForUser' in agent.features:
  2229. payload.update({'noRechargeCard': True})
  2230. # if 'ledgerAfterFinished' in agent.features:
  2231. # payload.update({
  2232. # 'noVirtualCard': True,
  2233. # 'noRechargeCard': True,
  2234. # 'noRecharge': True
  2235. # })
  2236. # 校验是否要绑定用户的手机号码
  2237. if 'telVerify' in agent.features:
  2238. needTelVerify = check_user_tel(user)
  2239. payload.update({
  2240. "needTelVerify": needTelVerify
  2241. })
  2242. # 检查是否支持一卡多用
  2243. if 'card_multi_use' in agent.features:
  2244. payload.update({'card_multi_use': True})
  2245. user_id = user.user_id
  2246. if user_id:
  2247. payload.update({'userId': user_id})
  2248. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  2249. @error_tolerate(nil = JsonErrorResponse(description = u'获取组失败'), logger = logger)
  2250. @permission_required(ROLE.myuser)
  2251. def getRecentlyGroup(request):
  2252. # type: (WSGIRequest)->JsonResponse
  2253. my_product_agent_id = request.user.productAgentId
  2254. # 是否是查询卡卷
  2255. hasCoupon = request.GET.get('hasCoupon', False)
  2256. openId = request.user.openId
  2257. rcds = ConsumeRecord.objects.filter(openId = openId, isNormal = True).order_by('-dateTimeAdded')
  2258. devNoList = list(set([rcd.devNo for rcd in rcds[0:100]]))
  2259. dataList = []
  2260. groupIdList = []
  2261. dealerIdList = []
  2262. map_dealer_product = {}
  2263. for devNo in devNoList:
  2264. dev = Device.get_dev(devNo)
  2265. if (dev is None) or (not dev.has_key('groupId')):
  2266. continue
  2267. group = Group.get_group(dev['groupId'])
  2268. if not group:
  2269. continue
  2270. dealer_id = str(dev['ownerId'])
  2271. if not dealer_id:
  2272. logger.error('dealer is null. id = %s' % dealer_id)
  2273. continue
  2274. try:
  2275. dealer = Dealer.objects(id = dealer_id).first()
  2276. if not dealer:
  2277. logger.error('dealer is null. id = %s' % dealer_id)
  2278. continue
  2279. except Exception as e:
  2280. logger.error('dealerId = {}; exception = {}'.format(dealer_id, str(e)))
  2281. if dealer_id not in map_dealer_product:
  2282. try:
  2283. product_agent = get_user_manager_agent(dealer) # type:Agent
  2284. except Exception as e:
  2285. logger.exception(e)
  2286. product_agent = None
  2287. if not product_agent:
  2288. logger.error('get product agent failure. devNo = {}; dealer id = {}'.format(dev['devNo'], dealer_id))
  2289. continue
  2290. map_dealer_product[dealer_id] = str(product_agent.id)
  2291. if map_dealer_product[dealer_id] != my_product_agent_id:
  2292. logger.debug('{} is not equal agent({})'.format(repr(dev), my_product_agent_id))
  2293. continue
  2294. if dev['groupId'] not in groupIdList:
  2295. if (not group.has_key('address')) or (not group.has_key('groupName')):
  2296. continue
  2297. dataList.append({'address': group['address'],
  2298. 'groupName': group['groupName'],
  2299. 'groupId': dev['groupId'],
  2300. 'devType': dev.get('devType', {}).get('name', ''),
  2301. 'logicalCode': dev['logicalCode'],
  2302. 'ownerId': dev['ownerId']}
  2303. )
  2304. groupIdList.append(dev['groupId'])
  2305. dealerIdList.append(dev['ownerId'])
  2306. if not hasCoupon:
  2307. return JsonResponse({"result": 1, "description": "", "payload": {"total": len(dataList), "dataList": dataList}})
  2308. # 查询下地址下的已经发布的虚拟卡
  2309. dealerIdList = list(set(dealerIdList))
  2310. vCards = VirtualCard.objects.filter(ownerId__in = dealerIdList, status = 1)
  2311. dataList1 = []
  2312. for data in dataList:
  2313. match = False
  2314. for card in vCards:
  2315. if data['ownerId'] == card.ownerId and ('*' in card.groupIds or data['groupId'] in card.groupIds):
  2316. match = True
  2317. break
  2318. if match:
  2319. dataList1.append(data)
  2320. return JsonResponse({"result": 1, "description": "", "payload": {"total": len(dataList1), "dataList": dataList1}})
  2321. @error_tolerate(nil = JsonErrorResponse(description = u'获取卡列表失败'), logger = logger)
  2322. @permission_required(ROLE.myuser)
  2323. def getCardList(request):
  2324. # type: (WSGIRequest)->JsonResponse
  2325. """
  2326. :param request:
  2327. :return:
  2328. """
  2329. pageIndex = int(request.GET.get('pageIndex', 1))
  2330. pageSize = int(request.GET.get('pageSize', 10))
  2331. searchKey = request.GET.get('searchKey', None)
  2332. openId = request.user.openId
  2333. agentId = request.user.agentId # zjl user.agentId -> user.productAgentId
  2334. agent = Agent.objects.get(id = agentId)
  2335. manager = Manager.objects(id = agent.managerId).get() # zjl delete
  2336. agent_id_list = [str(item.id) for item in Agent.objects(managerId = str(manager.id))] # zjl delete
  2337. hideMenu = True if 'hideCardMenu' in agent.features else False
  2338. skip = (pageIndex - 1) * pageSize
  2339. cards = Card.objects.filter(openId = openId, # zjl delete
  2340. agentId__in = agent_id_list).search(searchKey) # zjl delete
  2341. # cards = Card.objects.filter(openId=openId, # zjl new
  2342. # agentId=agentId).search(searchKey) # zjl new
  2343. dataList = []
  2344. for card in cards.skip(skip).limit(pageSize):
  2345. hide = ['orderRecord', 'rechargeRecord', 'backRecord', 'frozen'] if (card.cardType == 'IC' and hideMenu) else []
  2346. if card.devNo:
  2347. dev = Device.get_dev(card.devNo) or dict()
  2348. devType = dev.get('devType', {})
  2349. if devType.has_key('id'):
  2350. try:
  2351. devType = DeviceType.objects.get(id = devType['id'])
  2352. if not devType.supportIcCardcharge:
  2353. hide.append('cardCharge')
  2354. except Exception, e:
  2355. pass
  2356. # 分以下三种情况处理
  2357. # 1 有groupId, 但是没有dealerId, 这个查数据目前没有。 这个情况下dealerId设置为group对应的, 如果没有dealer, 全部清空
  2358. # 2 有dealerId, 没有groupId, 这种情况下, 直接取dealer的第一个groupId, 没有全部取空
  2359. # 3 两个都没有的情况下, 直接取设备对应的group和dealerId
  2360. if not card.groupId:
  2361. if card.dealerId:
  2362. group = Group.get_default_group(card.dealerId) # type: GroupDict
  2363. if group:
  2364. card.groupId = group.groupId
  2365. else:
  2366. card.groupId = ''
  2367. card.dealerId = ''
  2368. card.save()
  2369. else:
  2370. # 不处理. 这个用户自己去绑定
  2371. pass
  2372. else:
  2373. if not card.dealerId:
  2374. group = Group.get_group(card.groupId) # type: GroupDict
  2375. if not group:
  2376. card.groupId = ''
  2377. card.dealerId = ''
  2378. else:
  2379. card.dealerId = group.ownerId
  2380. card.save()
  2381. group = Group.get_group(card.groupId) # type: GroupDict
  2382. dataList.append(
  2383. {
  2384. 'cardId': str(card.id),
  2385. 'cardNo': card.cardNo,
  2386. 'cardType': card.cardType,
  2387. 'cardName': card.cardName,
  2388. 'phone': card.phone,
  2389. 'groupId': card.groupId,
  2390. 'groupName': group.groupName if group else '',
  2391. 'dealerId': card.dealerId,
  2392. 'balance': card.balance,
  2393. 'isHaveBalance': card.isHaveBalance,
  2394. 'remarks': card.remarks,
  2395. 'status': card.status,
  2396. 'frozen': False if card.frozen is None else card.frozen,
  2397. 'hide': hide,
  2398. 'boundVirtualCardId': card.boundVirtualCardId
  2399. }
  2400. )
  2401. total = cards.count()
  2402. return JsonResponse(
  2403. {
  2404. 'result': 1,
  2405. 'description': '',
  2406. 'payload':
  2407. {
  2408. 'total': total, "dataList": dataList
  2409. }
  2410. }
  2411. )
  2412. @error_tolerate(nil = JsonOkResponse(description = u"获取卡信息失败"), logger = logger)
  2413. @permission_required(ROLE.myuser)
  2414. def getCard(request):
  2415. """
  2416. 获取单一的卡信息
  2417. :param request:
  2418. :return:
  2419. """
  2420. cardId = request.GET.get("cardId", "")
  2421. try:
  2422. card = Card.objects.get(id = cardId)
  2423. except DoesNotExist:
  2424. return JsonErrorResponse(description = u"获取卡信息失败,请刷新页面试试")
  2425. agentId = request.user.agentId
  2426. agent = Agent.objects.get(id = agentId)
  2427. hideMenu = True if 'hideCardMenu' in agent.features else False
  2428. hide = ['orderRecord', 'rechargeRecord', 'backRecord', 'frozen'] if (card.cardType == 'IC' and hideMenu) else []
  2429. if card.devNo:
  2430. dev = Device.get_dev(card.devNo) or dict()
  2431. devType = dev.get('devType', {})
  2432. if devType.has_key('id'):
  2433. try:
  2434. devType = DeviceType.objects.get(id = devType['id'])
  2435. if not devType.supportIcCardcharge:
  2436. hide.append('cardCharge')
  2437. except Exception as e:
  2438. logger.exception(e)
  2439. group = Group.get_group(card.groupId)
  2440. data = {
  2441. 'cardId': str(card.id),
  2442. 'cardNo': card.cardNo,
  2443. 'cardType': card.cardType,
  2444. 'cardName': card.cardName,
  2445. 'phone': card.phone,
  2446. 'groupId': card.groupId,
  2447. 'groupName': group.groupName if group else '',
  2448. 'dealerId': card.dealerId,
  2449. 'balance': card.balance,
  2450. 'isHaveBalance': card.isHaveBalance,
  2451. 'remarks': card.remarks,
  2452. 'status': card.status,
  2453. 'frozen': False if card.frozen is None else card.frozen,
  2454. 'hide': hide,
  2455. }
  2456. return JsonOkResponse(payload = data)
  2457. @error_tolerate(nil = JsonErrorResponse(description = u"查询卡信息失败"), logger = logger)
  2458. @permission_required(ROLE.myuser)
  2459. def queryCard(request):
  2460. """
  2461. 根据前台提供的cardNo 以及 groupId 返回该卡的所有信息
  2462. :param request:
  2463. :return:
  2464. """
  2465. # 获取参数 参数校验
  2466. cardNo = request.GET.get("cardNo")
  2467. groupId = request.GET.get("groupId")
  2468. if not all([cardNo, groupId]):
  2469. return JsonErrorResponse(description = u"参数不全,请输入卡号获取扫描设备获取绑定地址")
  2470. group = Group.get_group(groupId) # type: GroupDict
  2471. if not group:
  2472. return JsonErrorResponse(description = u"开卡地址不存在,请重新扫描设备获取绑定地址或联系发卡经销商(1001)")
  2473. dealer = Dealer.objects(id = str(group.ownerId)).first() # type: Dealer
  2474. if not dealer:
  2475. return JsonErrorResponse(description = u"开卡地址不存在,请重新扫描设备获取绑定地址或联系发卡经销商(1002)")
  2476. agent = Agent.objects(id = str(dealer.agentId)).first()
  2477. if not agent:
  2478. return JsonErrorResponse(description = u"代理商不存在,请刷新页面后重试(1001)")
  2479. productAgent = get_user_manager_agent(agent)
  2480. if str(productAgent.id) != request.user.productAgentId:
  2481. return JsonErrorResponse(description = u"不是该平台下的地址,请换个设备编号扫码试试(1001)")
  2482. # 鉴别卡相应信息
  2483. try:
  2484. card = Card.objects.get(cardNo=cardNo, agentId=str(agent.id))
  2485. except DoesNotExist:
  2486. # 没有找到卡的情况下 如果代理商规定了经销商必须要先录入卡
  2487. dealerBindCard = True if "dealerBindCard" in agent.features else False
  2488. if dealerBindCard:
  2489. return JsonErrorResponse(description=u"无效的卡号,该卡号未被录入,请联系发卡方")
  2490. return JsonResponse(
  2491. {
  2492. "result": 1,
  2493. "description": u"",
  2494. "payload": {
  2495. "cardNo": cardNo,
  2496. "groupId": group.groupId,
  2497. "groupName": group.groupName,
  2498. }
  2499. }
  2500. )
  2501. # 卡已经被被别人绑定了
  2502. if card.openId and card.openId != request.user.openId and card.openId != Const.DEFAULT_CARD_OPENID:
  2503. return JsonResponse(
  2504. {
  2505. "result": ErrorCode.CARD_BIND_BY_OTHER,
  2506. "description": u"{} 卡片已经被其他用户使用,请检查卡号是否正确或联系相应的经销商".format(cardNo),
  2507. "payload": {}
  2508. }
  2509. )
  2510. if group.groupId != card.groupId:
  2511. card_bind_group = Group.get_group(card.groupId)
  2512. else:
  2513. card_bind_group = group
  2514. if not card_bind_group:
  2515. card_bind_dealer = None
  2516. else:
  2517. card_bind_dealer = Dealer.objects(id = str(card_bind_group.ownerId)).first()
  2518. # 卡綁定的組和經銷商只要有一個無效, 就走增加的流程
  2519. if not card_bind_group or not card_bind_dealer:
  2520. return JsonResponse(
  2521. {
  2522. "result": 1,
  2523. "description": u"",
  2524. "payload": {
  2525. "cardNo": cardNo,
  2526. "groupId": group.groupId,
  2527. "groupName": group.groupName,
  2528. }
  2529. }
  2530. )
  2531. # 该卡已经被自己绑定
  2532. if card.openId and card.openId != Const.DEFAULT_CARD_OPENID:
  2533. return JsonResponse(
  2534. {
  2535. "result": ErrorCode.CARD_BIND_BY_SELF,
  2536. "description": u"{} 卡片已经存在于您的卡包中,是否进入编辑界面编辑该卡的相应信息".format(cardNo),
  2537. "payload": {
  2538. "cardId": str(card.id),
  2539. "cardNo": cardNo,
  2540. "cardName": card.cardName,
  2541. "groupId": card_bind_group.groupId,
  2542. "groupName": card_bind_group.groupName,
  2543. "phone": card.phone
  2544. }
  2545. }
  2546. )
  2547. # 该卡没有被绑定, 但是经销商信息已经绑定, 直接走绑定流程
  2548. if not card.openId or card.openId == Const.DEFAULT_CARD_OPENID:
  2549. return JsonResponse(
  2550. {
  2551. "result": ErrorCode.CARD_FORBID_CHARGE_GROUP,
  2552. "description": u"该卡已经被经销商录入,是否进入卡绑定界面绑定卡{}".format(cardNo),
  2553. "payload": {
  2554. "cardId": str(card.id),
  2555. "cardNo": cardNo,
  2556. "cardName": card.cardName,
  2557. "groupId": card_bind_group.groupId,
  2558. "groupName": card_bind_group.groupName,
  2559. "phone": card.phone
  2560. }
  2561. }
  2562. )
  2563. @error_tolerate(nil = JsonErrorResponse(description = u"添加卡失败"), logger = logger)
  2564. @permission_required(ROLE.myuser)
  2565. def addCard(request):
  2566. """
  2567. 添加卡 之前已经做过校验了
  2568. :param request:
  2569. :return:
  2570. """
  2571. payload = json.loads(request.body)
  2572. cardNo = payload.get("cardNo")
  2573. cardName = payload.get("cardName")
  2574. phone = payload.get("phone")
  2575. logicalCode = payload.get("logicalCode")
  2576. cardId = payload.get("cardId")
  2577. cardType = payload.get('cardType', '')
  2578. # 参数校验
  2579. if cardNo.isdigit():
  2580. cardNo = str(int(cardNo))
  2581. if not Card.check_card_no(cardNo):
  2582. return JsonErrorResponse(description = u"激活失败,无效的卡号,卡号长度不能超过32位")
  2583. if cardName and not check_entity_name(cardName):
  2584. return JsonErrorResponse(description = u"请输入正确的持卡人昵称(2-20位)")
  2585. if phone and not check_phone_number(phone):
  2586. return JsonErrorResponse(description = u"手机号码输入错误")
  2587. # 绑定设备和经销商的关系校验
  2588. device = Device.get_dev_by_l(logicalCode)
  2589. if not device:
  2590. return JsonErrorResponse(description = u"错误的设备二维码,请重新扫描设备二维码")
  2591. group = Group.get_group(device.get("groupId"))
  2592. if not group:
  2593. return JsonErrorResponse(description = u"未找到设备组,请刷新页面重试")
  2594. dealer = Dealer.objects.filter(id = group.get("ownerId")).first()
  2595. if not dealer:
  2596. return JsonErrorResponse(description = u"未找到经销商,请刷新页面重试")
  2597. agent = Agent.objects.filter(id = str(dealer.agentId)).first()
  2598. if not agent:
  2599. return JsonErrorResponse(description = u"未找到代理商,请刷新页面重试")
  2600. productAgent = get_user_manager_agent(agent)
  2601. if str(productAgent.id) != request.user.productAgentId:
  2602. return JsonErrorResponse(description = u"不是该平台下的用户,不能绑定该平台的实体卡")
  2603. if not cardId:
  2604. # 是否允许办理多张实体卡
  2605. onlyOneCard = True if "onlyOneCard" in agent.features and not request.user.many_cards else False
  2606. if onlyOneCard and request.user.cards_num > 0:
  2607. return JsonErrorResponse(description = u"您只能绑定一张实体卡,请联系经销商了解相应的规则")
  2608. # 卡存在校验
  2609. try:
  2610. card = Card.objects.get(Q(agentId=str(agent.id)) | Q(agentId=str(agent.id)), cardNo=cardNo)
  2611. except DoesNotExist:
  2612. # 没有找到卡的情况下 如果代理商规定了经销商必须要先录入卡
  2613. dealerBindCard = True if "dealerBindCard" in agent.features else False
  2614. if dealerBindCard:
  2615. return JsonErrorResponse(description=u"无效的卡号,该卡号未被录入,请联系发卡方")
  2616. card = Card(
  2617. cardNo = cardNo,
  2618. openId = request.user.openId,
  2619. cardName = cardName,
  2620. groupId = device.get("groupId"),
  2621. phone = phone,
  2622. nickName = request.user.nickname,
  2623. agentId = str(agent.id),
  2624. dealerId = str(dealer.id),
  2625. productAgentId = request.user.productAgentId,
  2626. managerialAppId = request.user.managerialAppId,
  2627. managerialOpenId = request.user.managerialOpenId,
  2628. cardType = cardType
  2629. )
  2630. card.save()
  2631. return JsonOkResponse(u"添加成功", payload = {"cardId": str(card.id)})
  2632. # 优先判断dealerId是否允许,在判断绑定关系
  2633. if card.dealerId and card.dealerId != device.get("ownerId"):
  2634. return JsonErrorResponse(description = u"该卡已被其他经销商录入,请确认卡号无误后联系您的发卡经销商")
  2635. if card.openId and card.openId != request.user.openId and card.openId != Const.DEFAULT_CARD_OPENID:
  2636. return JsonErrorResponse(description = u"该卡已被其他用户绑定,请确认卡号无误后联系您的发卡经销商")
  2637. card.openId = request.user.openId
  2638. card.cardName = cardName
  2639. card.phone = phone
  2640. card.nickName = request.user.nickname
  2641. card.groupId = device.get("groupId")
  2642. card.dealerId = str(dealer.id)
  2643. card.agentId = str(agent.id)
  2644. card.productAgentId = request.user.productAgentId
  2645. card.managerialAppId = request.user.managerialAppId
  2646. card.managerialOpenId = request.user.managerialOpenId
  2647. card.save()
  2648. return JsonOkResponse(u"添加成功", payload = {"cardId": str(card.id)})
  2649. # 1003 ErrorCode 过来的
  2650. else:
  2651. try:
  2652. card = Card.objects.get(id = cardId)
  2653. except DoesNotExist:
  2654. return JsonErrorResponse(description = u"未找到实体卡,请刷新页面后重试")
  2655. card.openId = request.user.openId
  2656. card.groupId = group.groupId
  2657. card.dealerId = group.ownerId
  2658. card.agentId = str(agent.id)
  2659. if cardName != card.cardName:
  2660. card.cardName = cardName
  2661. if phone != card.phone:
  2662. card.phone = phone
  2663. card.nickName = request.user.nickname
  2664. card.productAgentId = request.user.productAgentId
  2665. card.managerialAppId = request.user.managerialAppId
  2666. card.managerialOpenId = request.user.managerialOpenId
  2667. card.save()
  2668. return JsonOkResponse(u"添加成功", payload = {"cardId": str(card.id)})
  2669. @error_tolerate(nil = JsonErrorResponse(description = u"编辑卡失败"), logger = logger)
  2670. @permission_required(ROLE.myuser)
  2671. def editCard(request):
  2672. """
  2673. 卡编辑
  2674. :param request:
  2675. :return:
  2676. """
  2677. payload = json.loads(request.body)
  2678. cardName = payload.get("cardName")
  2679. if cardName and not check_entity_name(cardName):
  2680. return JsonErrorResponse(description = u"请输入正确的持卡人昵称(2-20位)")
  2681. phone = payload.get("phone")
  2682. if phone and not check_phone_number(phone):
  2683. return JsonErrorResponse(description = u"手机号码输入错误")
  2684. card = Card.objects(id = str(payload.get("cardId"))).first()
  2685. if not card:
  2686. return JsonErrorResponse(description = u"未找到可编辑的卡片,请刷新页面重试")
  2687. card.cardName = cardName
  2688. card.phone = phone
  2689. card.save()
  2690. return JsonOkResponse(description = u"修改成功")
  2691. @error_tolerate(nil = JsonErrorResponse(description = u"补卡失败"), logger = logger)
  2692. @permission_required(ROLE.myuser)
  2693. def swapCardNo(request):
  2694. """
  2695. 用户补卡 其实就是换个卡号
  2696. :param request:
  2697. :return:
  2698. """
  2699. payload = json.loads(request.body)
  2700. cardNo = payload.get("cardNo", "")
  2701. cardId = payload.get("cardId")
  2702. # 卡号前置去0
  2703. if cardNo.isdigit():
  2704. cardNo = str(int(cardNo))
  2705. openId = str(request.user.openId)
  2706. if not Card.check_card_no(cardNo):
  2707. return JsonErrorResponse(description = u"无效的卡号,卡号长度不能超过32位")
  2708. try:
  2709. oldCard = Card.objects.get(id = cardId)
  2710. except DoesNotExist:
  2711. return JsonErrorResponse(description = u"查询旧卡失败")
  2712. # 没有找到卡的情况下 如果代理商规定了经销商必须要先录入卡
  2713. agent = Agent.objects.get(id=oldCard.productAgentId)
  2714. dealerBindCard = True if "dealerBindCard" in agent.features else False
  2715. if dealerBindCard:
  2716. return JsonErrorResponse(description=u"无效的卡号,该卡号未被录入,请联系发卡方")
  2717. if oldCard.cardNo == cardNo:
  2718. return JsonErrorResponse(description = u"卡号一致无需修改")
  2719. if oldCard.openId != openId:
  2720. return JsonErrorResponse(description = u"不是您的卡号,无权修改")
  2721. checkStatus, checkMsg = Card.check_swap_card_no(cardNo, oldCard.dealerId, oldCard.agentId)
  2722. if not checkStatus:
  2723. return JsonErrorResponse(description = checkMsg)
  2724. # 直接将卡号更新掉,然后新建一条换卡记录
  2725. oldCard.update(cardNo = cardNo)
  2726. SwapCardRecord.add_record(oldCard.cardNo, cardNo, oldCard.agentId, str(request.user.id))
  2727. return JsonOkResponse(description = u"卡号修改成功")
  2728. @error_tolerate(nil = JsonErrorResponse(description = u"绑定失败"), logger = logger)
  2729. def bindCard(request):
  2730. """
  2731. 用户通过经销商分享的链接进来绑定实体卡
  2732. :param request:
  2733. :return:
  2734. """
  2735. openId = request.user.openId
  2736. payload = json.loads(request.body)
  2737. cardName = payload.get("cardName")
  2738. if not check_entity_name(cardName):
  2739. return JsonErrorResponse(description = u"请输入正确的持卡人昵称(2-20位)")
  2740. phone = payload.get("phone")
  2741. if not check_phone_number(phone):
  2742. return JsonErrorResponse(description = u"手机号码输入错误")
  2743. cardId = payload.get('cardId')
  2744. card = Card.objects(id = cardId).first() # type: Card
  2745. if not card:
  2746. return JsonErrorResponse(u"该实体卡不存在,请联系经销商获取正确的绑定二维码")
  2747. group = Group.get_group(card.groupId) # type: GroupDict
  2748. if not group:
  2749. return JsonErrorResponse(u'开卡地址无效,请联系经销商获取正确的绑定二维码(1001)')
  2750. dealer = Dealer.objects(id = str(group.ownerId)).first() # type: Dealer
  2751. if not dealer:
  2752. return JsonErrorResponse(u'开卡地址无效,请联系经销商获取正确的绑定二维码(1002)')
  2753. if str(dealer.id) != card.dealerId:
  2754. return JsonErrorResponse(u'开卡地址无效,请联系经销商获取正确的绑定二维码(1003)')
  2755. agent = Agent.objects(id = str(dealer.agentId)).first()
  2756. if not agent:
  2757. return JsonErrorResponse(description = u'代理商不存在,请刷新页面后重试(1002)')
  2758. productAgent = get_user_manager_agent(agent)
  2759. if str(productAgent.id) != request.user.productAgentId:
  2760. return JsonErrorResponse(description = u"不是该平台下的用户,不能绑定该平台的实体卡")
  2761. # 和卡相关的特性的获取
  2762. onlyOneCard = True if "onlyOneCard" in agent.features and not request.user.many_cards else False
  2763. if onlyOneCard and request.user.cards_num > 0:
  2764. return JsonErrorResponse(description = u"您只能绑定一张实体卡,请联系经销商了解相应的规则")
  2765. card.openId = openId
  2766. card.cardName = cardName
  2767. card.phone = phone
  2768. card.nickName = request.user.nickname
  2769. card.productAgentId = request.user.productAgentId
  2770. card.managerialAppId = request.user.managerialAppId
  2771. card.managerialOpenId = request.user.managerialOpenId
  2772. card.save()
  2773. return JsonOkResponse(description = u"添加成功", payload = {"cardId": str(card.id)})
  2774. @error_tolerate(nil = JsonErrorResponse(description = u'解绑卡失败'), logger = logger)
  2775. @record_operation_behavior()
  2776. @permission_required(ROLE.myuser)
  2777. def unbindCard(request):
  2778. # type: (WSGIRequest)->JsonResponse
  2779. openId = request.user.openId
  2780. payload = json.loads(request.body)
  2781. cardId = payload.get('id', None)
  2782. card = Card.objects(id = cardId, openId = openId).first()
  2783. if not card:
  2784. return JsonErrorResponse(description = u'找不到该卡')
  2785. updated = card.clear_card()
  2786. if not updated:
  2787. return JsonErrorResponse(description = u'变更状态失败')
  2788. return JsonResponse({"result": 1, "description": "", "payload": {}})
  2789. @error_tolerate(nil = JsonErrorResponse(description = u'获取正在使用失败'), logger = logger)
  2790. @permission_required(ROLE.myuser)
  2791. def getCurrentUse(request):
  2792. # type: (WSGIRequest)->JsonResponse
  2793. openId = request.user.openId
  2794. filters = {
  2795. "open_id": openId,
  2796. "isFinished": False,
  2797. "port": {"$ne": -1}
  2798. }
  2799. # 后付费流程中,扫码的时候会将 跳转到用户的正在服务 这个地方不要受其他设备类型的干扰
  2800. orderId = request.GET.get("orderId")
  2801. if orderId:
  2802. consumeOrder = ClientConsumeModelProxy.get_one(id=orderId)
  2803. device = Device.get_dev(consumeOrder.devNo)
  2804. if not device.owner: # 经销商此时解绑了
  2805. return JsonResponse({"result": 1, "description": "", "payload": {"total": 0, "dataList": []}})
  2806. # 下面的可以恢复正常流程
  2807. if device.devTypeCode in support_policy_device:
  2808. filters = {
  2809. "open_id": openId,
  2810. "device_imei": device.devNo,
  2811. "consumeOrder.consumeRecordId": orderId,
  2812. }
  2813. pageIndex = int(request.GET.get('pageIndex', 1))
  2814. pageSize = int(request.GET.get('pageSize', 10))
  2815. dataList = []
  2816. for item in ServiceProgress.get_collection().find(filters):
  2817. if int(time.time()) > item['finished_time']:
  2818. continue
  2819. else:
  2820. try:
  2821. devNo = item['device_imei']
  2822. device = Device.get_dev(devNo) # type: DeviceDict
  2823. smartBox = ActionDeviceBuilder.create_action_device(device)
  2824. group = Group.get_group(device['groupId'])
  2825. nowTime = int(time.time())
  2826. data = {
  2827. 'startTime': time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(item['start_time'])),
  2828. 'order': item['consumeOrder'],
  2829. 'address': group.get('address', ''),
  2830. 'groupName': group.get('groupName', ''),
  2831. 'devType': device['devType'].get('name'),
  2832. 'devTypeCode': device['devType'].get('code'),
  2833. 'logicalCode': device['logicalCode'],
  2834. 'status': Const.DEV_WORK_STATUS_WORKING,
  2835. 'devNo': devNo,
  2836. 'majorDeviceType': device.majorDeviceType
  2837. }
  2838. if 'show_PG_to_user' in device.owner.features and device.support_power_graph and item.get("port"):
  2839. data.update({'showPG': True, 'port': item.get("port")})
  2840. if device['devType']['code'] in support_policy_weifule:
  2841. orderInfoList = smartBox.get_current_use(base_data=data, spDict=item)
  2842. dataList.extend(orderInfoList)
  2843. continue
  2844. needTime = item.get('consumeOrder', {}).get('needTime', None)
  2845. unit = item.get('consumeOrder', {}).get('unit', None)
  2846. if needTime and unit in [u'分钟', u'小时', u'天',
  2847. u'秒']: # 数据库里面记录的都是归为分钟(建议后续全部统一为秒).这里计算的时间是以设备为准,不是以端口为准的,实际如果有端口,应该以端口为准
  2848. if needTime == 999: # 特殊表示充满自停
  2849. data.update({'needTime': u'充满自停'})
  2850. else:
  2851. data.update({'needTime': u'%s分钟' % needTime,
  2852. 'leftTime': round(int(item['finished_time'] - nowTime) / 60.0, 1)})
  2853. if item.get('port', -2) in [0, -1]:
  2854. dataList.append(data)
  2855. continue
  2856. else:
  2857. data.update({"port": item["port"]})
  2858. ctrInfo = Device.get_dev_control_cache(devNo)
  2859. _coin = data.get("order", dict()).get("coin")
  2860. if _coin:
  2861. data["order"].update({"coin": "{}{}".format(_coin, smartBox.show_pay_unit)})
  2862. try:
  2863. curInfo = device.deviceAdapter.get_port_using_detail(item['port'], ctrInfo)
  2864. if curInfo.has_key('startTime'): # 微付乐自己的单板会上报startTime上来,和这里的startTime有冲突,所以,需要以订单的startTime为准
  2865. curInfo.pop('startTime')
  2866. if device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_HAINIAO:
  2867. curInfo['port'] = str(int(curInfo['port']) + 1)
  2868. if 'orderNo' in curInfo:
  2869. if data['order']['orderNo'] == curInfo['orderNo']: # 说明此单正处于运行中,数据可以直接用
  2870. data.update(curInfo)
  2871. else:
  2872. data.update({
  2873. 'orderNo': data['order']['orderNo'],
  2874. 'desc': u'此订单已经下发到设备上,上一单运行完毕就会自动运行此订单',
  2875. })
  2876. data.pop('leftTime', None)
  2877. data.pop('leftElec', None)
  2878. else:
  2879. data.update(curInfo)
  2880. # 正在服务显示按钮
  2881. data.update(DeviceType.get_services_button(device['devType']['id']))
  2882. try:
  2883. data.update({'actualNeedTime': data['usedTime'] + data['leftTime']})
  2884. except Exception as e:
  2885. pass
  2886. dealer = Dealer.get_dealer(device.ownerId)
  2887. if dealer:
  2888. agent = Agent.objects(id = dealer['agentId']).first() # type: Agent
  2889. if agent:
  2890. agentFeatures = agent.features
  2891. if 'show_elec_data_for_user' not in agentFeatures:
  2892. data.pop('elec', None)
  2893. data.pop('needElec', None)
  2894. data.pop('power', None)
  2895. data.pop("leftElec", None)
  2896. data.pop("usedElec",None)
  2897. if not device.is_auto_refund and "hide_refund_data_for_user" in agentFeatures:
  2898. data.pop("consumeMoney", None)
  2899. data.pop("leftMoney", None)
  2900. data.pop("usedTime", None)
  2901. data.pop("leftTime", None)
  2902. if 'hide_consume_coin_data' in device.devTypeFeatures:
  2903. data.pop('consumeMoney', None)
  2904. data.pop('leftMoney', None)
  2905. if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHARGING_HONGZHUO]:
  2906. data.pop('actualNeedTime',None)
  2907. data['power'] = data['powerNow']
  2908. if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_BL_TEN,
  2909. Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE]:
  2910. data.pop('actualNeedTime',None)
  2911. # 这里需要反过来做一次校验,因为网络不稳定,可能造成丢包,没有刷新状态。
  2912. # 如果出来的状态是空闲的,那就说明服务已经结束
  2913. # zjl 充电柜的临时跳过 下个版本会对这个function进行彻底的拆分
  2914. if device.devTypeCode not in [
  2915. Const.DEVICE_TYPE_CODE_CABINET_NEW,
  2916. Const.DEVICE_TYPE_CODE_CABINET,
  2917. Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING,
  2918. Const.DEVICE_TYPE_CODE_CHANGING_BL_TEN,
  2919. Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE,] + support_policy_device:
  2920. isFinished = False
  2921. if curInfo.has_key('power') and curInfo.has_key('leftTime'):
  2922. if curInfo['power'] == 0 and curInfo['leftTime'] in [0, u'(线路空载)']:
  2923. isFinished = True
  2924. else:
  2925. if (curInfo.has_key('power') and curInfo['power'] == 0) or (
  2926. curInfo.has_key('leftTime') and curInfo['leftTime'] in [0, u'(线路空载)']):
  2927. isFinished = True
  2928. if isFinished:
  2929. try:
  2930. ServiceProgress.get_collection().update_many(
  2931. {
  2932. 'open_id': openId,
  2933. 'isFinished': False,
  2934. 'device_imei': devNo,
  2935. 'port': item['port']
  2936. }, {
  2937. '$set':
  2938. {
  2939. 'isFinished': True,
  2940. 'expireAt': datetime.datetime.now()
  2941. }
  2942. })
  2943. data['leftTime'] = 0
  2944. except Exception as e:
  2945. logger.error('update service progress e=%s' % e)
  2946. except Exception as e:
  2947. logger.exception('get cur info=%s' % e)
  2948. dataList.append(data)
  2949. except Exception as e:
  2950. logger.exception(e)
  2951. # 返回数据之前 将数据再次过滤一遍
  2952. count = len(dataList)
  2953. dataList = dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  2954. newDataList = list()
  2955. for _consumeDict in dataList:
  2956. if "devNo" in _consumeDict:
  2957. dev = Device.get_dev(_consumeDict["devNo"])
  2958. newDataList.append(UserConsumeFilter(dev.owner, _consumeDict).filter())
  2959. else:
  2960. newDataList.append(_consumeDict)
  2961. return JsonResponse({
  2962. "result": 1,
  2963. "description": "",
  2964. "payload": {
  2965. "total": count,
  2966. "dataList": newDataList
  2967. }
  2968. })
  2969. @error_tolerate(nil=JsonErrorResponse(description = u'获取计数失败'), logger = logger)
  2970. @permission_required(ROLE.myuser)
  2971. def getUserCenterCount(request):
  2972. # type: (WSGIRequest)->JsonResponse
  2973. openId = request.user.openId
  2974. # 统计正在使用
  2975. currentUse = ConsumeRecord.objects.filter(
  2976. openId=openId,
  2977. status__in=[
  2978. ConsumeRecord.Status.RUNNING, ConsumeRecord.Status.END
  2979. ]
  2980. ).count()
  2981. # 统计反馈消息
  2982. dealerIds = MyUser.get_dealer_ids(openId, request.user.productAgentId)
  2983. newMessage = FeedBack.objects.filter(openId=openId, ownerId__in=dealerIds, isRead=False)
  2984. return JsonResponse(
  2985. {
  2986. "result": 1,
  2987. "description": "",
  2988. "payload": {
  2989. "currentUse": currentUse, "newMessage": newMessage.count()
  2990. }
  2991. })
  2992. @error_tolerate(nil = JsonErrorResponse(description = u'获取卡记录失败'), logger = logger)
  2993. @permission_required(ROLE.myuser)
  2994. def getUserCardRecord(request):
  2995. # type: (WSGIRequest)->JsonResponse
  2996. pageIndex = int(request.GET.get('pageIndex', 1))
  2997. pageSize = int(request.GET.get('pageSize', 10))
  2998. startTime = request.GET.get('startTime', 10)
  2999. endTime = request.GET.get('endTime', 10)
  3000. cardId = request.GET.get('cardId', None)
  3001. type = request.GET.get('type', None)
  3002. card = Card.objects.get(id = cardId)
  3003. if type == "chargeCard":
  3004. dataList = []
  3005. for item in CardRechargeRecord.get_collection().find(
  3006. {
  3007. 'cardId': cardId,
  3008. 'dateTimeAdded':
  3009. {
  3010. '$gte': to_datetime(startTime + " 00:00:00"),
  3011. '$lte': to_datetime(endTime + " 23:59:59")
  3012. },
  3013. "remarks": {
  3014. "$ne": u"退币"
  3015. }
  3016. }
  3017. ).sort("dateTimeAdded", -1):
  3018. data = {
  3019. "cardId": str(item['_id']),
  3020. "cardNo": card.cardNo,
  3021. "via": "chargeCard",
  3022. "amount": item['money'],
  3023. "coins": item.get('coins', item['money']),
  3024. "address": item['address'],
  3025. "groupName": item['groupName'],
  3026. "balance": item['balance'],
  3027. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S')
  3028. }
  3029. if item.has_key('preBalance'):
  3030. data.update({'preBalance': item['preBalance']})
  3031. dataList.append(data)
  3032. elif type == "consume":
  3033. dataList = []
  3034. rcds = CardConsumeRecord.get_collection().find({'cardId': cardId,
  3035. 'dateTimeAdded': {
  3036. '$gte': to_datetime(startTime + " 00:00:00"),
  3037. '$lte': to_datetime(endTime + " 23:59:59")}}).sort(
  3038. "dateTimeAdded", -1)
  3039. for item in rcds:
  3040. newData = {
  3041. "cardId": str(cardId),
  3042. "cardNo": card.cardNo,
  3043. "via": "consume",
  3044. "devType": item['devType'],
  3045. "amount": item['money'],
  3046. "logicalCode": item['logicalCode'],
  3047. "address": item['address'],
  3048. "groupName": item['groupName'],
  3049. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S')
  3050. }
  3051. newData.update(item.get('servicedInfo', {}))
  3052. dataList.append(newData)
  3053. elif type == 'order':
  3054. dataList = [
  3055. {
  3056. "via": "order",
  3057. "amount": item['money'],
  3058. "coins": item.get('coins', item['money']),
  3059. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'),
  3060. "status": u'等待刷卡充值' if item['status'] == 'finishedPay' else u'充值完成',
  3061. "desc": item['remarks']
  3062. }
  3063. for item in CardRechargeOrder.get_collection().find({
  3064. 'cardId': cardId,
  3065. 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  3066. '$lte': to_datetime(endTime + " 23:59:59")}})
  3067. .sort("dateTimeAdded", -1)]
  3068. elif type == "refund":
  3069. dataList = []
  3070. for item in CardRechargeRecord.get_collection().find(
  3071. {
  3072. 'cardId': cardId,
  3073. 'dateTimeAdded':
  3074. {
  3075. '$gte': to_datetime(startTime + " 00:00:00"),
  3076. '$lte': to_datetime(endTime + " 23:59:59")
  3077. },
  3078. "remarks": u"退币"
  3079. }
  3080. ).sort("dateTimeAdded", -1):
  3081. data = {
  3082. "cardId": str(item['_id']),
  3083. "cardNo": card.cardNo,
  3084. "via": "refund",
  3085. "amount": item['money'],
  3086. "coins": item.get('coins', item['money']),
  3087. "address": item['address'],
  3088. "groupName": item['groupName'],
  3089. "balance": item['balance'],
  3090. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S')
  3091. }
  3092. if item.has_key('preBalance'):
  3093. data.update({'preBalance': item['preBalance']})
  3094. dataList.append(data)
  3095. elif type == "frozen":
  3096. dataList = []
  3097. for item in getattr(card, 'ongoingList', []):
  3098. order = ConsumeRecord.objects.filter(id = item['transaction_id']).first()
  3099. data = {
  3100. "amount": order.coin.mongo_amount,
  3101. "createdTime": order.startTime.strftime(Const.DATETIME_FMT),
  3102. "via": "consume",
  3103. "devType": order.dev_type_name,
  3104. "chargeIndex": order.used_port,
  3105. "logicalCode": order.logicalCode,
  3106. "address": order.address,
  3107. "groupName": order.groupName,
  3108. "balance": card.balance.mongo_amount,
  3109. "spendMoney": order.coin.mongo_amount,
  3110. }
  3111. dataList.append(data)
  3112. else:
  3113. return JsonResponse({"result": 0, "description": u"查询类型错误", "payload": {}})
  3114. return JsonResponse({"result": 1, "description": "", "payload": {"total": len(dataList), "dataList": dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]}})
  3115. @permission_required(ROLE.myuser)
  3116. def freezeCard(request):
  3117. # type: (WSGIRequest)->JsonResponse
  3118. payload = json.loads(request.body)
  3119. isFrozen = payload.get('frozen')
  3120. cardId = payload.get('id', '')
  3121. try:
  3122. card = Card.objects.get(id = cardId)
  3123. card.frozen = isFrozen
  3124. card.status = 'deactive'
  3125. card.save()
  3126. except Exception as e:
  3127. logger.exception(e.message)
  3128. return JsonResponse({"result": 0, "description": u'系统错误', "payload": {}})
  3129. # 如果是淋浴器,如果卡正在使用,直接把设备停掉,发指令过去
  3130. return JsonResponse({"result": 1, "description": '', "payload": {}})
  3131. @permission_required(ROLE.myuser)
  3132. def bindVirtualCardToRechargeIDCard(request):
  3133. # type: (WSGIRequest)->JsonResponse
  3134. # TODO zjl 这个地方最好加上虚拟卡的绑定记录
  3135. payload = json.loads(request.body)
  3136. virtualCardId = payload.get('virtualCardId')
  3137. rechargeIDCardId = payload.get('rechargeIDCardId')
  3138. if virtualCardId is None:
  3139. return JsonErrorResponse(description = u'未找到虚拟卡ID')
  3140. if rechargeIDCardId is None:
  3141. return JsonErrorResponse(description = u'未找到ID实体卡')
  3142. card = Card.objects(id = rechargeIDCardId).first()
  3143. if card is None:
  3144. return JsonErrorResponse(description = u'未找到ID实体卡')
  3145. if card.cardType != RECHARGE_CARD_TYPE.ID:
  3146. return JsonErrorResponse(description = u'该卡不是ID卡')
  3147. virtualCard = UserVirtualCard.objects(id = virtualCardId).first()
  3148. if virtualCard is None:
  3149. return JsonErrorResponse(description = u'未找到虚拟卡')
  3150. updated = card.bind_virtual_card(virtualCard)
  3151. if updated:
  3152. return JsonOkResponse()
  3153. else:
  3154. return JsonErrorResponse(description = u'绑定失败')
  3155. def unbindVirtualCardToRechargeIDCard(request):
  3156. # type: (WSGIRequest)->JsonResponse
  3157. payload = json.loads(request.body)
  3158. virtualCardId = payload.get('virtualCardId')
  3159. rechargeIDCardId = payload.get('rechargeIDCardId')
  3160. if virtualCardId is None:
  3161. return JsonErrorResponse(description = u'未找到虚拟卡ID')
  3162. if rechargeIDCardId is None:
  3163. return JsonErrorResponse(description = u'未找到ID实体卡')
  3164. card = Card.objects(id = rechargeIDCardId).first()
  3165. if card is None:
  3166. return JsonErrorResponse(description = u'未找到ID实体卡')
  3167. if card.cardType != RECHARGE_CARD_TYPE.ID:
  3168. return JsonErrorResponse(description = u'该卡不是ID卡')
  3169. virtualCard = UserVirtualCard.objects(id = virtualCardId).first()
  3170. if virtualCard is None:
  3171. return JsonErrorResponse(description = u'未找到虚拟卡')
  3172. updated = card.unbind_virtual_card(virtualCard)
  3173. if updated:
  3174. return JsonOkResponse()
  3175. else:
  3176. return JsonErrorResponse(description = u'解绑失败')
  3177. @permission_required(ROLE.myuser)
  3178. def cardDiscountList(request):
  3179. # type: (WSGIRequest)->JsonResponse
  3180. """
  3181. 获取用户实体卡套餐.
  3182. 获取的方式有两种:
  3183. 1、实体卡管理里面,直接选择卡,进入套餐界面。传入cardId参数;
  3184. 2、在扫码的充卡界面,直接输入卡号,进入套餐界面,传入扫码的设备号;
  3185. :param request:
  3186. :return:
  3187. """
  3188. def user_center_recharge(card_id):
  3189. card = Card.objects(id = str(card_id)).first() # type: Card
  3190. if not card:
  3191. logger.error('can not find the cardId = %s' % request.GET.get('cardId'))
  3192. return JsonResponse({'result': 0, 'description': u'没有找到对应的卡,请您刷新页面重试', 'payload': {}})
  3193. if not card.dealerId or not card.groupId:
  3194. return JsonResponse({
  3195. 'result': ErrorCode.CARD_NEED_BIND_GROUP,
  3196. 'description': u'此卡没有绑定开卡地址',
  3197. 'payload': {
  3198. 'cardId': str(card.id),
  3199. 'cardNo': card.cardNo,
  3200. 'phone': card.phone,
  3201. 'cardName': card.cardName
  3202. }})
  3203. group = Group.get_group(card.groupId) # type: GroupDict
  3204. card_rule_list = group.card_rule_list
  3205. card_rule_list = filter(lambda x: (float(x["coins"]) + float(card.balance)) < 5000, card_rule_list)
  3206. return JsonResponse({
  3207. 'result': 1, 'description': 'SUCCESS', 'payload': {'groupId': card.groupId, 'ruleList': card_rule_list}})
  3208. def device_type_card_charge(devCache):
  3209. """
  3210. 从套餐页面的充卡按钮进入的卡充值页面。
  3211. 不同设备类型进入不同的判断,后续有新的设备类型特有的需求增加新的判断分支。
  3212. """
  3213. if devCache.devTypeCode == Const.DEVICE_TYPE_CODE_WASHCAR_LANGUANG:
  3214. box = ActionDeviceBuilder.create_action_device(devCache)
  3215. devStatus = box.get_dev_status()
  3216. if devStatus.get('xf_status') == '0x0001':
  3217. allowCardCharge = True
  3218. else:
  3219. allowCardCharge = False
  3220. return allowCardCharge
  3221. return True
  3222. if 'cardId' in request.GET:
  3223. return user_center_recharge(request.GET.get('cardId'))
  3224. else:
  3225. if 'devNo' in request.GET and request.GET.get('devNo'):
  3226. dev = Device.get_dev(request.GET.get('devNo')) # type: Optional[DeviceDict]
  3227. elif 'logicalCode' in request.GET and request.GET.get('logicalCode'):
  3228. dev = Device.get_dev_by_logicalCode(request.GET.get('logicalCode')) # type: Optional[DeviceDict]
  3229. else:
  3230. dev = None # type: Optional[DeviceDict]
  3231. if not dev:
  3232. return JsonErrorResponse(description = u'参数错误,请刷新重试(1001)')
  3233. if device_type_card_charge(dev) is False:
  3234. return JsonErrorResponse(description = u'暂不支持卡充值,请联系经销商检查设备或重试一下')
  3235. group = Group.get_group(dev.groupId) # type: GroupDict
  3236. return JsonResponse({'result': 1, 'description': 'SUCCESS',
  3237. 'payload': {'groupId': dev.groupId, 'ruleList': group.card_rule_list}})
  3238. @error_tolerate(nil = JsonErrorResponse(description = u'未知错误'))
  3239. def getAgentQRCode(request):
  3240. # type: (WSGIRequest)->JsonResponse
  3241. agentId = request.GET.get('agentId', None)
  3242. if agentId is None:
  3243. return JsonErrorResponse(description = u'页面过期,请您重新扫码重试')
  3244. try:
  3245. agent = Agent.objects.get(id = agentId)
  3246. if agent.gzhServiceQrcodeUrl == '':
  3247. return JsonErrorResponse(description = u'没有提供公众号的二维码,需要先配置好公众号的二维码')
  3248. else:
  3249. return JsonOkResponse(
  3250. payload = {'url': agent.gzhServiceQrcodeUrl, 'linkUrl': agent.gzhServiceLinkUrl, 'title': agent.title,
  3251. 'desc': agent.desc})
  3252. except DoesNotExist:
  3253. logger.exception('could not find agent by agentId={0}'.format(agentId))
  3254. return JsonErrorResponse(description = u'没有找到对应的代理商,请您检查数据是否正确')
  3255. @permission_required(ROLE.myuser)
  3256. def reportEndUserLocation(request):
  3257. # type: (WSGIRequest)->JsonResponse
  3258. """
  3259. 上报终端用户的地理信息
  3260. `sample request`
  3261. {
  3262. 'logicalCode': '111',
  3263. 'lng': 12323.23
  3264. 'lat': 1232123.22,
  3265. 'type': 'gcj02'
  3266. }
  3267. :param request:
  3268. :return:
  3269. """
  3270. currentUser = request.user # type: cast(MyUser)
  3271. payload = json.loads(request.body)
  3272. logger.debug('end user location is: %s' % payload)
  3273. try:
  3274. GPS_TYPE.lookupByValue(payload['type'])
  3275. except ValueError:
  3276. return JsonErrorResponse(u'无效的GPS类型')
  3277. pointPair = (float(payload.get('lng', 360)), float(payload.get('lat', 360))) # type: Tuple[float, float]
  3278. if any(map(lambda _: _ == 360 or isnan(_), pointPair)):
  3279. return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'})
  3280. if pointPair in [_.coordinates for _ in currentUser.locations]:
  3281. logger.debug('user{0!r} location point{1} duplicates'.format(currentUser, pointPair))
  3282. return JsonResponse({'result': 1, 'description': ''})
  3283. location = EndUserLocation(logicalCode = payload['logicalCode'],
  3284. point = pointPair,
  3285. type = payload['type'])
  3286. updated = currentUser.update(add_to_set__locations = location)
  3287. if not updated:
  3288. logger.info(u'记录终端用户地址失败 user({0!r}) payload={1}'.format(currentUser, payload))
  3289. return JsonResponse({'result': 1, 'description': ''})
  3290. @permission_required(ROLE.myuser)
  3291. def getOnsale(request):
  3292. # type: (WSGIRequest)->JsonResponse
  3293. """
  3294. 用户侧 进入之前获取营销活动的流程
  3295. :param request:
  3296. :return:
  3297. """
  3298. lc = request.GET.get('logicalCode')
  3299. showSite = int(request.GET.get('showSite'))
  3300. dev = Device.get_dev_by_logicalCode(lc)
  3301. nowTime = datetime.datetime.now()
  3302. onsales = OnSale.objects.filter(status = 'start', showSite = showSite, dealerId = dev['ownerId'],
  3303. logicalCodeList = lc, startTime__lte = nowTime, endTime__gte = nowTime)
  3304. if onsales.count() <= 0:
  3305. return JsonOkResponse()
  3306. onsaleList = []
  3307. # 查询是否已经参加了活动, 如果已经参加 并且活动描述仅仅只能参加一次 不在展示该活动
  3308. for onsale in onsales:
  3309. if OnSaleRecord.objects.filter(onsaleId = str(onsale['id']), userId__in = [str(request.user.id),
  3310. request.user.openId]).count() and onsale.showType == "onlyOne":
  3311. continue
  3312. onsaleList.append(onsale)
  3313. if not onsaleList:
  3314. return JsonOkResponse()
  3315. # TODO 这个活动为什么是随机的 ??? 这个 shuffle 也很有问题
  3316. # random.shuffle(onsaleList)
  3317. # onsale = onsaleList[0]
  3318. onsale = random.choice(onsaleList)
  3319. return JsonResponse({
  3320. "result": 1, "description": '',
  3321. "payload": {
  3322. 'onsaleId': str(onsale.id),
  3323. 'img': onsale.img,
  3324. 'desc': onsale.desc,
  3325. 'onClickUrl': onsale.onClickUrl,
  3326. 'showType': onsale.showType
  3327. }
  3328. })
  3329. @permission_required(ROLE.myuser)
  3330. def getPromotionalCoins(request):
  3331. # type: (WSGIRequest)->JsonResponse
  3332. """
  3333. 营销活动,用户获币
  3334. :param request:
  3335. :return:
  3336. """
  3337. lc = request.GET.get('logicalCode')
  3338. onsaleId = request.GET.get('onsaleId')
  3339. # 先检查这个用户是否有领取过,如果领取过,就不允许领取
  3340. if not onsaleId:
  3341. return JsonErrorResponse(description = u'找不到营销活动ID')
  3342. if not lc:
  3343. return JsonErrorResponse(description = u'找不到设备')
  3344. user = request.user # type: MyUser
  3345. userId = str(user.id)
  3346. key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId)
  3347. with memcache_lock(key = key, value = '1', expire = 60) as acquired:
  3348. if acquired:
  3349. count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = userId).count()
  3350. if count > 0:
  3351. return JsonErrorResponse(description = u'您已经领取过金币了哦,不能再领了哦')
  3352. onsale = OnSale.objects(id = onsaleId).first() # type: Optional[OnSale]
  3353. if not onsale:
  3354. return JsonErrorResponse(description = u'推广活动不存在')
  3355. if onsale.status == 'stop':
  3356. return JsonErrorResponse(description = u'推广活动已经下架,无法领取了哦')
  3357. coins = int(onsale.detailDict.get('coins', 0))
  3358. updated = user.incr_balance(VirtualCoin(coins))
  3359. if not updated:
  3360. return JsonErrorResponse(description = u'获币失败')
  3361. # 添加一条充值记录
  3362. orderNo = str(uuid.uuid1())
  3363. dev = Device.get_dev_by_logicalCode(lc)
  3364. group = Group.get_group(dev['groupId'])
  3365. try:
  3366. newRcd = RechargeRecord(orderNo = orderNo,
  3367. coins = coins, money = 0.00, openId = request.user.openId,
  3368. groupId = dev['groupId'],
  3369. devNo = dev['devNo'], logicalCode = lc,
  3370. ownerId = dev['ownerId'], groupName = group['groupName'],
  3371. groupNumber = dev['groupNumber'], address = group['address'],
  3372. wxOrderNo = u'活动赠币',
  3373. devTypeName = dev.devTypeName, nickname = '',
  3374. result = 'success', via = 'onsaleSendCoins')
  3375. newRcd.save()
  3376. except Exception as e:
  3377. logger.exception('update record for feedback coins error=%s,orderNo=%s' % (e, orderNo))
  3378. # 增加一条活动
  3379. try:
  3380. newRcd = OnSaleRecord(
  3381. onsaleId = onsaleId,
  3382. userId = userId,
  3383. nickName = request.user.nickname,
  3384. addedTime = datetime.datetime.now(),
  3385. onsaleDetail = {'coins': coins}
  3386. )
  3387. newRcd.save()
  3388. except Exception as e:
  3389. logger.exception('update record for onsale record error=%s,orderNo=%s' % e)
  3390. return JsonOkResponse(description = u'赠送成功!您可以直接使用金币!')
  3391. else:
  3392. return JsonErrorResponse(description = u'您已正在领取')
  3393. @permission_required(ROLE.myuser)
  3394. def getPromotionalDuration(request):
  3395. # type: (WSGIRequest)->JsonResponse
  3396. """
  3397. :param request:
  3398. :return:
  3399. """
  3400. lc = request.GET.get('logicalCode')
  3401. onsaleId = request.GET.get('onsaleId')
  3402. # 先检查这个用户是否有领取过,如果领取过,就不允许领取
  3403. if not onsaleId:
  3404. return JsonErrorResponse(description = u'找不到营销活动ID')
  3405. if not lc:
  3406. return JsonErrorResponse(description = u'找不到设备')
  3407. userId = str(request.user.id)
  3408. key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId)
  3409. with memcache_lock(key = key, value = '1', expire = 60) as acquired:
  3410. if acquired:
  3411. # 先检查这个用户是否有领取过,如果领取过,就不允许领取
  3412. count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = userId).count()
  3413. if count > 0:
  3414. return JsonErrorResponse(description = u'您已经免费体验过了哦,不能再免费体验了哦,您可以试试充值消费哦')
  3415. onsale = OnSale.objects(id = onsaleId).first() # type: Optional[OnSale]
  3416. if not onsale:
  3417. return JsonErrorResponse(description = u'该活动不存在')
  3418. if onsale.status == 'stop':
  3419. return JsonErrorResponse(description = u'推广活动已经下架,无法体验了哦')
  3420. duration = int(onsale.detailDict.get('duration')) * 60
  3421. dev = Device.get_dev_by_logicalCode(lc) # type: DeviceDict
  3422. box = ActionDeviceBuilder.create_action_device(dev)
  3423. try:
  3424. box.send_dev_runtime(request.user.openId, duration)
  3425. except ServiceException, e:
  3426. return JsonErrorResponse(description = e.result.get('description'))
  3427. except Exception, e:
  3428. return JsonErrorResponse(description = u'系统异常,请您重试')
  3429. # 增加一条活动
  3430. try:
  3431. OnSaleRecord(
  3432. onsaleId = onsaleId,
  3433. userId = str(request.user.id),
  3434. nickName = request.user.nickname,
  3435. addedTime = datetime.datetime.now(),
  3436. onsaleDetail = {'duration': int(onsale.detailDict.get('duration'))}
  3437. ).save()
  3438. except Exception as e:
  3439. logger.exception('update record for onsale record error=%s' % (e,))
  3440. return JsonOkResponse(description = u'服务开始啦!您可以体验啦')
  3441. else:
  3442. return JsonErrorResponse(description = u'您已领取福利')
  3443. @permission_required(ROLE.myuser)
  3444. def getBannerList(request):
  3445. # type: (WSGIRequest)->JsonResponse
  3446. """
  3447. :param request:
  3448. :return:
  3449. """
  3450. lc = request.GET.get('logicalCode')
  3451. dev = Device.get_dev_by_logicalCode(lc)
  3452. dealer = Dealer.objects.get(id = dev['ownerId'])
  3453. agent = Agent.objects.get(id = dealer.agentId)
  3454. aBannerList = agent.bannerList
  3455. if not aBannerList or dealer.isShowBanner is False:
  3456. return JsonResponse({"result": 1, "description": '', "payload": {}})
  3457. return JsonResponse({"result": 1, "description": '', "payload": aBannerList})
  3458. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  3459. @permission_required(ROLE.myuser)
  3460. def submitComment(request):
  3461. # type: (WSGIRequest)->JsonResponse
  3462. """
  3463. :param request:
  3464. :return:
  3465. """
  3466. payload = json.loads(request.body)
  3467. lc = payload.get('logicalCode')
  3468. desc = payload.get('description')
  3469. dev = Device.get_dev_by_logicalCode(lc)
  3470. group = Group.get_group(dev['groupId'])
  3471. Comment(
  3472. devNo = dev['devNo'],
  3473. logicalCode = lc,
  3474. groupId = dev['groupId'],
  3475. groupNumber = dev['groupNumber'],
  3476. groupName = group['groupName'],
  3477. address = group['address'],
  3478. ownerId = dev['ownerId'],
  3479. openId = request.user.openId,
  3480. nickname = request.user.nickname,
  3481. ratingList = payload['rating'],
  3482. description = desc
  3483. ).save()
  3484. return JsonResponse({"result": 1, "description": '', "payload": {}})
  3485. @permission_required(ROLE.myuser)
  3486. def onsaleRecharge(request):
  3487. # type: (WSGIRequest)->JsonResponse
  3488. """
  3489. :param request:
  3490. :return:
  3491. """
  3492. user = request.user # type: MyUser
  3493. lc = request.GET.get('logicalCode')
  3494. if not lc:
  3495. return JsonResponse({"result": 0, "description": u'设备不存在,请刷新后重试(1001)', "payload": {}})
  3496. device = Device.get_dev_by_logicalCode(lc) # type: DeviceDict
  3497. if not device:
  3498. return JsonResponse({"result": 0, "description": u'设备不存在,请刷新后重试(1002)', "payload": {}})
  3499. onsaleId = request.GET.get('onsaleId')
  3500. if not onsaleId:
  3501. return JsonResponse({"result": 0, "description": u'活动ID错误,请刷新后重试', "payload": {}})
  3502. if user.groupId != device.groupId:
  3503. return JsonResponse({"result": 0, "description": u'请在扫码后点击活动页面去充值。点击其他方式的活动链接无效。', "payload": {}})
  3504. jumpUrl = concat_user_recharge_url(l = lc)
  3505. # 增加一条活动
  3506. try:
  3507. OnSaleRecord(
  3508. onsaleId = onsaleId,
  3509. userId = str(request.user.id),
  3510. nickName = request.user.nickname,
  3511. addedTime = datetime.datetime.now(),
  3512. onsaleDetail = {}
  3513. ).save()
  3514. except Exception as e:
  3515. logger.exception(e)
  3516. return JsonResponse({"result": 0, "description": u'系统异常,请重试', "payload": {}})
  3517. return JsonResponse({"result": 1, "description": '', "payload": {'url': jumpUrl}})
  3518. @permission_required(ROLE.myuser)
  3519. def onsaleTicketList(request):
  3520. # type: (WSGIRequest)->JsonResponse
  3521. """
  3522. :param request:
  3523. :return:
  3524. """
  3525. user = request.user # type: MyUser
  3526. lc = request.GET.get('logicalCode')
  3527. onsaleId = request.GET.get('onsaleId')
  3528. agentId = user.productAgentId
  3529. if agentId is None:
  3530. return JsonResponse({"result": 0, "description": '获取代理商错误', "payload": {}})
  3531. encodeUrl = concat_user_cardTicketList_entry_url(agentId = agentId, l = lc)
  3532. # 增加一条活动
  3533. try:
  3534. OnSaleRecord(
  3535. onsaleId = onsaleId,
  3536. userId = str(request.user.id),
  3537. nickName = request.user.nickname,
  3538. addedTime = datetime.datetime.now(),
  3539. onsaleDetail = {}
  3540. ).save()
  3541. except Exception as e:
  3542. logger.exception(e)
  3543. return JsonResponse({"result": 0, "description": u'系统异常,请重试', "payload": {}})
  3544. return JsonResponse({"result": 1, "description": '', "payload": {'url': encodeUrl}})
  3545. @permission_required(ROLE.myuser)
  3546. def sendCodeForVerify(request):
  3547. # type: (WSGIRequest)->JsonResponse
  3548. """
  3549. :param request:
  3550. :return:
  3551. """
  3552. payload = json.loads(request.body)
  3553. lc = payload.get('logicalCode')
  3554. onsaleId = payload.get('onsaleId')
  3555. userId = str(request.user.id)
  3556. key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId)
  3557. with memcache_lock(key = key, value = '1', expire = 60) as acquired:
  3558. if acquired:
  3559. count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = userId).count()
  3560. if count > 0:
  3561. return JsonErrorResponse(description = u'您已经免费体验过了哦,不能再免费体验了哦,您可以试试充值消费哦')
  3562. dev = Device.get_dev_by_logicalCode(lc) # type: DeviceDict
  3563. phoneNumber = payload.get('phoneNumber')
  3564. dealer = Dealer.get_dealer(dev['ownerId'])
  3565. agent = Agent.objects.get(id = dealer['agentId'])
  3566. status, msg = userMobileVerifySMSProvider.get(phoneNumber = phoneNumber,
  3567. productName = agent.productName,
  3568. vendor = SysParas.get_sms_vendor(request.user.smsVendor))
  3569. if not status:
  3570. return JsonErrorResponse(description = msg)
  3571. else:
  3572. return JsonOkResponse()
  3573. else:
  3574. return JsonErrorResponse(description = u'您已正在领取')
  3575. @permission_required(ROLE.myuser)
  3576. def mobileVerify(request):
  3577. # type: (WSGIRequest)->JsonResponse
  3578. """
  3579. :param request:
  3580. :return:
  3581. """
  3582. payload = json.loads(request.body)
  3583. lc = payload.get('logicalCode')
  3584. onsaleId = payload.get('onsaleId')
  3585. phoneNumber = payload.get('phoneNumber')
  3586. code = payload.get('code')
  3587. userId = str(request.user.id)
  3588. key = '{user}{onsale}-lock'.format(user = userId, onsale = onsaleId)
  3589. with memcache_lock(key = key, value = '1', expire = 60) as acquired:
  3590. if acquired:
  3591. status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code)
  3592. if not status:
  3593. return JsonErrorResponse(description = msg)
  3594. count = OnSaleRecord.objects.filter(onsaleId = onsaleId, userId = str(request.user.id)).count()
  3595. if count > 0:
  3596. return JsonResponse({"result": 0, "description": u'您已经免费体验过了哦,不能再免费体验了哦,您可以试试充值消费哦', "payload": {}})
  3597. try:
  3598. onsale = OnSale.objects.get(id = onsaleId)
  3599. except Exception as e:
  3600. logger.exception(e)
  3601. return JsonResponse({"result": 0, "description": u'推广活动已经下架,无法体验了哦', "payload": {}})
  3602. if onsale.status == 'stop':
  3603. return JsonResponse({"result": 0, "description": u'推广活动已经下架,无法体验了哦', "payload": {}})
  3604. duration = int(onsale.detailDict.get('duration')) * 60
  3605. dev = Device.get_dev_by_logicalCode(lc)
  3606. duration = int(onsale.detailDict.get('duration')) * 60
  3607. dev = Device.get_dev_by_logicalCode(lc) # type: DeviceDict
  3608. box = ActionDeviceBuilder.create_action_device(dev)
  3609. try:
  3610. box.send_dev_runtime(request.user.openId, duration)
  3611. except ServiceException, e:
  3612. return JsonErrorResponse(description = e.result.get('description'))
  3613. except Exception, e:
  3614. return JsonErrorResponse(description = u'系统异常,请您重试')
  3615. # 增加一条活动
  3616. try:
  3617. OnSaleRecord(
  3618. onsaleId = onsaleId,
  3619. userId = str(request.user.id),
  3620. nickName = request.user.nickname,
  3621. addedTime = datetime.datetime.now(),
  3622. onsaleDetail = {'duration': int(onsale.detailDict.get('duration')),
  3623. 'phoneNumber': phoneNumber}
  3624. ).save()
  3625. except Exception as e:
  3626. logger.exception('update record for onsale record error=%s' % (e,))
  3627. return JsonOkResponse(description = u'服务开始啦!您可以体验啦')
  3628. else:
  3629. return JsonErrorResponse(description = u'您已领取福利')
  3630. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  3631. def test(request):
  3632. return JsonOkResponse()
  3633. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  3634. def getCurrentOrder(request):
  3635. # type: (WSGIRequest)->JsonResponse
  3636. """
  3637. 获取目前用户目前订单的情况,给予用户下面操作的指示
  3638. :param request:
  3639. :return:
  3640. """
  3641. devNo = request.GET.get('devNo')
  3642. startKey = request.GET.get('startKey')
  3643. if not startKey:
  3644. return JsonErrorResponse(description = u'未找到启动key')
  3645. def get_response(orderProcessing, succeeded, desc = '', record = None):
  3646. record = {} if record is None else record
  3647. return JsonOkResponse(
  3648. payload = {
  3649. 'orderProcessing': orderProcessing,
  3650. 'succeeded': succeeded,
  3651. 'desc': desc,
  3652. 'record': record
  3653. }
  3654. )
  3655. #: 前台还需要发送请求轮询获取数据
  3656. not_yet = get_response(orderProcessing = True, succeeded = None)
  3657. #: 有错误或状态未知,前台可以停止轮询
  3658. stop_polling_unknown = get_response(orderProcessing = False, succeeded = False, desc = u'系统异常')
  3659. #: 确切知道启动成功
  3660. polling_finished_succeeded = lambda desc, record: get_response(orderProcessing = False,
  3661. succeeded = True,
  3662. desc = desc,
  3663. record = record)
  3664. #: 确切知道启动失败
  3665. polling_finished_failed = lambda desc, record: get_response(orderProcessing = False,
  3666. succeeded = False,
  3667. desc = desc,
  3668. record = record)
  3669. record = None
  3670. start_key_status = get_start_key_status(startKey) # type: dict
  3671. if start_key_status:
  3672. logger.debug('getCurrentOrder startKey = %s; status = %s; ts = %s' %
  3673. (startKey, start_key_status,
  3674. timestamp_to_dt(start_key_status['ts']).strftime(
  3675. '%Y-%m-%d %H:%M:%S') if 'ts' in start_key_status else ''))
  3676. state = start_key_status['state']
  3677. if state == START_DEVICE_STATUS.FAILURE or state == START_DEVICE_STATUS.TIMEOUT:
  3678. return polling_finished_failed(desc=start_key_status['reason'], record = None)
  3679. if state == START_DEVICE_STATUS.FINISHED:
  3680. if 'orderId' in start_key_status:
  3681. record = ConsumeRecord.objects(id = str(start_key_status['orderId'])).first() # type: ConsumeRecord
  3682. if not record:
  3683. logger.error('start key cache is not valid. value = {}'.format(str(start_key_status)))
  3684. return stop_polling_unknown
  3685. else:
  3686. logger.debug('start key status is {}'.format(state))
  3687. # 如果查过2分钟还没有结果,直接检查订单
  3688. exp = long(request.GET.get('exp', 0))
  3689. if exp < 2 * 60 * 1000:
  3690. return not_yet
  3691. else:
  3692. logger.debug('too long to get result. try to query record.')
  3693. if not record:
  3694. record = ConsumeRecord.objects(startKey = startKey).first() # type: Optional[ConsumeRecord]
  3695. if not record:
  3696. logger.error('cache and record are null, startKey = {}'.format(startKey))
  3697. return not_yet
  3698. if record.status in [ConsumeRecord.Status.WAITING, ConsumeRecord.Status.CREATED]:
  3699. return not_yet
  3700. dev = Device.get_dev(devNo) # type: DeviceDict
  3701. if not dev:
  3702. logger.error('cannot find device by devNo(%s))' % (devNo,))
  3703. return stop_polling_unknown
  3704. if record.isNormal:
  3705. #: 表明应用服务器并未发现异常,但是还是有可能实际场景失败,比如吃币,所以需要给用户良好的指导和要求其上传证据。并返回币数以便上分
  3706. return polling_finished_succeeded(
  3707. desc = u'您已成功启动设备。如果有疑问,请点击右下角"设备无反应"按钮',
  3708. record = {'coins': record.coin, 'detailLink': record.deail_link(dev), "isIns": record.insId}
  3709. )
  3710. else:
  3711. #: 设备服务器与设备连接失败(超时 etc,.)需要记录失败场景,同时保证用户不扣币,前台则给予提示其重试
  3712. return polling_finished_failed(
  3713. desc = record.errorDesc,
  3714. record = {'coins': record.coin, 'detailLink': record.deail_link(dev)}
  3715. )
  3716. @permission_required(ROLE.myuser)
  3717. def getOrderStatus(request):
  3718. # type: (WSGIRequest)->JsonResponse
  3719. """
  3720. 蓝牙获取订单状态
  3721. :param request:
  3722. :return:
  3723. """
  3724. payload = json.loads(request.body)
  3725. try:
  3726. order_id = str(payload.get('orderId'))
  3727. if OrderCacheMgr(order_id, cls_name = RechargeRecord.__name__).has_done():
  3728. record = RechargeRecord.objects(id = str(payload.get('orderId'))).first() # type: RechargeRecord
  3729. if record.is_success():
  3730. return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'success'}})
  3731. else:
  3732. return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'fail'}})
  3733. else:
  3734. return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'nop'}})
  3735. except Exception as e:
  3736. logger.exception(e)
  3737. return JsonResponse({'result': 1, 'description': '', 'payload': {'status': 'nop'}})
  3738. @permission_required(ROLE.myuser)
  3739. def pressButton(request):
  3740. # type: (WSGIRequest)->JsonResponse
  3741. payload = json.loads(request.body)
  3742. button_name = payload.get('button')
  3743. value = payload.get('value')
  3744. lc = payload.get('logicalCode')
  3745. dev = Device.get_dev_by_logicalCode(lc)
  3746. smartBox = ActionDeviceBuilder.create_action_device(dev)
  3747. try:
  3748. devInfo = smartBox.press_button(button_name, value)
  3749. except ServiceException as e:
  3750. return JsonErrorResponse(description = e.result.get('description'))
  3751. except Exception as e:
  3752. logger.exception('cannot get_port_status, error=%s' % (str(e),))
  3753. return JsonErrorResponse(description = u'未知错误')
  3754. return JsonResponse({"result": 1, "description": '', "payload": devInfo})
  3755. @permission_required(ROLE.myuser)
  3756. def changeVolume(request):
  3757. # type: (WSGIRequest)->JsonResponse
  3758. payload = json.loads(request.body)
  3759. logical_volume = payload.get('logicalCode')
  3760. volume = payload.get('value')
  3761. dev = Device.get_dev_by_logicalCode(logical_volume)
  3762. smart_box = ActionDeviceBuilder.create_action_device(dev)
  3763. try:
  3764. result = smart_box.changeVolume(volume)
  3765. return JsonResponse({"result": 1, "description": '', "payload": result})
  3766. except ServiceException as e:
  3767. return JsonErrorResponse(description = e.result.get('description'))
  3768. except AttributeError as e:
  3769. return JsonErrorResponse(description = u'暂时不支持该功能')
  3770. except Exception as e:
  3771. logger.exception('cannot changeVolume, error=%s' % (str(e),))
  3772. return JsonErrorResponse(description = u'未知错误')
  3773. @record_operation_behavior()
  3774. @permission_required(ROLE.myuser)
  3775. def stopCountDown(request):
  3776. # type: (WSGIRequest)->JsonResponse
  3777. openId = str(request.user.openId)
  3778. payload = json.loads(request.body)
  3779. port = payload.get('chargeIndex', None)
  3780. devNo = Device.get_devNo_by_logicalCode(logicalCode = payload['logicalCode'])
  3781. devCtrInfo = Device.get_dev_control_cache(devNo = devNo)
  3782. orderNo = payload.get("orderNo")
  3783. # 如果设备本身停止后,有停止时间上报,系统会在停止事件中处理退费、通知事宜。这里要做的就是直接停止而已.
  3784. dev = Device.get_dev(devNo = devNo) # type: DeviceDict
  3785. groupId = str(dev.get("groupId"))
  3786. group = Group.get_group(groupId)
  3787. box = ActionDeviceBuilder.create_action_device(dev)
  3788. if box.isHaveStopEvent:
  3789. try:
  3790. if dev.devType["code"] in [Const.DEVICE_TYPE_CODE_CHARGE_WEIFULE_CAR,
  3791. Const.DEVICE_TYPE_CODE_CAR_WEIFULE_CHARGING_DOUB,
  3792. Const.DEVICE_TYPE_CODE_CAR_WEIFULE_21KW,
  3793. Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,
  3794. Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG,
  3795. Const.DEVICE_TYPE_CODE_CHANGING_SOCKET,
  3796. Const.DEVICE_TYPE_CODE_WEIFULE_TOUCH_PAD,
  3797. Const.DEVICE_TYPE_CODE_WEIFULE_ANJIAN,
  3798. ] or dev.support_reliable:
  3799. box.stop_by_order(port, orderNo)
  3800. else:
  3801. box.stop(port)
  3802. except ServiceException, e:
  3803. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  3804. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  3805. # 没有停止事件的,需要在这里处理退费事宜
  3806. if port is None:
  3807. for ii in range(10):
  3808. try:
  3809. portInfo = devCtrInfo.get(str(ii + 1), None)
  3810. if portInfo is None:
  3811. continue
  3812. if portInfo.has_key('openId') and portInfo['openId'] == openId and portInfo['status'] in [
  3813. Const.DEV_WORK_STATUS_WORKING, Const.DEV_WORK_STATUS_PAUSE]:
  3814. port = str(ii + 1)
  3815. break
  3816. except Exception, e:
  3817. continue
  3818. with memcache_lock(key = start_device_lock_key(openId = openId), value = '1', expire = 360) as acquired:
  3819. if acquired:
  3820. if port is not None:
  3821. devCtrInfo = devCtrInfo.get(str(port), {})
  3822. totalFee = devCtrInfo.get('coins', None)
  3823. if totalFee is None:
  3824. logger.error('feedback coins error devNo=%s, totalFee=%s' % (devNo, totalFee))
  3825. return JsonResponse({"result": 0, "description": u'获取订购金额失败', "payload": {}})
  3826. totalTime = devCtrInfo.get('needTime', None)
  3827. if totalTime is None:
  3828. for _ in dev['washConfig'].values():
  3829. if totalFee == _['price']:
  3830. totalTime = int(_['time'])
  3831. try:
  3832. devInfo = box.stop(port)
  3833. except ServiceException, e:
  3834. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  3835. if 'remainder_time' not in devInfo: # 有些情况,是不需要根据时间退费的,比如云快充的充电桩,会根据事件,直接结算
  3836. return JsonResponse({"result": 1, "description": '', "payload": ''})
  3837. remainderTime = devInfo['remainder_time']
  3838. # 更新内存缓存状态
  3839. if port is None:
  3840. Device.invalid_device_control_cache(devNo)
  3841. else:
  3842. ctrInfo = Device.get_dev_control_cache(devNo)
  3843. ctrInfo.update({str(port): {}})
  3844. Device.update_dev_control_cache(devNo, ctrInfo)
  3845. refundFee = box.calc_stop_back_coins(totalFee, remainderTime, totalTime)
  3846. backCoins = VirtualCoin(refundFee)
  3847. desc = u'共付款:%s元,预定时间为:%s分钟,剩余时间:%s' % (
  3848. totalFee, totalTime, remainderTime)
  3849. # 通知完成
  3850. user = MyUser.objects(openId = openId, groupId = groupId).first()
  3851. task_caller('report_to_user_via_wechat', openId = user.managerialOpenId, dealerId = dev['ownerId'],
  3852. templateName = 'service_complete',
  3853. **{
  3854. 'title': u'订购总时间为:%s分钟,剩余时间:%s分钟' % (
  3855. totalTime,
  3856. remainderTime),
  3857. 'service': u'服务(设备编号:%s,地址:%s)' % (
  3858. payload['logicalCode'], group['address']),
  3859. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  3860. 'remark': u'谢谢您的支持'
  3861. })
  3862. # 如果需要退款,计算退款数据.
  3863. if not dev.is_auto_refund:
  3864. ServiceProgress.update_progress_and_consume_rcd(
  3865. dev['ownerId'],
  3866. {'open_id': openId, 'device_imei': devNo, 'isFinished': False},
  3867. {'leftTime': remainderTime,
  3868. 'needTime': u'扫码订购%s分钟' % totalTime,
  3869. 'duration': totalTime - remainderTime}
  3870. )
  3871. else:
  3872. # 扫码退钱, 退到个人账号
  3873. user.incr_balance(backCoins)
  3874. # 添加一条充值记录
  3875. orderNo = str(uuid.uuid4())
  3876. try:
  3877. newRcd = RechargeRecord(orderNo = orderNo,
  3878. coins = backCoins, openId = openId, groupId = str(request.user.groupId),
  3879. devNo = devNo, logicalCode = payload['logicalCode'],
  3880. ownerId = dev['ownerId'],
  3881. groupName = group['groupName'], groupNumber = dev['groupNumber'],
  3882. address = group['address'], wxOrderNo = u'设备退币',
  3883. devTypeName = dev.devTypeName, nickname = '',
  3884. result = 'success', via = 'refund')
  3885. newRcd.save()
  3886. except Exception as e:
  3887. logger.exception('update record for feedback coins error=%s,orderNo=%s' % (e, orderNo))
  3888. ServiceProgress.update_progress_and_consume_rcd(
  3889. dev['ownerId'],
  3890. {'open_id': openId, 'device_imei': devNo, 'isFinished': False},
  3891. {'leftTime': remainderTime,
  3892. 'needTime': u'扫码订购%s分钟' % totalTime,
  3893. 'duration': totalTime - remainderTime}
  3894. )
  3895. task_caller('report_to_user_via_wechat', openId = user.managerialOpenId, dealerId = dev['ownerId'],
  3896. templateName = 'refund_coins',
  3897. **{
  3898. 'title': desc,
  3899. 'backCount': u'金币:%s' % backCoins,
  3900. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  3901. })
  3902. return JsonResponse({"result": 1, "description": '', "payload": ''})
  3903. @error_tolerate(nil=JsonErrorResponse(u"获取虚拟卡列表失败"))
  3904. @permission_required(ROLE.myuser)
  3905. def getCardTicketList(request): # type: (WSGIRequest)->JsonResponse
  3906. """
  3907. 获取虚拟卡的列表
  3908. """
  3909. pageIndex = int(request.GET.get('pageIndex', 1))
  3910. pageSize = int(request.GET.get('pageSize', 10))
  3911. invalid = int(request.GET.get("invalid", 0))
  3912. openId = request.user.openId
  3913. now_time = datetime.datetime.now()
  3914. filters = {"openIds": openId}
  3915. if invalid:
  3916. filters.update({"expiredTime__lt": now_time})
  3917. else:
  3918. filters.update({"expiredTime__gte": now_time})
  3919. vCards = UserVirtualCard.objects.filter(**filters)
  3920. total = vCards.count()
  3921. dataList = list()
  3922. for _vcard in vCards.skip((pageIndex - 1) * pageSize).limit(pageSize):
  3923. data = _vcard.to_dict()
  3924. # 检查是否需要续费
  3925. isNeedRenew, days = is_need_renew(_vcard)
  3926. if isNeedRenew:
  3927. data.update({'needRenew': True})
  3928. # 添加是否是卡主
  3929. data.update({"isOwner": _vcard.isOwner(request.user.openId)})
  3930. dataList.append(data)
  3931. return JsonOkResponse(payload={
  3932. 'total': total, 'pageSize': pageSize, 'dataList': dataList
  3933. })
  3934. @error_tolerate(nil=JsonErrorResponse(u"获取虚拟卡详情失败"))
  3935. @permission_required(ROLE.myuser)
  3936. def getCardTicket(request):
  3937. cardId = request.GET.get("cardId")
  3938. try:
  3939. card = UserVirtualCard.objects.get(id=cardId)
  3940. except DoesNotExist:
  3941. return JsonErrorResponse(description=u"获取虚拟卡详情失败")
  3942. payload = card.to_detail()
  3943. isNeedRenew, days = is_need_renew(card)
  3944. if isNeedRenew:
  3945. payload.update({'needRenew': True})
  3946. payload.update({
  3947. "isOwner": card.isOwner(request.user.openId),
  3948. "agentId": request.user.productAgentId
  3949. })
  3950. return JsonOkResponse(payload=payload)
  3951. @error_tolerate(nil = DefaultJsonErrorResponse, logger = logger)
  3952. @permission_required(ROLE.myuser)
  3953. def getUserVirtualCardByGroup(request):
  3954. """
  3955. 通过groupId查询该地址下有没有购买过虚拟卡
  3956. :param request:
  3957. :return:
  3958. """
  3959. groupId = request.GET.get("groupId")
  3960. if not groupId:
  3961. return JsonErrorResponse(u"查询错误")
  3962. # 如果没有通过地址数量的检查 则直接提示不能开卡
  3963. if not Group.check_virtual_card_number(groupId):
  3964. return JsonErrorResponse(description = u"该地址虚拟卡数量已经达到上限,请联系发卡经销商")
  3965. vCards = UserVirtualCard.objects.filter(
  3966. openIds__in = [request.user.openId],
  3967. groupIds__in = ['*', groupId],
  3968. expiredTime__gt = datetime.datetime.now()
  3969. )
  3970. vCardList = [str(vCard.cardNo) for vCard in vCards]
  3971. return JsonOkResponse(payload = {"vCardList": vCardList})
  3972. @permission_required(ROLE.myuser)
  3973. def getCardTicketTypeList(request):
  3974. # type: (WSGIRequest)->JsonResponse
  3975. groupId = request.GET.get('groupId', None)
  3976. if groupId is None:
  3977. return JsonErrorResponse(u'没有找到您的充值地址哦')
  3978. if not Group.check_virtual_card_number(groupId):
  3979. return JsonErrorResponse(description=u"该地址虚拟卡数量已经达到上限,请联系发卡经销商")
  3980. group = Group.get_group(groupId)
  3981. onlineCards = VirtualCard.objects.filter(
  3982. ownerId=group['ownerId'],
  3983. status=1,
  3984. groupIds__in=['*', groupId],
  3985. expiredTime__gt=datetime.datetime.now()
  3986. )
  3987. dataList = []
  3988. for obj in onlineCards:
  3989. data = obj.to_dict()
  3990. if '*' in obj.groupIds:
  3991. groups = [{'groupName': grp['groupName'], 'address': grp['address']} for grp in
  3992. Group.get_groups_by_group_ids(Group.get_group_ids_of_dealer(obj.ownerId)).values()]
  3993. else:
  3994. groups = [{'groupName': grp['groupName'], 'address': grp['address']} for grp in
  3995. Group.get_groups_by_group_ids(obj.groupIds).values()]
  3996. data["groups"] = groups
  3997. dataList.append(data)
  3998. return JsonOkResponse(payload={'dataList': dataList})
  3999. # 分享卡卷的链接
  4000. @permission_required(ROLE.myuser)
  4001. def getShareCardTicket(request):
  4002. # type: (WSGIRequest)->JsonResponse
  4003. vCardId = request.GET.get('cardId', None)
  4004. if vCardId is None:
  4005. return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被卡主注销,无法共享', "payload": None})
  4006. try:
  4007. vCard = UserVirtualCard.objects.get(id = vCardId)
  4008. except DoesNotExist as e:
  4009. return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被卡主注销,无法共享', "payload": None})
  4010. if len(vCard.openIds) > vCard.userLimit - 1:
  4011. return JsonResponse({"result": 0, "description": u'共享的人数已经达到卡的限制,您无法共享哦', "payload": None})
  4012. agentId = Dealer.get_dealer(vCard.dealerId).get('agentId', None)
  4013. if agentId is None:
  4014. return JsonResponse({"result": 0, "description": u'非法卡,您无法共享哦', "payload": None})
  4015. if request.user.agentId != agentId:
  4016. return JsonResponse({"result": 0, "description": u'非法卡,您无法共享哦', "payload": None})
  4017. if request.user.openId in vCard.openIds:
  4018. return JsonResponse({"result": 0, "description": u'您已经共享了此卡', "payload": None})
  4019. vCard.openIds.append(request.user.openId)
  4020. try:
  4021. vCard.save()
  4022. except Exception as e:
  4023. logger.info('save sharing card error=%s' % e)
  4024. return JsonResponse({"result": 0, "description": u'保存卡的信息异常,请您重试', "payload": None})
  4025. data = vCard.to_detail()
  4026. data.update({
  4027. "isOwner": vCard.isOwner(request.user.openId),
  4028. "agentId": request.user.productAgentId
  4029. })
  4030. return JsonResponse({"result": 1, "description": '', "payload": data})
  4031. @permission_required(ROLE.myuser)
  4032. def removeCardSharedMembers(request):
  4033. # type: (WSGIRequest)->JsonResponse
  4034. payload = json.loads(request.body)
  4035. vCardId = payload.get('cardId')
  4036. openId = payload.get('userId')
  4037. if vCardId is None:
  4038. return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被注销,请您刷新页面后再重试', "payload": None})
  4039. try:
  4040. vCard = UserVirtualCard.objects.get(id = vCardId)
  4041. except DoesNotExist:
  4042. return JsonResponse({"result": 0, "description": u'没有找到卡卷,可能该卡卷已经被注销,请您刷新页面后再重试', "payload": None})
  4043. vCard.openIds.remove(openId)
  4044. try:
  4045. vCard.save()
  4046. except Exception as e:
  4047. logger.info('save sharing card error=%s' % e)
  4048. return JsonResponse({"result": 0, "description": u'保存卡的信息异常,请您重试', "payload": None})
  4049. return JsonResponse({"result": 1, "description": '', "payload": None})
  4050. @permission_required(ROLE.myuser)
  4051. def stopService(request):
  4052. # type: (WSGIRequest)->JsonResponse
  4053. payload = json.loads(request.body)
  4054. logicalCode = payload.get('logicalCode')
  4055. port = payload.get('port', None)
  4056. dev = Device.get_dev_by_l(logicalCode)
  4057. box = ActionDeviceBuilder.create_action_device(dev)
  4058. try:
  4059. box.stop(port)
  4060. except ServiceException, e:
  4061. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  4062. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  4063. @permission_required(ROLE.myuser)
  4064. def toggleDeviceStatus(request):
  4065. # type: (WSGIRequest)->JsonResponse
  4066. payload = json.loads(request.body)
  4067. logicalCode = payload.get('logicalCode')
  4068. port = payload.get('chargeIndex', None)
  4069. isContinue = False if payload.get('targetStatus', None) == 'pause' else True
  4070. dev = Device.get_dev_by_l(logicalCode)
  4071. box = ActionDeviceBuilder.create_action_device(dev)
  4072. try:
  4073. result = box.pause(request.user.openId, isContinue, port)
  4074. return JsonResponse({'result': 1, 'description': '', 'payload': result})
  4075. except ServiceException, e:
  4076. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  4077. @permission_required(ROLE.myuser)
  4078. def getDeviceSellItems(request):
  4079. payload = json.loads(request.body)
  4080. logicalCode = payload.get('logicalCode')
  4081. objs = Cell.objects.filter(logicalCode = logicalCode, itemStatus = 'full')
  4082. dataList = [{
  4083. 'cellNo': obj.cellNo, 'boardNo': obj.boardNo,
  4084. 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle,
  4085. 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl,
  4086. 'itemPrice': obj.itemPrice
  4087. } for obj in objs]
  4088. return JsonResponse({'result': 1, 'description': '', 'payload': {'dataList': dataList}})
  4089. @permission_required(ROLE.myuser)
  4090. def getDeviceCells(request):
  4091. logicalCode = request.GET.get('logicalCode')
  4092. objs = Cell.objects.filter(logicalCode = logicalCode)
  4093. dev = Device.get_dev_by_logicalCode(logicalCode)
  4094. box = ActionDeviceBuilder.create_action_device(dev)
  4095. lockStatusDict = box.get_all_lock_status()
  4096. dataList = [{'id': str(obj.id), 'cellNo': obj.cellNo, 'boardNo': obj.boardNo,
  4097. 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle,
  4098. 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl,
  4099. 'itemPrice': round(obj.itemPrice / 100.0, 2), 'lockStatus': lockStatusDict.get(obj.cellNo, 'close')}
  4100. for obj in objs if (lockStatusDict.get(obj.cellNo, 'close') == 'close' and obj.itemStatus != 'empty')]
  4101. return JsonResponse({'result': 1, 'description': '', 'payload': {'dataList': dataList}})
  4102. @permission_required(ROLE.myuser)
  4103. def updateUserActiveInfo(request):
  4104. """
  4105. 安骑换电用户 的身份信息上传接口
  4106. 需要信息 手机验证码 手机号码 身份验证信息 推荐人信息(非必须)
  4107. 推荐人
  4108. # 新添加了字段 phoneNumber
  4109. """
  4110. user = request.user # type: MyUser
  4111. if user.is_product_user():
  4112. return JsonErrorResponse(u"请先扫描设备")
  4113. active_info = MyUser.get_active_info(user.openId, agentId = user.agentId)
  4114. if active_info and active_info.get("isMember"):
  4115. return JsonErrorResponse(u"您已经完成实名认证,请勿重复")
  4116. payload = json.loads(request.body)
  4117. code = payload.get("code", "")
  4118. phoneNumber = payload.get("phoneNumber", "")
  4119. imgList = payload.get("imgList", [])
  4120. recommender = payload.get("recommender", "")
  4121. if phoneNumber:
  4122. if MyUser.objects.filter(
  4123. Q(phoneNumber = phoneNumber),
  4124. Q(agentId = request.user.agentId) | Q(productAgentId = request.user.productAgentId)
  4125. ):
  4126. return JsonErrorResponse(description = u"手机号码已经被注册!")
  4127. # 推荐人如果填写必须有效 并且非本人 并且激活
  4128. if recommender:
  4129. if not MyUser.objects.filter(
  4130. Q(phoneNumber = recommender),
  4131. Q(agentId = request.user.agentId) | Q(productAgentId = request.user.productAgentId)
  4132. ) or recommender == phoneNumber:
  4133. return JsonErrorResponse(u"无效的推荐人")
  4134. status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code)
  4135. if not status:
  4136. return JsonErrorResponse(msg)
  4137. MyUser.set_active_info(
  4138. {"phoneNumber": phoneNumber,
  4139. "imgList": imgList,
  4140. "recommender": recommender,
  4141. "status": 1,
  4142. "createdTime": datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S")
  4143. },
  4144. openId = user.openId,
  4145. agentId = user.agentId,
  4146. groupId = user.groupId
  4147. )
  4148. return JsonOkResponse()
  4149. @permission_required(ROLE.myuser)
  4150. def getUserActiveInfo(request):
  4151. user = request.user
  4152. active_info = MyUser.get_active_info(user.openId, agentId = user.agentId)
  4153. status = active_info.get("status", "")
  4154. payload = {
  4155. "id": user.id,
  4156. "identifyUrl": active_info.get("identifyUrl", ""),
  4157. "recommender": active_info.get("recommender", ""),
  4158. "phoneNumber": active_info.get("phoneNumber", ""),
  4159. "status": status if status else 0,
  4160. "remarks": active_info.get("remarks", "")
  4161. }
  4162. return JsonResponse({"result": 1, "description": '', "payload": payload})
  4163. @permission_required(ROLE.myuser)
  4164. def getTelVerifyInfo(request):
  4165. user = request.user
  4166. status = 1 if user.phone else 0
  4167. return JsonResponse({"result": 1, "description": "", "payload": {"status": status}})
  4168. @permission_required(ROLE.myuser)
  4169. def updateTelVerifyInfo(request):
  4170. """
  4171. 绑定手机号码. 手机号码只是做为属性, 谁能获取验证码, 手机号码就是谁的
  4172. """
  4173. user = request.user
  4174. jsonData = json.loads(request.body)
  4175. phoneNumber = jsonData.get("phoneNumber", "")
  4176. code = jsonData.get("code", "")
  4177. # 首先校验 短信验证码
  4178. status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code)
  4179. if not status:
  4180. return JsonErrorResponse(msg)
  4181. try:
  4182. user.phone = phoneNumber
  4183. except Exception as e:
  4184. logger.exception(e)
  4185. return JsonErrorResponse(description=u"手机号码绑定失败,请刷新重试")
  4186. return JsonOkResponse(description=u"绑定成功")
  4187. @permission_required(ROLE.myuser)
  4188. def sendActiveSmsCode(request):
  4189. """
  4190. 安骑换电用户 获取手机验证码 手机号码
  4191. """
  4192. user = request.user
  4193. payload = json.loads(request.body)
  4194. phoneNumber = payload.get("phoneNumber", "")
  4195. # phoneNumber 唯一
  4196. checkUser = MyUser.objects.filter(
  4197. Q(phoneNumber = phoneNumber),
  4198. Q(agentId = request.user.agentId) | Q(productAgentId = request.user.productAgentId)
  4199. ).first()
  4200. if checkUser and checkUser.gateway == user.gateway:
  4201. return JsonErrorResponse(u"该号码已经被注册")
  4202. agent = Agent.objects.get(id = user.agentId)
  4203. status, msg = userMobileVerifySMSProvider.get(phoneNumber = phoneNumber,
  4204. productName = agent.productName,
  4205. vendor = SysParas.get_sms_vendor(request.user.smsVendor),
  4206. openId = user.openId)
  4207. if not status:
  4208. return JsonErrorResponse(description = msg)
  4209. else:
  4210. return JsonOkResponse()
  4211. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'上传身份文件图片存储失败,请重新试试'))
  4212. @permission_required(ROLE.myuser)
  4213. def UploadIdentify(request):
  4214. """
  4215. 用户上传身份验证
  4216. """
  4217. files = request.FILES.getlist('file')
  4218. if not len(files):
  4219. return JsonResponse({'result': 0, 'description': u'未知的身份文件信息,请重新试试', 'payload': {}})
  4220. uploader = AliOssFileUploader(inputFile = request.FILES.getlist('file')[0], uploadType = 'identify')
  4221. logger.info('[uploadItemPic] %s is being used' % (repr(uploader),))
  4222. try:
  4223. outputUrl = uploader.upload()
  4224. return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl})
  4225. except InvalidFileSize, e:
  4226. logger.info(
  4227. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  4228. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  4229. except InvalidFileName, e:
  4230. logger.info(
  4231. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  4232. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  4233. @permission_required(ROLE.myuser)
  4234. def UserActiveIntercepter(request):
  4235. """
  4236. 安骑用户 拦截器 身份认证未通过的用户
  4237. """
  4238. user = request.user
  4239. active_info = MyUser.get_active_info(openId = user.openId, agentId = user.agentId)
  4240. isMember = active_info.get("isMember", False)
  4241. return JsonOkResponse(payload = {"isMember": int(isMember)})
  4242. @permission_required(ROLE.myuser)
  4243. def DeviceTrack(request):
  4244. """
  4245. 电池电压、位置信息 存在位置信息
  4246. """
  4247. # TODO 数据库分库整改
  4248. # 获取用户的最后一次serverProcess 从中获取用户电池的IMEI
  4249. # API查询电池信息
  4250. # 返回信息
  4251. user = request.user
  4252. active_info = MyUser.get_active_info(openId = user.openId, agentId = user.agentId)
  4253. status = active_info.get("status", 0)
  4254. if status != 2: # 完成身份认证的用户状态是2
  4255. return JsonErrorResponse(u"请先完成身份认证信息")
  4256. # 找出换电柜的使用记录 并且拿到的电池的编号不为-1
  4257. record = ConsumeRecord.objects.filter(
  4258. openId = user.openId,
  4259. servicedInfo__newBatteryImei__exists = True,
  4260. servicedInfo__newBatteryImei__ne = "-1"
  4261. ).order_by("-dateTimeAdded").first()
  4262. if not record:
  4263. return JsonErrorResponse(u"未获取到有效电池信息")
  4264. battery = record.servicedInfo.get("newBatteryImei")
  4265. try:
  4266. result = batteryInfo(battery)
  4267. except Exception as e:
  4268. logger.info("get battery info error ,reason is : %s" % e)
  4269. return JsonErrorResponse(u"网络故障,获取电池信息失败")
  4270. batInfo = result.get(battery)
  4271. if not batInfo:
  4272. return JsonErrorResponse(u"电池编号错误")
  4273. lng = batInfo.get("lng")
  4274. lat = batInfo.get("lat")
  4275. lng, lat = coordinateHandler(lng, lat)
  4276. payload = {
  4277. "total": 1,
  4278. "items": [
  4279. {
  4280. "lng": lng,
  4281. "lat": lat,
  4282. "remarks": u"当前电池电压信息是%s" % batInfo.get("voltage"),
  4283. }
  4284. ]
  4285. }
  4286. return JsonOkResponse(payload = payload)
  4287. @error_tolerate(logger=logger)
  4288. @permission_required(ROLE.myuser)
  4289. # @ServerSwitch.payment_switch('系统维护升级中,请稍后重试')
  4290. def payGateway(request):
  4291. # type: (WSGIRequest)->HttpResponse
  4292. """
  4293. 用户请求充值
  4294. 两层机制保证订单不被重复处理。
  4295. 1、用户订单创建后,在cache塞一个值为0的key;在收到回调或者查询到状态后,对这个key加1。如果返回新值为2则代表已经有处理过。
  4296. 2、如果cache失效,那么返回值为None。这个时候需要判断RechargeRecord的update结果,如果有修改,则代表没处理;否则已经处理过
  4297. :param request:
  4298. :return:
  4299. """
  4300. from apps.web.common.transaction.pay import PayPullUpFactoryIntf
  4301. class PayPullUpFactory(PayPullUpFactoryIntf):
  4302. @classmethod
  4303. def create_by_alipay(cls, payment_gateway, payParam, record):
  4304. current_user = payParam.curUser
  4305. open_id = current_user.get_bound_pay_openid(payment_gateway.bound_openid_key)
  4306. pull_up_cls = PayManager().get_pull_up(payment_gateway.pay_app_type)
  4307. return pull_up_cls(open_id, payment_gateway, record, **{
  4308. 'showAd': payParam.showAd,
  4309. 'notifyUrl': PAY_NOTIFY_URL.ALI_PAY_BACK
  4310. })
  4311. @classmethod
  4312. def create_by_wechat(cls, payment_gateway, payParam, record):
  4313. current_user = payParam.curUser
  4314. open_id = current_user.get_bound_pay_openid(payment_gateway.bound_openid_key)
  4315. from pprint import pprint
  4316. pprint(open_id)
  4317. pull_up_cls = PayManager().get_pull_up(payment_gateway.pay_app_type)
  4318. return pull_up_cls(open_id, payment_gateway, record, **{
  4319. 'showAd': payParam.showAd,
  4320. 'notifyUrl': PAY_NOTIFY_URL.WECHAT_PAY_BACK
  4321. })
  4322. @classmethod
  4323. def create(cls, payment_gateway, record, **payload):
  4324. payParam = payload.get('payParam')
  4325. if payment_gateway.pay_app_type == PayAppType.ALIPAY:
  4326. return cls.create_by_alipay(payment_gateway, payParam, record)
  4327. elif payment_gateway.pay_app_type == PayAppType.WECHAT:
  4328. return cls.create_by_wechat(payment_gateway, payParam, record)
  4329. else:
  4330. raise UserServerException(u'不支持的支付方式')
  4331. try:
  4332. logger.info('----{user} unified order----'.format(user=repr(request.user)))
  4333. payParam = PayParam(request) # type: PayParam
  4334. payParam.call_check()
  4335. payment_gateway = payParam.payGateway
  4336. if not payment_gateway:
  4337. raise UserServerException(u'第三方支付配置错误,请联系平台客服(1001)')
  4338. record = BUILDER_MAP.get(payParam.recordBuilderKey)(payParam) # type: RechargeRecord
  4339. from apps.web.common.transaction.pay import PayPullUp
  4340. pull_up = PayPullUp.create(PayPullUpFactory, payment_gateway, record, **{'payParam': payParam})
  4341. response = pull_up.do()
  4342. if 'startKey' in payParam.attachParas:
  4343. set_start_key_status(payParam.attachParas['startKey'], START_DEVICE_STATUS.PAYING)
  4344. return response
  4345. except InterceptException as e:
  4346. logger.debug(e.redirect)
  4347. return JsonResponse({
  4348. 'result': ErrorCode.LOGIN_VERIFY,
  4349. 'payload': {
  4350. 'redirect': e.redirect
  4351. }
  4352. })
  4353. except ServiceException as e:
  4354. logger.error(str(e))
  4355. return JsonResponse(e.result)
  4356. except UserServerException as e:
  4357. logger.error(e.message)
  4358. return JsonErrorResponse(e.message)
  4359. except AliException as e:
  4360. logger.error(str(e))
  4361. return JsonErrorResponse(description=e.message)
  4362. except Exception as e:
  4363. logger.exception(e)
  4364. return JsonErrorResponse(description=u'系统错误,请重试')
  4365. finally:
  4366. logger.info('----{user} unified order over----'.format(user=repr(request.user)))
  4367. @error_tolerate(logger = logger)
  4368. @permission_required(ROLE.myuser)
  4369. def setMyUserDetail(request):
  4370. user = request.user # type: MyUser
  4371. payload = json.loads(request.body)
  4372. ownerId = payload.pop('ownerId')
  4373. MyUserDetail.objects(openId = str(user.openId), dealerId = str(ownerId)).upsert_one(
  4374. openId = str(user.openId), dealerId = str(ownerId),
  4375. userName = payload.get('userName'), userPhone = payload.get('userPhone'),
  4376. userUnit = payload.get('userUnit'), userFloor = payload.get('userFloor'),
  4377. userRoom = payload.get('userRoom'))
  4378. return JsonResponse({'result': 1, 'description': 'SUCCESS', 'payload': {}})
  4379. @error_tolerate(logger = logger)
  4380. def payNotify(request, pay_app_type):
  4381. # type: (WSGIRequest, str)->JsonResponse
  4382. if pay_app_type == PayAppType.ALIPAY:
  4383. payload = request.POST.dict()
  4384. if 'refund_fee' in payload and 'gmt_refund' in payload:
  4385. notifier_cls = RefundManager().get_notifier(pay_app_type)
  4386. return notifier_cls(request, lambda order_no: RefundMoneyRecord.get_record(order_no)).do(refund_post_pay)
  4387. recharge_cls_factory = lambda order_no: RechargeRecord
  4388. notifier_cls = PayManager().get_notifier(pay_app_type = pay_app_type)
  4389. return notifier_cls(request, recharge_cls_factory).do(post_pay)
  4390. @permission_required(ROLE.myuser)
  4391. def getFavoriteDevice(request):
  4392. pageIndex = int(request.GET.get('pageIndex', 1))
  4393. pageSize = int(request.GET.get('pageSize', 10))
  4394. devNoList = request.user.collectedDeviceList
  4395. devs = Device.get_dev_by_nos(devNoList, verbose = True)
  4396. dataList = []
  4397. for dev in devs.values():
  4398. dev.update({'type': dev['devType'].get('name', '')})
  4399. dataList.append(dev)
  4400. return JsonOkResponse(
  4401. payload = {'total': len(dataList), 'items': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]})
  4402. @permission_required(ROLE.myuser)
  4403. def deleteFavoriteDevice(request):
  4404. payload = json.loads(request.body)
  4405. lcCodes = payload['logicalCodeList']
  4406. removeList = set()
  4407. for lcCode in lcCodes:
  4408. devNo = Device.get_devNo_by_logicalCode(lcCode)
  4409. removeList.add(devNo)
  4410. devNolist = set(request.user.collectedDeviceList)
  4411. request.user.collectedDeviceList = list(devNolist - removeList)
  4412. return JsonOkResponse()
  4413. @permission_required(ROLE.myuser)
  4414. def addFavoriteDevice(request):
  4415. payload = json.loads(request.body)
  4416. isFavorite = payload['favorite']
  4417. lcCode = payload['logicalCode']
  4418. devNo = Device.get_devNo_by_logicalCode(lcCode)
  4419. collectedDeviceList = request.user.collectedDeviceList
  4420. if isFavorite:
  4421. if devNo not in collectedDeviceList:
  4422. collectedDeviceList.append(devNo)
  4423. request.user.collectedDeviceList = collectedDeviceList
  4424. else:
  4425. return JsonOkResponse(description = u'该设备已经收藏啦')
  4426. else:
  4427. if devNo in collectedDeviceList:
  4428. collectedDeviceList.remove(devNo)
  4429. request.user.collectedDeviceList = collectedDeviceList
  4430. else:
  4431. return JsonOkResponse(description = u'该设备已经取消收藏啦')
  4432. return JsonOkResponse()
  4433. # 检查是否需要弹出加粉界面。1、需要获取监督号的openId。2、检查是否需要弹出加粉界面
  4434. # 监督号的入口也需要调用此函数,目的是找到客户应该登录的agentId。
  4435. @permission_required(ROLE.myuser)
  4436. def moniUserAccess(request):
  4437. logger.info('receive moniUserAccess')
  4438. # 目前只支持微信加粉
  4439. try:
  4440. href = request.GET.get('redirect')
  4441. moniAppId = request.GET.get('moniAppId', None)
  4442. if moniAppId is None:
  4443. agent = Agent.objects.get(id = request.user.agentId)
  4444. moniApp = agent.get_online_moni_app()
  4445. if not moniApp:
  4446. return ErrorResponseRedirect(error = cn(u'请您刷新下页面,重新点击试试'))
  4447. else:
  4448. try:
  4449. moniApp = MoniApp.get_collection().find({'appId': moniAppId})[0]
  4450. except Exception, e:
  4451. return ErrorResponseRedirect(error = cn(u'建议您从扫码页面关注公众号,这样才可以使用此公众号的服务哦'))
  4452. # 返回跳转页面
  4453. state = MoniUserAuthState(appId = moniApp['appId'], openId = request.user.openId, href = href)
  4454. wechatApp = WechatAuthApp(appid = moniApp['appId'], secret = moniApp['secret'])
  4455. bridge = WechatAuthBridge(wechatApp)
  4456. return ExternalResponseRedirect(
  4457. bridge.generate_auth_url_base_scope(redirect_uri = USER_AUTH_REDIRECT_URL.MONI_BASE,
  4458. payload = state.encode()))
  4459. except Exception, e:
  4460. logger.exception(e)
  4461. return ErrorResponseRedirect(error = cn(u'系统开小差了~~~,请您刷新下页面,重新点击试试'))
  4462. @permission_required(ROLE.myuser)
  4463. def checkPoint(request):
  4464. logger.info('checkPoint,receive,user openId=%s' % request.user.openId)
  4465. # 目前只支持微信加粉
  4466. if (not detect_wechat_client(request)):
  4467. logger.info('checkPoint,it is not wechat client')
  4468. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4469. try:
  4470. point = request.GET.get('point')
  4471. logicalCode = request.GET.get('logicalCode')
  4472. dev = Device.get_dev_by_logicalCode(logicalCode)
  4473. dealer = Dealer.objects(id = dev['ownerId']).get()
  4474. logger.info('checkPoint,user openId=%s,logicalCode=%s' % (request.user.openId, logicalCode))
  4475. # 检查经销商和代理商的开关
  4476. if dealer.moniAppCheckPointDict.has_key(point) and (not dealer.moniAppCheckPointDict[point]):
  4477. logger.info('checkPoint,moniappcheck point dealer is off,point')
  4478. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4479. agent = Agent.objects(id = dealer.agentId).get()
  4480. if agent.moniAppCheckPointDict.has_key(point) and (not agent.moniAppCheckPointDict[point]):
  4481. logger.info('checkPoint,moniappcheck point agent is off')
  4482. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4483. moniApp = agent.get_online_moni_app()
  4484. if not moniApp:
  4485. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4486. rcds = MoniUser.objects.filter(openId = request.user.openId, moniAppId = moniApp['appId'])
  4487. if rcds.count() == 0: # 一条记录都没有是,说明没有拿到对应数据
  4488. logger.info('checkPoint,can not find moniuser')
  4489. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4490. else:
  4491. moniUser = rcds.first()
  4492. if moniUser.isSubscribe:
  4493. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4494. else: # 如果没关注,可能存在用户通过其他手段提前关注了,要多重检查下
  4495. app = WechatAuthApp(appid = moniApp['appId'], secret = moniApp['secret'])
  4496. proxy = WechatClientProxy(app)
  4497. isSubGzh = proxy.is_subscribe_gzh(moniUser['moniOpenId'])
  4498. if isSubGzh:
  4499. moniUser.isSubscribe = True
  4500. moniUser.subPoint = point
  4501. moniUser.subLogicalCode = logicalCode
  4502. moniUser.subDealerId = str(dealer.id)
  4503. moniUser.subAgentId = str(agent.id)
  4504. moniUser.save()
  4505. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4506. else:
  4507. moniUser.subPoint = point
  4508. moniUser.subLogicalCode = logicalCode
  4509. moniUser.subDealerId = str(dealer.id)
  4510. moniUser.subAgentId = str(agent.id)
  4511. moniUser.save()
  4512. return JsonOkResponse(
  4513. payload = {'addFans': True, 'qrCode': moniApp['qrCode'], 'title': moniApp['title'],
  4514. 'desc': moniApp['desc']})
  4515. except Exception, e:
  4516. return JsonOkResponse(payload = {'addFans': False, 'qrCode': ''})
  4517. @permission_required(ROLE.myuser)
  4518. def isNeedAccessMoniApp(request):
  4519. logger.info('receive isNeedAccessMoniApp')
  4520. if (not detect_wechat_client(request)):
  4521. return JsonOkResponse(payload = {'isNeed': False})
  4522. try:
  4523. agent = Agent.objects(id = request.user.agentId).get()
  4524. # 如果代理商支持强制关注公众号,而且用户一天内才创建进来,为了体验好一点,这次就不要弹窗了
  4525. if agent.forceFollowGzh and (datetime.datetime.now() - request.user.dateTimeAdded).total_seconds() < 24 * 60 * 60:
  4526. return JsonOkResponse(payload = {'isNeed': False})
  4527. # 如果这个用户已经订阅了某个监督号,就直接返回
  4528. moniApp = agent.get_online_moni_app()
  4529. if not moniApp:
  4530. return JsonOkResponse(payload = {'isNeed': False})
  4531. moniUserCount = MoniUser.objects.filter(openId = request.user.openId, moniAppId = moniApp['appId']).count()
  4532. if moniUserCount == 0:
  4533. return JsonOkResponse(payload = {'isNeed': True})
  4534. return JsonOkResponse(payload = {'isNeed': False})
  4535. except Exception, e:
  4536. return JsonOkResponse(payload = {'isNeed': False})
  4537. @permission_required(ROLE.myuser)
  4538. def getComplaintList(request):
  4539. pageIndex = int(request.GET.get('pageIndex', 1))
  4540. pageSize = int(request.GET.get('pageSize', 10))
  4541. objs = Complaint.objects.filter(openId = request.user.openId)
  4542. dataList = []
  4543. total = objs.count()
  4544. for obj in objs.paginate(pageIndex = pageIndex, pageSize = pageSize):
  4545. dataList.append({
  4546. 'id': str(obj.id),
  4547. 'logicalCode': obj.logicalCode,
  4548. 'createdTime': obj.dateTimeAdded.strftime(Const.DATETIME_FMT),
  4549. 'handledTime': obj.handledTime.strftime(Const.DATETIME_FMT),
  4550. 'handledStatus': obj.handledStatus,
  4551. 'groupName': obj.groupName,
  4552. 'reason': obj.reason
  4553. })
  4554. return JsonOkResponse(payload = {'total': total, 'dataList': dataList})
  4555. def submitComplaint(request):
  4556. payload = json.loads(request.body)
  4557. # 首先产生一条投诉记录
  4558. logicalCode = payload.get('logicalCode')
  4559. orderNo = payload.get('orderNo')
  4560. reason = payload.get('reason')
  4561. order = ConsumeRecord.objects.get(orderNo = orderNo)
  4562. if order.logicalCode != logicalCode:
  4563. return JsonErrorResponse(description = u'设备的编码填写错误,请您检查下哦')
  4564. if Complaint.objects.filter(orderNo = orderNo).count() > 0:
  4565. return JsonErrorResponse(description = u'该订单已经投诉成功,不需要您重复投诉了哦')
  4566. newObj = Complaint(
  4567. openId = request.user.openId,
  4568. logicalCode = logicalCode,
  4569. groupName = order.groupName,
  4570. orderNo = orderNo,
  4571. reason = reason
  4572. )
  4573. newObj.save()
  4574. # 然后通知经销商
  4575. newMsg = DealerMessage(
  4576. ownerId = order.ownerId,
  4577. fromUser = u'系统平台',
  4578. messageType = 'complaint',
  4579. title = u'客户投诉',
  4580. desc = u'平台收到客户的投诉,请您尽快处理,如果收到投诉过多,系统会提醒设备用户,甚至禁用此设备。地址:%s,设备:%s,投诉原因:%s' % (
  4581. order.groupName, logicalCode, reason),
  4582. relatedInfo = {'complaintId': str(newObj.id)}
  4583. )
  4584. newMsg.save()
  4585. return JsonOkResponse()
  4586. @permission_required(ROLE.myuser)
  4587. @request_limit_by_user(operation='queryServicePhone', limit=10, period=2 * 60 * 60, logger=None)
  4588. def queryServicePhone(request):
  4589. """
  4590. 根据订单查询客服电话
  4591. :param request:
  4592. :return:
  4593. """
  4594. logicalCode = request.GET.get('logicalCode')
  4595. dealerIds = MyUser.get_dealer_ids(openId = request.user.openId, productAgentId = request.user.productAgentId)
  4596. device = Device.get_dev_by_logicalCode(logicalCode) # type: DeviceDict
  4597. if not device or device.ownerId not in dealerIds:
  4598. return JsonOkResponse(payload={})
  4599. if not device.owner:
  4600. logger.error('dealer<id={}> not exists.'.format(device.ownerId))
  4601. return JsonOkResponse(payload={})
  4602. return JsonOkResponse(payload=({'phone': device.owner.service_phone}))
  4603. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  4604. @permission_required(ROLE.myuser)
  4605. def getAllFeature(request):
  4606. agent = Agent.objects.get(id = request.user.agentId)
  4607. if agent is None:
  4608. return JsonErrorResponse(description = u'代理商不存在')
  4609. else:
  4610. return JsonOkResponse(payload = {_: True for _ in agent.features})
  4611. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  4612. @permission_required(ROLE.myuser)
  4613. def queryCardNo(request):
  4614. logicalCode = request.GET.get('logicalCode')
  4615. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  4616. if devNo is None:
  4617. return JsonErrorResponse(description = u'未识别的设备编号')
  4618. cardNo = Card.get_dev_card_no(devNo)
  4619. if cardNo is None:
  4620. return JsonOkResponse(payload = {'cardNo': ''})
  4621. return JsonOkResponse(payload = {'cardNo': cardNo})
  4622. @error_tolerate(nil = JsonErrorResponse(description = u'系统错误'), logger = logger)
  4623. @permission_required(ROLE.myuser)
  4624. def prepareScanCard(request):
  4625. logicalCode = request.GET.get('logicalCode')
  4626. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  4627. if devNo is None:
  4628. return JsonErrorResponse(description = u'未识别的设备编号')
  4629. Card.clear_dev_card_no(devNo)
  4630. return JsonOkResponse()
  4631. @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger)
  4632. @permission_required(ROLE.myuser)
  4633. def checkUserConsumeOrder(request):
  4634. logicalCode = request.GET.get("logicalCode")
  4635. dev = Device.get_dev_by_logicalCode(logicalCode)
  4636. if not dev:
  4637. return JsonErrorResponse(u"未找到设备,请扫码重试")
  4638. box = ActionDeviceBuilder.create_action_device(dev)
  4639. if not hasattr(box, "check_user_consume_order"):
  4640. return JsonOkResponse()
  4641. status = box.check_user_consume_order()
  4642. return JsonResponse({"result": status})
  4643. @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger)
  4644. @permission_required(ROLE.myuser)
  4645. def preJudgment(request):
  4646. """
  4647. 这个接口 无论如何不能抛出异常 前台规定
  4648. :param request:
  4649. :return:
  4650. """
  4651. logicalCode = request.GET.get("logicalCode")
  4652. dev = Device.get_dev_by_logicalCode(logicalCode)
  4653. if not dev:
  4654. return JsonErrorResponse(u"该设备不存在")
  4655. order = get_user_not_complete_order(request.user, dev.owner)
  4656. # 正常结果下的返回
  4657. if not order:
  4658. return JsonOkResponse()
  4659. if order.status == order.Status.RUNNING:
  4660. return JsonResponse({"result": ErrorCode.ORDER_RUNNING, "description": u"您有一笔正在进行的订单",
  4661. "payload": {'ownerId': order.ownerId, "orderId": str(order.id)}})
  4662. elif not order.isPaid:
  4663. return JsonResponse({"result": ErrorCode.ORDER_NEED_PAY, "description": u"你有一笔尚未支付的订单,请先完成支付,然后在使用设备",
  4664. "payload": {'ownerId': order.ownerId, "orderId": str(order.id)}})
  4665. # elif order.is_waitPay():
  4666. # return JsonResponse({"result": ErrorCode.ORDER_PAYING, "description": u"正在检查支付结果,请稍后",
  4667. # "payload": {'ownerId': order.ownerId, "orderId": str(order.id)}})
  4668. else:
  4669. return JsonResponse({"result": "2", "description": u"系统错误,请您稍后重试"})
  4670. @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger)
  4671. @permission_required(ROLE.myuser)
  4672. def getCardBindUserStatus(request):
  4673. user = request.user
  4674. status = 1 if user.extra.get('campus_user_num', '') else 0
  4675. return JsonResponse({"result": 1, "description": "", "payload": {"status": status}})
  4676. @error_tolerate(nil = JsonErrorResponse("系统错误"), logger = logger)
  4677. @permission_required(ROLE.myuser)
  4678. def updateCardBindUserInfo(request):
  4679. user = request.user
  4680. jsonData = json.loads(request.body)
  4681. phoneNumber = str(jsonData.get("phoneNumber", "").strip())
  4682. code = jsonData.get("code", "")
  4683. campus_user_num = str(jsonData.get('userNo').strip())
  4684. userName = str(jsonData.get('userName').strip())
  4685. from apps.web.eventer.caiyi import config_dic
  4686. # 测试白名单
  4687. test_card = serviceCache.get('yc-num-{}'.format(campus_user_num))
  4688. if test_card:
  4689. userName = 'test'
  4690. campus_user_num = 'test001'
  4691. logger.debug('yc_test_card,to reg card!!!')
  4692. res = {'factoryFixId': '757996699'}
  4693. else:
  4694. # TODO 去服务器验证人员编号和手机号是否吻合
  4695. yc = YuChuanApi(**config_dic)
  4696. try:
  4697. res = yc.sql_get_user_info(campus_user_num)
  4698. user_phone = base64.encodestring(phoneNumber + '.00').strip()
  4699. if res['mobilePhone'] != user_phone or res['userName'] != userName:
  4700. return JsonErrorResponse(description = u'一卡通信息填写错误~,请您检查下哦')
  4701. except Exception as e:
  4702. return JsonErrorResponse(description = u'一卡通信息填写错误!!!,请您检查下哦')
  4703. card_no = str(res.get('factoryFixId')).replace('L', '')
  4704. if not card_no:
  4705. raise UserServerException(u'一卡通信息填写错误!!')
  4706. status, msg = userMobileVerifySMSProvider.verify(phoneNumber, code)
  4707. if not status:
  4708. return JsonErrorResponse(msg)
  4709. dic = {
  4710. "card_dealer": "宇川智能平台一卡通",
  4711. "campus_user_num": campus_user_num,
  4712. }
  4713. card = Card.objects.filter(cardNo = card_no, cardType = 'YuChuanCard').first() or Card.objects.create(
  4714. cardNo = card_no, agentId = user.agentId, phone = phoneNumber, remarks = '宇川一卡通',
  4715. productAgentId = user.productAgentId, cardName = userName, attachParas = dic, cardType = 'YuChuanCard',
  4716. nickName = user.nickname, openId = user.openId)
  4717. if card.openId == card_no or card.openId != user.openId: # 判断是否为刷卡注册入库,或则换微信绑定
  4718. card.openId = user.openId
  4719. card.nickName = user.nickname
  4720. card.phone = phoneNumber
  4721. card.save()
  4722. dic['card_no'] = card_no
  4723. user.phoneNumber = phoneNumber
  4724. user.extra = dic
  4725. user.save()
  4726. return JsonResponse({"result": 1, "description": "", "payload": {"status": 1}})
  4727. @error_tolerate(logger = logger, nil = JsonErrorResponse(description = u"获取卡金额失败"))
  4728. @permission_required(ROLE.myuser)
  4729. def getRemoteCardBalance(request):
  4730. """
  4731. 获取远程充值卡的金额
  4732. :param request:
  4733. :return:
  4734. """
  4735. logicalCode = request.GET.get("logicalCode")
  4736. dev = Device.get_dev_by_l(logicalCode)
  4737. if not dev:
  4738. return JsonErrorResponse(description = u"请先扫描设备")
  4739. box = ActionDeviceBuilder.create_action_device(dev)
  4740. if not hasattr(box, "get_remote_card_balance"):
  4741. return JsonErrorResponse(description = u"当前设备暂不支持充值卡")
  4742. try:
  4743. result = box.get_remote_card_balance()
  4744. except ServiceException as e:
  4745. return JsonErrorResponse(description = e.message.get("description"))
  4746. res = result.get("res")
  4747. if res == "02":
  4748. return JsonErrorResponse(description = u"请先将卡片置于设备上")
  4749. # 这个地方将用户的信息塞入进去
  4750. user = request.user
  4751. result.update({
  4752. "avatarUrl": user.avatar,
  4753. "openId": user.openId
  4754. })
  4755. # 然后再次塞入设备信息
  4756. result.update({
  4757. "devNo": dev.devNo,
  4758. "groupId": dev.groupId
  4759. })
  4760. packages = dev.get("washConfig", dict())
  4761. newPackages = list()
  4762. for _id, item in packages.items():
  4763. switch = item.get("switch", True)
  4764. if not switch:
  4765. continue
  4766. newPackages.append({
  4767. "id": _id,
  4768. "payAmount": item.get("price"),
  4769. "coins": item.get("coins")
  4770. })
  4771. result.update({"packages": newPackages})
  4772. return JsonOkResponse(payload = result)
  4773. @error_tolerate(logger = logger, nil = JsonOkResponse())
  4774. @permission_required(ROLE.myuser)
  4775. def getUserDisclaimer(request):
  4776. """
  4777. 获取用户的免责声明
  4778. 用户 用户进入系统第一次的时候需要阅读此协议并且 明确表示阅读 否则展示界面给用户
  4779. :param request:
  4780. :return:
  4781. """
  4782. productAgentId = request.user.productAgentId
  4783. disclaimer = Agent.get_disclaimer(productAgentId)
  4784. # 当用户阅读的声明版本与当前免责代理商的版本不一致 并且代理商的免责声明内容不为空的时候 前台需要展示免责声明
  4785. payload = {
  4786. "version": disclaimer.version,
  4787. "content": disclaimer.content
  4788. }
  4789. if not disclaimer.content:
  4790. payload = {}
  4791. return JsonOkResponse(payload = payload)
  4792. @error_tolerate(logger = logger, nil = JsonOkResponse())
  4793. @permission_required(ROLE.myuser)
  4794. def pauseUsingDevice(request):
  4795. payload = json.loads(request.body)
  4796. logicalCode = payload.get('logicalCode', '')
  4797. if logicalCode == '':
  4798. return JsonErrorResponse(description = u'参数错误(没有逻辑码)')
  4799. port = payload.get('chargeIndex', '')
  4800. if port == '':
  4801. return JsonErrorResponse(description = u'参数错误(没有端口号)')
  4802. dev = Device.get_dev_by_l(logicalCode)
  4803. portCache = Device.get_dev_control_cache(dev['devNo'])[str(port)]
  4804. if dev['devType']['code'] in ['1002121', '1002122']:
  4805. if portCache.get('pausePort', False) is True:
  4806. oper = '01'
  4807. else:
  4808. oper = '02'
  4809. else:
  4810. oper = '00'
  4811. smartBox = ActionDeviceBuilder.create_action_device(dev)
  4812. try:
  4813. smartBox.pauseToUseDevice(port, oper)
  4814. except Exception as e:
  4815. return JsonErrorResponse(description = u'操作失败')
  4816. return JsonOkResponse()
  4817. @error_tolerate(logger = logger, nil = ErrorResponseRedirect(error = u'微信授权失败,请刷新后重试'))
  4818. @permission_required(ROLE.myuser)
  4819. def gatewayEntry(request):
  4820. """
  4821. 再发起支付之前 获取一次用户的 payOpenId 然后重定向到用户的支付详情页面 并直接访问payGateway
  4822. :param request:
  4823. :return:
  4824. """
  4825. def get_pay_gateway_redirect(pp, adLink):
  4826. redirect = pp._request.GET.get("redirect")
  4827. info = {
  4828. 'params': pp._request.GET.get("params"),
  4829. 'goodsInfo': json.dumps(pp.goodsInfo)
  4830. }
  4831. if adLink:
  4832. info.update({'adLink': adLink})
  4833. url = before_frag_add_query(redirect, info)
  4834. logger.debug('redirect to client url is: {}'.format(url))
  4835. return FrontEndResponseRedirect(url)
  4836. def get_auth_redirect(pp, bridge, adLink):
  4837. authCode = pp._request.GET.get(bridge.auth_code_key)
  4838. if not authCode:
  4839. redirect_uri = concat_server_end_url(
  4840. uri = add_query('/user/pay/gatewayEntry', {
  4841. 'params': pp._request.GET.get("params"),
  4842. 'redirect': pp._request.GET.get("redirect")
  4843. })
  4844. )
  4845. logger.debug('base scope auth url is:{}'.format(redirect_uri))
  4846. return ExternalResponseRedirect(
  4847. bridge.generate_auth_url_base_scope(
  4848. redirect_uri = redirect_uri,
  4849. payload = {}
  4850. )
  4851. )
  4852. else:
  4853. userPayOpenId = bridge.authorize(authCode)
  4854. if not userPayOpenId:
  4855. return ErrorResponseRedirect(error = u'微信授权失败,请刷新后重试')
  4856. else:
  4857. pp.curUser.set_bound_pay_openid(bridge.bound_openid_key, openId = userPayOpenId)
  4858. pp.curUser.save()
  4859. return get_pay_gateway_redirect(pp, adLink)
  4860. def RCU_process(payParam):
  4861. code = request.GET.get('code')
  4862. if not code:
  4863. redirect = payParam._request.GET.get("redirect")
  4864. redirect_uri = concat_server_end_url(
  4865. uri = add_query('/user/pay/gatewayEntry', {
  4866. 'params': payParam._request.GET.get("params"),
  4867. 'redirect': redirect
  4868. })
  4869. )
  4870. url = add_query(pay_gateway.app.authCodeUrl, {'authCallBackUrl': redirect_uri})
  4871. logger.debug('base scope auth url is:{}'.format(redirect_uri))
  4872. return FrontEndResponseRedirect(url)
  4873. else:
  4874. redirect = payParam._request.GET.get("redirect")
  4875. info = {
  4876. 'params': payParam._request.GET.get("params"),
  4877. 'code': code,
  4878. 'goodsInfo': json.dumps(payParam.goodsInfo),
  4879. }
  4880. if adLink:
  4881. info.update({'adLink': adLink})
  4882. url = before_frag_add_query(redirect, info)
  4883. logger.debug('redirect to client url is: {}'.format(url))
  4884. return FrontEndResponseRedirect(url)
  4885. payParam = PayParam(request)
  4886. curUser = payParam.curUser
  4887. pay_gateway = payParam.payGateway
  4888. adLink = request.GET.get('adLink', None)
  4889. # 首先判断登录的平台 只有微信扫码的需要获取其支付的openId
  4890. if detect_wechat_client(request):
  4891. if pay_gateway.pay_app_type == PayAppType.WECHAT:
  4892. authBridge = WechatAuthBridge(pay_gateway.app)
  4893. payOpenId = curUser.get_bound_pay_openid(authBridge.bound_openid_key)
  4894. if payOpenId:
  4895. return get_pay_gateway_redirect(payParam, adLink)
  4896. else:
  4897. return get_auth_redirect(payParam, authBridge, adLink)
  4898. else:
  4899. return JsonErrorResponse(description = u"平台配置错误,请稍后再试")
  4900. # 支付宝平台登录
  4901. elif detect_alipay_client(request):
  4902. return get_pay_gateway_redirect(payParam, adLink)
  4903. # 其他平台暂时不支持
  4904. else:
  4905. return NotSupportedPlatformResponseRedirect()
  4906. @error_tolerate(logger = logger, nil = JsonErrorResponse(u"套餐获取失败"))
  4907. @permission_required(ROLE.myuser)
  4908. def getMonthlyPackage(request):
  4909. """
  4910. 获取包月的套餐
  4911. :param request:
  4912. :return:
  4913. """
  4914. devNo = Device.get_dev_no_from_request(request)
  4915. cardNo = request.GET.get("cardNo")
  4916. device = Device.get_dev(devNo)
  4917. card = Card.objects.filter(cardNo = cardNo, openId = request.user.openId,
  4918. productAgentId = request.user.productAgentId).first()
  4919. if device:
  4920. group = Group.get_dealer_group(dealerId = device.ownerId, id = device.groupId)
  4921. elif card:
  4922. group = Group.get_dealer_group(dealerId = card.dealerId, id = card.groupId)
  4923. else:
  4924. return JsonErrorResponse(description = u"获取套餐失败(1000),请刷新重试")
  4925. if not group:
  4926. return JsonErrorResponse(description = u"套餐获取失败(1001),请刷新重试")
  4927. monthPackage = group.monthlyRule
  4928. if not monthPackage:
  4929. return JsonOkResponse()
  4930. return JsonOkResponse(payload = {"dataList": [monthPackage.to_dict()]})
  4931. @error_tolerate(nil = JsonErrorResponse(u"续费失败,请重新尝试"), logger = logger)
  4932. @permission_required(ROLE.myuser)
  4933. def checkVirtualCardRenew(request):
  4934. """
  4935. 检查当前的虚拟卡是否可以续费
  4936. :param request:
  4937. :return:
  4938. """
  4939. cardId = request.GET.get("cardId")
  4940. if not cardId:
  4941. return JsonErrorResponse(description = u"未找到相应虚拟卡,请重试")
  4942. vCard = UserVirtualCard.objects.get(id = cardId)
  4943. if not Group.check_virtual_card_number(groupId = vCard.groupId):
  4944. return JsonErrorResponse(description = u"该地址虚拟卡数量已经达到上限,请联系发卡经销商")
  4945. return JsonOkResponse()
  4946. @error_tolerate(nil = JsonErrorResponse(u"获取失败,请重试"), logger = logger)
  4947. @permission_required(ROLE.myuser)
  4948. def getUserMonthlyPackage(request):
  4949. """
  4950. 获取用户的 包月套餐
  4951. :param request:
  4952. :return:
  4953. """
  4954. openId = request.user.openId
  4955. monthlyPackages = MonthlyPackage.get_user_all(openId)
  4956. dataList = [_package.to_dict() for _package in monthlyPackages]
  4957. return JsonOkResponse(payload = {"dataList": dataList})
  4958. @error_tolerate(nil = JsonErrorResponse(u"获取失败,请重试"), logger = logger)
  4959. @permission_required(ROLE.myuser)
  4960. def getMonthlyPackageUseDetail(request):
  4961. """
  4962. 获取 用户的使用详情
  4963. :param request:
  4964. :return:
  4965. """
  4966. monthlyPackageId = request.GET.get("monthlyPackageId")
  4967. pageIndex = int(request.GET.get("pageIndex", 1))
  4968. pageSize = int(request.GET.get("pageSize", 10))
  4969. monthlyPackage = MonthlyPackage.objects.get(id = monthlyPackageId)
  4970. useDetail = monthlyPackage.get_used_detail()
  4971. # 获取使用的总的数量 添加上订单的ID 方便前台跳转
  4972. total = len(useDetail)
  4973. result = useDetail[pageSize * (pageIndex - 1): pageSize * pageIndex]
  4974. orderNos = [_item.get("orderNo") for _item in result]
  4975. consumeRecords = ConsumeRecord.objects.filter(openId = request.user.openId, orderNo__in = orderNos).only("openId",
  4976. "orderNo",
  4977. "id",
  4978. "dateTimeAdded")
  4979. dataList = [
  4980. {"id": consume.id, "orderNo": consume.orderNo, "orderTime": consume.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")}
  4981. for consume in consumeRecords
  4982. ]
  4983. return JsonOkResponse(payload = {"total": total, "dataList": dataList})
  4984. @error_tolerate(nil = JsonErrorResponse(u"获取失败,请重试"), logger = logger)
  4985. @permission_required(ROLE.myuser)
  4986. def supportPayment(request):
  4987. def get_dealer(request):
  4988. logicalCode = request.GET.get('logicalCode', None)
  4989. if logicalCode:
  4990. device = Device.get_dev_by_logicalCode(logicalCode)
  4991. if not device:
  4992. logger.info('can not find device. logicalCode={}'.format(logicalCode))
  4993. return None
  4994. else:
  4995. return device.owner
  4996. else:
  4997. groupId = request.GET.get('groupId', None)
  4998. if not groupId:
  4999. logger.info('can not find group. groupId={}'.format(groupId))
  5000. return None
  5001. else:
  5002. group = Group.get_group(groupId) # type: GroupDict
  5003. if not group:
  5004. logger.info('can not find group. groupId={}'.format(groupId))
  5005. return None
  5006. else:
  5007. return group.owner
  5008. dealer = get_dealer(request)
  5009. if dealer is None:
  5010. return JsonErrorResponse(description = u'该设备未注册,暂时无法使用支付宝或者微信支付, 请投币(1013)')
  5011. return JsonOkResponse(description = u'无商户配置')
  5012. @permission_required(ROLE.myuser)
  5013. def getAlipayAd(request):
  5014. """
  5015. 领取红包福利任务
  5016. :param request:
  5017. :return:
  5018. """
  5019. try:
  5020. user = request.user # type: MyUser
  5021. logicalCode = request.GET.get('logicalCode', '')
  5022. pageIndex = int(request.GET.get('pageIndex', 0))
  5023. pageSize = int(request.GET.get('pageSize', 10))
  5024. chargeIndex = request.GET.get('chargeIndex', '')
  5025. dev = Device.get_dev_by_l(logicalCode) # Type:DeviceDict
  5026. from apps.web.core.models import SystemSettings
  5027. if user.gateway != AppPlatformType.ALIPAY:
  5028. return JsonOkResponse(payload = {})
  5029. if not dev:
  5030. return JsonOkResponse(payload = {})
  5031. if not Redpack.can_use(dealer = dev.owner, devTypeCode = dev.devTypeCode):
  5032. return JsonOkResponse(payload = {})
  5033. if not DevRegToAli.objects.filter(logicalCode = logicalCode).first():
  5034. reg_result = DevRegToAli.reg_to_aliyun_v3(dev)
  5035. if not reg_result:
  5036. return JsonOkResponse()
  5037. if 'disable_alipay_ruhui' in dev.owner.features:
  5038. ruhui = {}
  5039. elif SystemSettings.disable_alipay_ruhui():
  5040. ruhui = {}
  5041. else:
  5042. # 判断是否为蓝牙. 蓝牙为老流程 串口充电桩为新流程
  5043. if dev.channelType == DeviceChannelType.Channel_BT:
  5044. showType = 'pop'
  5045. else:
  5046. # 1 确认显示方式
  5047. showType = 'footerTopRedpack'
  5048. group = dev.group
  5049. if group.get('beforeCharge'):
  5050. showType = 'pop'
  5051. if 'show_pop_ruhui' in dev.owner.features:
  5052. showType = 'pop'
  5053. elif 'show_top_ruhui' in dev.owner.features:
  5054. showType = 'top'
  5055. elif 'show_buttun_ruhui' in dev.owner.features:
  5056. showType = 'buttun'
  5057. # 2 请求 请求权益 创建红报
  5058. ruhui = RedpackBuilder.get_alipay_cpa_by_ruhui_v3(openId = user.openId, logicalCode = logicalCode,
  5059. chargeIndex = chargeIndex, showType = showType)
  5060. if ruhui:
  5061. # 地址组启动强制充值, 后面的页面需要弹窗 比较复杂直接改为弹窗流程
  5062. group = dev.group
  5063. if group.get('beforeCharge'):
  5064. ruhui = {'url': ruhui['url'], 'money': ruhui['money'], 'showType': ruhui['showType'],
  5065. 'urlId': ruhui['urlId']}
  5066. else:
  5067. pass
  5068. if 'disable_alipay_laxin' in dev.owner.features:
  5069. laxin = {}
  5070. elif SystemSettings.disable_alipay_laxin():
  5071. laxin = {}
  5072. else:
  5073. # 拉新
  5074. dataList = RedpackBuilder.get_alipay_cpa_by_laxin(openId = user.openId)
  5075. total = len(dataList)
  5076. if dataList:
  5077. dataList = dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  5078. laxin = {'dataList': dataList, 'total': total}
  5079. return JsonOkResponse(payload = {'laxin': laxin, 'ruhui': ruhui})
  5080. except Exception as e:
  5081. logger.exception(e)
  5082. return JsonOkResponse()
  5083. @error_tolerate(u"获取权益失败", logger=logger)
  5084. @permission_required(ROLE.myuser)
  5085. def getAlipayAdResult(request):
  5086. """
  5087. 领取红包福利任务
  5088. :param request:
  5089. :return:
  5090. """
  5091. alipayOpenId = request.GET.get('alipayOpenId')
  5092. taskId = request.GET.get('taskId')
  5093. taskType = request.GET.get('taskType')
  5094. openId = request.GET.get('alipayOpenId')
  5095. logicalCode = request.GET.get('logicalCode')
  5096. dev = Device.get_dev_by_logicalCode(logicalCode)
  5097. # 拉新结果处理
  5098. if taskId and alipayOpenId:
  5099. if RedpackBuilder.query_cpa_laxin_task_status(taskId, alipayOpenId):
  5100. redpack = RedpackBuilder.create_cpa_laxin_redpack(dev, taskId, openId, taskType)
  5101. if redpack:
  5102. return JsonOkResponse(payload={'showAmount': redpack.money.mongo_amount})
  5103. # 入会结果处理
  5104. redpackInfo = RedpackBuilder._pop_alipay_key(request.user.openId)
  5105. if redpackInfo:
  5106. showType = redpackInfo.get('showType')
  5107. if showType == 'pop':
  5108. return JsonOkResponse(payload={'showAmount': redpackInfo.get('money')})
  5109. return JsonResponse({'payload': {}})
  5110. @error_tolerate(u"获取权益失败", logger=logger)
  5111. @permission_required(ROLE.myuser)
  5112. def getMyRedpackList(request):
  5113. user = request.user # type: MyUser
  5114. pageIndex = int(request.GET.get('pageIndex', 0))
  5115. pageSize = int(request.GET.get('pageSize', 10))
  5116. dataList = Redpack.show_redpack(openId=user.openId)
  5117. total = len(dataList)
  5118. dataList = dataList[(pageIndex-1) * pageSize: pageIndex * pageSize]
  5119. return JsonOkResponse(payload={'dataList':dataList, 'total':total})
  5120. @error_tolerate(nil = JsonErrorResponse(description = u'显示用户信息错误'), logger = logger)
  5121. @permission_required(ROLE.myuser)
  5122. def getCurrentFeePara(request):
  5123. devNo = request.GET.get('devNo', None)
  5124. devObj = Device.objects.get(devNo = devNo)
  5125. feeMode = devObj.otherConf.get('feeMode',{})
  5126. timeRateList = []
  5127. shiduan = feeMode.get('shiduan','000000000000000000000000000000000000000000000000')
  5128. nowTime = datetime.datetime.now().strftime('%H:%M')
  5129. curFeeIndex = 0
  5130. for ii in range(48):
  5131. startHour = 0 + ii/2
  5132. startMin = '00' if ii%2==0 else '30'
  5133. endHour = startHour if ii%2==0 else startHour + 1
  5134. endMin = '30' if ii%2==0 else '00'
  5135. startTime = '%02d:%s' % (startHour,startMin)
  5136. endTime = '%02d:%s' % (endHour,endMin)
  5137. timeRateList.append({'startTime':startTime,'endTime':endTime,'rate':shiduan[ii]})
  5138. if nowTime >= startTime and nowTime <= endTime:
  5139. curFeeIndex = shiduan[ii]
  5140. result = {'top_price_rate':feeMode.get('jianFee',0),
  5141. 'top_price_service_rate':feeMode.get('jianServe',0),
  5142. 'peak_price_rate':feeMode.get('fengFee',0),
  5143. 'peak_price_service_rate':feeMode.get('fengServe',0),
  5144. 'normal_price_rate':feeMode.get('pingFee',0),
  5145. 'normal_price_service_rate':feeMode.get('pingServe',0),
  5146. 'valley_price_rate':feeMode.get('guFee',0),
  5147. 'valley_price_service_rate':feeMode.get('guServe',0),
  5148. 'jishunScale':feeMode.get('jishunScale',0),
  5149. 'timeRateList':timeRateList,
  5150. 'curFeeIndex':curFeeIndex}
  5151. return JsonOkResponse( payload = result )
  5152. @permission_required(ROLE.myuser)
  5153. def getNearbyCarStation(request):
  5154. # type: (WSGIRequest)->JsonResponse
  5155. try:
  5156. lng = float(request.GET.get('lng'))
  5157. lat = float(request.GET.get('lat'))
  5158. pageIndex = int(request.GET.get('pageIndex',1))
  5159. pageSize = int(request.GET.get('pageSize',10))
  5160. maxDistance = int(request.GET.get('distance', 5000))
  5161. logger.debug('now location. lat = %s; lng = %s' % (lat, lng))
  5162. if maxDistance > Const.NEAR_BY_MAX_DISTANCE:
  5163. maxDistance = Const.NEAR_BY_MAX_DISTANCE
  5164. if lng == 360 or lat == 360 or isnan(lng) or isnan(lat):
  5165. return JsonResponse({'result': 0, 'description': u'定位失败,请打开位置权限,刷新后重试'})
  5166. payload = getNearbyGroupsFromDB(lng, lat, pageIndex, pageSize, maxDistance, request.user.agentId,
  5167. request.GET.get('chargeType', 0))
  5168. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  5169. except Exception as e:
  5170. logger.exception(e)
  5171. return JsonResponse({'result': 0, 'description': u'获取附近设备失败'})
  5172. def getNearbyGroupsFromDB(lng, lat, pageIndex, pageSize, maxDistance, agentId, chargeType):
  5173. def hav(theta):
  5174. s = sin(theta / 2)
  5175. return s * s
  5176. def get_distance_hav(lat0, lng0, lat1, lng1):
  5177. if lat1 == 360 or lng1 == 360:
  5178. return -1
  5179. EARTH_RADIUS = 6371000
  5180. lat0 = radians(lat0)
  5181. lat1 = radians(lat1)
  5182. lng0 = radians(lng0)
  5183. lng1 = radians(lng1)
  5184. dlng = fabs(lng0 - lng1)
  5185. dlat = fabs(lat0 - lat1)
  5186. h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlng)
  5187. return int(2 * EARTH_RADIUS * asin(sqrt(h)))
  5188. if not agentId:
  5189. logger.error('agent is null.')
  5190. return {
  5191. 'total': 0,
  5192. 'items': []
  5193. }
  5194. dealers = Dealer.get_dealers(agentId)
  5195. if not dealers:
  5196. return {
  5197. 'total': 0,
  5198. 'items': []
  5199. }
  5200. queryDict = {
  5201. 'ownerId': {'$in': dealers},
  5202. 'StationStatus':50,# 站点状态必须是正常使用中的
  5203. 'location': {
  5204. '$near': {'$geometry': {'type': 'Point', 'coordinates': [lng, lat]},
  5205. '$maxDistance': maxDistance}}}
  5206. if chargeType != '0':
  5207. queryDict.update({'chargeType':int(chargeType)})
  5208. groups = SwapGroup.get_collection().find(queryDict)
  5209. items = []
  5210. for swapInfo in groups[(pageIndex - 1) * pageSize:pageIndex * pageSize]:
  5211. groupId = swapInfo['groupId']
  5212. group = Group.get_group(groupId)
  5213. if group is None:
  5214. continue
  5215. swaplng = float(swapInfo['location']['coordinates'][0])
  5216. swaplat = float(swapInfo['location']['coordinates'][1])
  5217. distance = get_distance_hav(lat, lng, swaplat, swaplng)
  5218. curFee = SwapGroup.get_cur_fee(swapInfo['PriceChargingInfo'])
  5219. if curFee is None:
  5220. continue
  5221. # 统计交流、直流端口的情况
  5222. statsDict = SwapGroup.get_stats(groupId)
  5223. info = {
  5224. 'lng': swaplng,
  5225. 'lat': swaplat,
  5226. 'Pictures':[{'IsCover':pic['IsCover'],'PicID':pic['PicID'],'Url':pic['Url'],'Title':pic['Title']} for pic in swapInfo.get('Pictures',[])],
  5227. 'PriceChargingInfo':[{'FeeTime':info['FeeTime'],'ElectricityFee':info['ElectricityFee'],'ServiceFee':info['ServiceFee']} for info in swapInfo['PriceChargingInfo']],
  5228. 'StationName':group['groupName'] if u'充电站' in group['groupName'] else u'%s充电站' % group['groupName'],
  5229. 'Address':group['address'],
  5230. 'Distance':distance,
  5231. 'BusineHours':swapInfo['BusineHours'],
  5232. 'acPortsSum':{'allPorts':statsDict['acAllPorts'],'usedPorts':statsDict['acUsedPorts'],'usePorts':statsDict['acUsePorts']},
  5233. 'dcPortsSum':{'allPorts':statsDict['dcAllPorts'],'usedPorts':statsDict['dcUsedPorts'],'usePorts':statsDict['dcUsePorts']},
  5234. 'exceptSum':{'offline':statsDict['offline'],'fault':statsDict['fault']},
  5235. 'curFee':{"curElecFee": curFee['curElecFee'], "curServiceFee": curFee['curServiceFee']},
  5236. 'ParkFee':swapInfo['ParkFee'],
  5237. 'tagDescList':SwapGroup.get_tag_desc_list_for_dict(swapInfo)
  5238. }
  5239. items.append(info)
  5240. payload = {
  5241. 'total': groups.count(),
  5242. 'items': items
  5243. }
  5244. return payload
  5245. @error_tolerate(logger = logger)
  5246. def refundOrderNotifier(request, pay_app_type):
  5247. """
  5248. 退款回调接口.
  5249. 微信和京东聚合单独指定回调
  5250. 支付宝支付和退款回调是一个
  5251. :param request:
  5252. :param pay_app_type:
  5253. :return:
  5254. """
  5255. assert pay_app_type in PayAppType.choices(), 'not support this pay app type({})'.format(pay_app_type)
  5256. notifier_cls = RefundManager().get_notifier(pay_app_type)
  5257. response = notifier_cls(request, lambda order_no: RefundMoneyRecord.get_record(order_no)).do(refund_post_pay)
  5258. return response
  5259. @error_tolerate(logger=logger)
  5260. @permission_required(ROLE.myuser)
  5261. def cancelWaitPay(request):
  5262. """
  5263. 后支付用户拉起支付后, 没有输入密码 点击恢复到end状态 用于再次支付
  5264. """
  5265. payload = json.loads(request.body)
  5266. ownerId = payload.get('ownerId')
  5267. consumeRecordId = payload.get('consumeRecordId')
  5268. if not ownerId or not consumeRecordId:
  5269. return JsonErrorResponse(description='参数缺失, 请刷新后重试..')
  5270. order = ConsumeRecord.objects.filter(
  5271. id=consumeRecordId,
  5272. ownerId=ownerId
  5273. ).first() # type: ConsumeRecord
  5274. if not order:
  5275. return JsonErrorResponse(description='没有找到该订单')
  5276. try:
  5277. if order.status == order.Status.WAIT_PAY and not order.isPaid:
  5278. order.status = order.Status.END
  5279. order.save()
  5280. except Exception as e:
  5281. logger.exception("[cancelWaitPay] error = {}".format(e))
  5282. return JsonErrorResponse(description='参数错误')
  5283. return JsonOkResponse(payload={})
  5284. @permission_required(ROLE.myuser)
  5285. def cancelRechargeRecord(request):
  5286. """
  5287. 用户取消订单
  5288. """
  5289. try:
  5290. payload = json.loads(request.body)
  5291. orderNo = payload.get('orderNo')
  5292. record = RechargeRecord.objects(orderNo = orderNo).first() # type: RechargeRecord
  5293. if not record:
  5294. logger.warning('has no recharge record<orderNo={}>'.format(orderNo))
  5295. else:
  5296. record.cancel()
  5297. except Exception as e:
  5298. logger.exception(e)
  5299. finally:
  5300. return JsonOkResponse()