views.py 551 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import base64
  4. import datetime
  5. import logging
  6. import random
  7. import re
  8. import time
  9. import urlparse
  10. import uuid
  11. from collections import Counter, defaultdict
  12. from decimal import Decimal
  13. from itertools import groupby
  14. from operator import itemgetter
  15. import arrow
  16. import cytoolz
  17. import simplejson as json
  18. from bson import Regex
  19. from bson.objectid import ObjectId
  20. from dateutil.relativedelta import relativedelta
  21. from django.conf import settings
  22. from django.contrib import auth
  23. from django.contrib.auth.hashers import make_password
  24. from django.core.cache import caches
  25. from django.core.handlers.wsgi import WSGIRequest
  26. from django.http import HttpResponse
  27. from django.views.decorators.http import require_POST, require_GET
  28. from mongoengine import Q
  29. from mongoengine.errors import DoesNotExist, NotUniqueError
  30. from typing import TYPE_CHECKING, Optional, cast, Union, Dict, Mapping
  31. from voluptuous import MultipleInvalid
  32. from apilib import utils_datetime
  33. from apilib.monetary import RMB, VirtualCoin, sum_rmb
  34. from apilib.quantity import Quantity
  35. from apilib.utils import natural_sort, is_number, round_2_digits
  36. from apilib.utils_datetime import to_datetime, defaultTodayDate, dt_to_timestamp, get_zero_time, \
  37. get_tomorrow_zero_time
  38. from apilib.utils_datetime import today_datetime_range
  39. from apilib.utils_json import JsonResponse, json_dumps
  40. from apilib.utils_mongo import format_dot_key
  41. from apilib.utils_string import cn
  42. from apilib.utils_url import add_query
  43. from apps import serviceCache, reportCache
  44. from apps.common.utils import get_start_and_end_by_month, get_start_and_end_by_year, get_date_range
  45. from apps.thirdparties.aliyun import AliyunSlider
  46. from apps.web.agent.models import Agent
  47. from apps.web.api.models import APIStartDeviceRecord
  48. from apps.web.common.models import District, DEFAULT_DEALER_FEATURES, WithdrawRecord, OperatorLog, \
  49. MonthlyPackageTemp, WithdrawBankCard
  50. from apps.web.common.proxy import ClientRechargeModelProxy, ClientConsumeModelProxy, DealerDailyStatsModelProxy, \
  51. GroupDailyStatsModelProxy, DeviceDailyStatsModelProxy, ClientDealerIncomeModelProxy, DealerReportModelProxy
  52. from apps.web.common.transaction import WithdrawStatus, WITHDRAW_PAY_TYPE, translate_withdraw_state
  53. from apps.web.common.transaction.pay import OrderCacheMgr, PayManager
  54. from apps.web.common.transaction.refund import RefundManager
  55. from apps.web.common.validation import NAME_RE, PHONE_NUMBER_RE
  56. from apps.web.constant import (
  57. Const,
  58. DEALER_CONSUMPTION_AGG_KIND_TRANSLATION,
  59. DEALER_CONSUMPTION_AGG_KIND, DEALER_CONSUMPTION_AGG_KIND_UNIT,
  60. MONTH_DATE_KEY,
  61. FAULT_RECORD_STATUS, APP_TYPE, PollRecordDefine, TYPE_ADJUST_USER_VIRTUAL_CARD, DeviceCmdCode,
  62. ErrorCode, RECHARGE_CARD_TYPE, RECHARGE_RECORD_VIA_TRANSLATION, skip_package_unit_verify_list,
  63. skip_package_range_verify_list, skip_package_params_verify_list, USER_RECHARGE_TYPE, CONSUMETYPE,
  64. support_policy_weifule, support_policy_device)
  65. from apps.web.constant import RechargeRecordVia
  66. from apps.web.core import PayAppType, ROLE
  67. from apps.web.core.accounting import Accounting, devCoinTmpl
  68. from apps.web.core.auth.wechat import WechatAuthBridge
  69. from apps.web.core.bridge.wechat import WechatClientProxy
  70. from apps.web.core.db import paginate, prepare_query, search_query
  71. from apps.web.core.device_define.huopo import HuopoCacheMgr
  72. from apps.web.core.exceptions import ServiceException, InvalidParameter, ParameterError, InvalidFileSize, \
  73. InvalidFileName, RentDeviceError
  74. from apps.web.core.file import AliOssFileUploader, SwapGroupPicFileUploader
  75. from apps.web.core.helpers import ActionDeviceBuilder
  76. from apps.web.core.messages.sms import (
  77. dealerAutoWithdrawSMSProvider,
  78. dealerRegisterSMSProvider,
  79. dealerWithdrawSMSProvider,
  80. dealerBindWechatSMSProvider,
  81. dealerBindWalletWechatSMSProvider,
  82. dealerEditMonitorSMSProvider,
  83. dealerMonitorWithdrawSMSProvider)
  84. from apps.web.core.models import OfflineTask, WechatPayApp
  85. from apps.web.core.networking import MessageSender
  86. from apps.web.core.payment import WithdrawGateway, PaymentGateway
  87. from apps.web.core.payment.wechat import WechatPaymentGateway
  88. from apps.web.core.sysparas import SysParas
  89. from apps.web.core.utils import DefaultJsonErrorResponse, JsonErrorResponse, JsonOkResponse, parse_json_payload
  90. from apps.web.dealer import OfflineTaskType
  91. from apps.web.dealer.define import DEALER_INCOME_SOURCE, DEALER_INCOME_SOURCE_TRANSLATION, DEALER_INCOME_TYPE, \
  92. PAY_NOTIFY_URL, DEALER_BIND_WECHAT_URL, DEALER_BIND_WALLET_WECHAT_URL
  93. from apps.web.dealer.models import (
  94. Dealer, UpscoreRecord, DealerRechargeRecord,
  95. OnSale, OnSaleRecord, VirtualCard,
  96. ElecPriceTemplate, ItemType,
  97. SubAccount, DealerMessage, Complaint, AdjustUserVirtualCardRecord, ExchangeOrder, DealerAddr, UpCardScoreRecord,
  98. PermissionRole, PermissionRule, TodoMessage, ApiAppInfo, RefundDealerRechargeRecord)
  99. from apps.web.dealer.proxy import DealerIncomeProxy
  100. from apps.web.dealer.transaction import post_pay
  101. from apps.web.dealer.transaction_deprecated import refund_post_pay
  102. from apps.web.dealer.utils import gen_login_response, gen_home_response, gen_subaccount_login_response, \
  103. VirtualCardBuilder, create_dealer_sim_charge_order, DealerSessionBuilder, MyToken, \
  104. create_dealer_charge_order_for_api, create_dealer_charge_order_for_disable_ad
  105. from apps.web.dealer.validation import dealerSchema
  106. from apps.web.dealer.validator import UserListValidator
  107. from apps.web.dealer.withdraw import DealerWithdrawService
  108. from apps.web.device.define import DeviceChannelType
  109. from apps.web.device.models import Device, Group, FeedBack, DeviceType, StockRecord, Cell, FaultRecord, Part, Battery, \
  110. GroupDict, DeviceRentOrder, GroupCacheMgr
  111. from apps.web.device.models import DeviceDict, RequestBodyDict, SwapGroup, DiscountPriceCharging, PriceCharging, \
  112. ChargeTag, Picture
  113. from apps.web.device.timescale import SignalManager
  114. from apps.web.device.utils import device_control_cache_key
  115. from apps.web.exceptions import UserServerException
  116. from apps.web.helpers import get_wx_config, current_platform, get_app, \
  117. get_wechat_auth_bridge, \
  118. get_wechat_user_manager_mp_proxy, \
  119. remove_some_desc_for_consume, get_inhourse_wechat_env_pay_gateway
  120. from apps.web.management.models import Manager
  121. from apps.web.report.models import (
  122. DevReport, GroupReport, DealerReport,
  123. GroupDailyStat, DealerMonthlyStat, DealerDailyStat, DeviceDailyStat
  124. )
  125. from apps.web.report.utils import (
  126. consumption_unit_precision,
  127. to_quantity,
  128. translate_income,
  129. translate_consumption)
  130. from apps.web.south_intf.swap_carcharger import SwapContract
  131. from apps.web.south_intf.zhejiang_fire import Company
  132. from apps.web.south_intf.zhejiang_fire import handler_event_to_zhejiang
  133. from apps.web.user.models import RechargeRecord, ConsumeRecord, MyUser, CardConsumeRecord, Card, \
  134. CardRechargeRecord, CardRechargeOrder, UserVirtualCard, ServiceProgress, VirtualCardRechargeRecord, BlackListUsers, \
  135. SwapCardRecord, UniqueUser
  136. from apps.web.user.transaction_deprecated import refund_cash
  137. from apps.web.user.utils import check_black_user, BatteryInfo
  138. from apps.web.user.utils2 import get_paginate
  139. from apps.web.utils import (permission_required, LimitAttemptsManager,
  140. dealer_login, subAccount_login, error_tolerate,
  141. ensure_all_fields_are_not_empty,
  142. is_login, check_role, is_dealer, concat_server_end_url,
  143. ErrorResponseRedirect,
  144. FrontEndResponseRedirect, ExternalResponseRedirect, DealerBindIdResponseRedirect,
  145. ViewValidator, record_operation_behavior)
  146. from apps.web.wrapper import request_limit_by_user
  147. from library.wechatbase.exceptions import WeChatException
  148. from taskmanager.mediator import task_caller
  149. logger = logging.getLogger(__name__)
  150. merge_with = cytoolz.merge_with
  151. get_in = cytoolz.get_in
  152. if TYPE_CHECKING:
  153. from apps.web.core.db import CustomQuerySet
  154. from collections import Iterable
  155. from apps.web.core.db import Query
  156. from apps.web.common.models import UserSearchable
  157. from apps.web.core.adapter.bolai_gateway import ChargingGatewayBox
  158. from apps.web.core.adapter.bolai_node import ChargingBox
  159. from apps.web.core.adapter.huiteng import washerHTBox
  160. from apps.web.core.adapter.xiyiji import WasherBox
  161. @error_tolerate(nil=DefaultJsonErrorResponse)
  162. @permission_required(ROLE.dealer, ROLE.subaccount)
  163. def getCheckCodeForNewTel(request):
  164. # type: (WSGIRequest)->JsonResponse
  165. payload = json.loads(request.body)
  166. toNumber = payload.get('phone', None)
  167. agentId = request.user.agentId
  168. agent = Agent.get_agent(agentId)
  169. productName = agent['productName']
  170. status, msg = dealerRegisterSMSProvider.get(phoneNumber = toNumber,
  171. productName = productName,
  172. vendor = SysParas.get_sms_vendor(request.user.smsVendor))
  173. if not status:
  174. return JsonResponse({'result': 0, 'description': msg})
  175. else:
  176. return JsonResponse({'result': 1, 'description': ''})
  177. @error_tolerate(nil=DefaultJsonErrorResponse)
  178. def getCheckCode(request):
  179. # type: (WSGIRequest)->JsonResponse
  180. """
  181. 经销商获取注册短信验证码
  182. :param request:
  183. :return:
  184. """
  185. payload = json.loads(request.body)
  186. toNumber = payload.get('phone', None)
  187. agentId = request.COOKIES.get('agentId', settings.MY_PRIMARY_AGENT_ID)
  188. agent = Agent.objects(id = agentId).first() # type: Agent
  189. sessionId = payload.get('csessionid', None)
  190. sig = payload.get('sig', None)
  191. token = payload.get('nc_token', None)
  192. result = eval(AliyunSlider().check_validation_results(sessionId, sig, token))
  193. if type(result) is dict:
  194. resultCode = result.get('Code', 900)
  195. else:
  196. resultCode = 900
  197. if resultCode == 100:
  198. status, msg = dealerRegisterSMSProvider.get(phoneNumber = toNumber,
  199. productName = agent.productName,
  200. vendor = SysParas.get_sms_vendor(agent.smsVendor))
  201. if not status:
  202. return JsonResponse({'result': 0, 'description': msg})
  203. else:
  204. return JsonResponse({'result': 1, 'description': ''})
  205. else:
  206. return JsonResponse({'result': 0, 'description': u'非正常请求,验证码发送失败'})
  207. @error_tolerate(nil=DefaultJsonErrorResponse)
  208. def verifyForgetCode(request):
  209. # type: (WSGIRequest)->JsonResponse
  210. """
  211. 经销商验证短信验证码
  212. :param request:
  213. :return:
  214. """
  215. phone = request.POST.get('phone', None)
  216. code = request.POST.get('code', None)
  217. password = request.POST.get('password', "")
  218. agentId = request.POST.get('agentId')
  219. if not agentId:
  220. return JsonErrorResponse(u'未选择您对应的代理商,请刷新后再试')
  221. dealer = Dealer.objects(username=phone, agentId=agentId).first()
  222. while True:
  223. if dealer is None:
  224. response = JsonErrorResponse(u'该手机号尚未注册,请注册后再进行操作')
  225. break
  226. if password == "":
  227. response = JsonErrorResponse(u"请输入密码")
  228. break
  229. status, desc = dealerRegisterSMSProvider.verify(phone, code)
  230. if not status:
  231. response = JsonErrorResponse(desc)
  232. else:
  233. dealer.set_password(password)
  234. dealer.unlock_login()
  235. response = JsonResponse({"result": 1, "description": None, "payload": {}})
  236. break
  237. if agentId != request.COOKIES.get('agentId'):
  238. Agent.record_cookie(agentId, response)
  239. return response
  240. @error_tolerate(nil=DefaultJsonErrorResponse)
  241. def getSubAccountCheckCode(request):
  242. # type: (WSGIRequest)->JsonResponse
  243. """
  244. 经销商获取注册短信验证码
  245. :param request:
  246. :return:
  247. """
  248. payload = json.loads(request.body)
  249. toNumber = payload.get('phone', None)
  250. agentId = request.COOKIES.get('agentId', settings.MY_PRIMARY_AGENT_ID)
  251. agent = Agent.objects(id = agentId).first() # type: Agent
  252. sessionId = payload.get('csessionid', None)
  253. sig = payload.get('sig', None)
  254. token = payload.get('nc_token', None)
  255. result = eval(AliyunSlider().check_validation_results(sessionId, sig, token))
  256. if type(result) is dict:
  257. resultCode = result.get('Code', 900)
  258. else:
  259. resultCode = 900
  260. if resultCode == 100:
  261. status, msg = dealerRegisterSMSProvider.get(phoneNumber = toNumber,
  262. productName = agent.productName,
  263. vendor = SysParas.get_sms_vendor(agent.smsVendor))
  264. if not status:
  265. return JsonResponse({'result': 0, 'description': msg})
  266. else:
  267. return JsonResponse({'result': 1, 'description': ''})
  268. else:
  269. return JsonResponse({'result': 0, 'description': u'非正常请求,验证码发送失败'})
  270. @error_tolerate(nil=DefaultJsonErrorResponse)
  271. def verifySubAccountForgetCode(request):
  272. # type: (WSGIRequest)->JsonResponse
  273. """
  274. 经销商验证短信验证码
  275. :param request:
  276. :return:
  277. """
  278. phone = request.POST.get('phone', None)
  279. code = request.POST.get('code', None)
  280. password = request.POST.get('password', "")
  281. agentId = request.POST.get('agentId')
  282. if not agentId:
  283. return JsonErrorResponse(u'未选择您对应的代理商,请刷新后再试')
  284. subaccount = SubAccount.objects(username=phone, agentId=agentId).first()
  285. while True:
  286. if subaccount is None:
  287. response = JsonErrorResponse(u'该手机号不是子账号,请主账号添加此子账号后再进行操作')
  288. break
  289. if password == "":
  290. response = JsonErrorResponse(u"请输入密码")
  291. break
  292. status, desc = dealerRegisterSMSProvider.verify(phone, code)
  293. if not status:
  294. response = JsonErrorResponse(desc)
  295. else:
  296. subaccount.set_password(password)
  297. subaccount.unlock_login()
  298. response = JsonResponse({"result": 1, "description": None, "payload": {}})
  299. break
  300. if agentId != request.COOKIES.get('agentId'):
  301. Agent.record_cookie(agentId, response)
  302. return response
  303. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  304. def getDealerRegisterSMSCode(request):
  305. # type: (WSGIRequest)->JsonResponse
  306. payload = json.loads(request.body)
  307. phoneNumber = payload.get('phoneNumber', None)
  308. agentId = request.COOKIES.get('agentId', settings.MY_PRIMARY_AGENT_ID)
  309. agent = Agent.objects(id = agentId).first() # type: Agent
  310. sessionId = payload.get('csessionid', None)
  311. sig = payload.get('sig', None)
  312. token = payload.get('nc_token', None)
  313. result = eval(AliyunSlider().check_validation_results(sessionId, sig, token))
  314. if type(result) is dict:
  315. resultCode = result.get('Code', 900)
  316. else:
  317. resultCode = 900
  318. if not phoneNumber:
  319. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  320. if len(Dealer.objects.filter(username = phoneNumber, agentId = agentId)):
  321. return JsonResponse({'result': 0, 'description': u'该手机号已注册'})
  322. if resultCode == 100:
  323. status, msg = dealerRegisterSMSProvider.get(phoneNumber = phoneNumber,
  324. productName = agent.productName,
  325. vendor = SysParas.get_sms_vendor(agent.smsVendor))
  326. if not status:
  327. return JsonResponse({'result': 0, 'description': msg})
  328. else:
  329. return JsonResponse({'result': 1, 'description': ''})
  330. else:
  331. return JsonResponse({'result': 0, 'description': u'非正常请求,验证码发送失败'})
  332. def dealerRegister(request):
  333. # type: (WSGIRequest)->JsonResponse
  334. try:
  335. rawPayload = json.loads(request.body) # type: dict
  336. mid = rawPayload.pop('managerId', None)
  337. if mid:
  338. agentId = Manager.objects.get(id=ObjectId(mid)).primeAgentId
  339. rawPayload['agentId'] = str(agentId)
  340. else:
  341. agentId = rawPayload.pop('agentId', None)
  342. if agentId:
  343. rawPayload['agentId'] = str(agentId)
  344. try:
  345. payload = dealerSchema(rawPayload)
  346. except MultipleInvalid:
  347. return JsonErrorResponse(description=u'信息填入有误,请检查手机号码等信息是否合法')
  348. agentId = rawPayload.get('agentId')
  349. agent = Agent.objects(id=agentId).first() # type: Optional[Agent]
  350. if not agent:
  351. return JsonErrorResponse(description=u'请联系您的代理商获取正确的经销商注册地址')
  352. username = payload.pop('username').strip()
  353. password = payload.pop('password').strip()
  354. if PHONE_NUMBER_RE.match(username) is None:
  355. return JsonErrorResponse(description=u'请输入正确格式的手机号码')
  356. status, msg = dealerRegisterSMSProvider.verify(phoneNumber=username, smsCode=rawPayload["code"])
  357. if not status:
  358. return JsonErrorResponse(description=msg)
  359. payload['features'] = DEFAULT_DEALER_FEATURES
  360. try:
  361. Dealer.create_user(
  362. username = username,
  363. password = password,
  364. adShow = True,
  365. noAdPolicy = 'banner',
  366. annualTrafficCost = agent.annualTrafficCost if \
  367. agent.annualTrafficCost > agent.trafficCardCost else agent.trafficCardCost,
  368. trafficCardCost = agent.trafficCardCost,
  369. withdrawFeeRatio = agent.withdrawFeeRatio if \
  370. agent.withdrawFeeRatio > agent.withdrawFeeRatioCost else agent.withdrawFeeRatioCost,
  371. **payload
  372. )
  373. except NotUniqueError:
  374. return JsonErrorResponse(description=u'该经销商已注册')
  375. except MultipleInvalid as e:
  376. logger.exception('failed to validate register dealer payload due to %s' % e)
  377. return JsonErrorResponse(description=u'部分输入不合法,请重试')
  378. except Exception as e:
  379. logger.exception('cannot register dealer due to %s' % e)
  380. return JsonErrorResponse(description=u'注册失败请重试')
  381. return JsonOkResponse()
  382. def dealerAccess(request):
  383. # type: (WSGIRequest)->JsonResponse
  384. agentId = request.GET.get('agentId', '')
  385. if not is_login(request, ROLE.dealer):
  386. response = gen_login_response(agentId)
  387. else:
  388. agent = Agent.objects(id=str(request.user.agentId)).get()
  389. if (not agentId) or (agentId == request.user.agentId) or (agentId == str(agent.primary_agent.id)):
  390. agentId = request.user.agentId
  391. response = gen_home_response(agentId)
  392. else:
  393. response = gen_login_response(agentId)
  394. return response
  395. def subAccountAccess(request):
  396. agentId = request.GET.get('agentId', '')
  397. if not is_login(request, ROLE.subaccount):
  398. response = gen_subaccount_login_response(agentId)
  399. else:
  400. agent = Agent.objects(id=str(request.user.agentId)).get()
  401. if (not agentId) or (agentId == request.user.agentId) or (agentId == str(agent.primary_agent.id)):
  402. agentId = request.user.agentId
  403. response = gen_home_response(agentId)
  404. else:
  405. response = gen_subaccount_login_response(agentId)
  406. return response
  407. def login(request):
  408. # type: (WSGIRequest)->JsonResponse
  409. username = request.POST.get('name', None)
  410. password = request.POST.get('password', None)
  411. agentId = request.POST.get('agentId')
  412. if not agentId:
  413. return JsonResponse({'result': 100, 'description': u'未选择对应的代理商,请刷新后在试', 'payload': {}})
  414. if not all([username, password]):
  415. response = JsonResponse({'result': 0, 'description': u'缺少用户名或密码', 'payload': {}})
  416. else:
  417. response = dealer_login(request, logger, username, password, agentId=agentId)
  418. if agentId != request.COOKIES.get('agentId', None):
  419. Agent.record_cookie(agentId, response)
  420. return response
  421. def subAccountLogin(request):
  422. username = request.POST.get('name', None)
  423. password = request.POST.get('password', None)
  424. agentId = request.POST.get('agentId')
  425. if not all([username, password]):
  426. response = JsonResponse({'result': 0, 'description': u'缺少用户名或密码', 'payload': {}})
  427. else:
  428. response = subAccount_login(request, logger, username, password, agentId=agentId)
  429. if agentId != request.COOKIES.get('agentId', None):
  430. Agent.record_cookie(agentId, response)
  431. response.set_cookie(key='sub_account_login_agentid', value=str(agentId), max_age=24 * 3600 * 30, domain = settings.COOKIE_DOMAIN)
  432. return response
  433. @permission_required(ROLE.dealer, ROLE.subaccount)
  434. def homepageData(request):
  435. # type: (WSGIRequest)->JsonResponse
  436. currentDealer = request.user # type: Optional[Dealer, SubAccount]
  437. dealer = request.user.myBoss # type: Dealer
  438. # 显示经销商的总余额(资金池+消费分润) 分两级显示
  439. deviceBalance = dealer.sub_balance(DEALER_INCOME_TYPE.DEVICE_INCOME)
  440. ledgerBalance = dealer.sub_balance(DEALER_INCOME_TYPE.LEDGER_CONSUME)
  441. payload = {
  442. 'totalBalance': deviceBalance + ledgerBalance,
  443. 'deviceBalance': deviceBalance,
  444. 'ledgerBalance': ledgerBalance
  445. }
  446. groupIds = Group.get_group_ids_of_dealer(str(dealer.id))
  447. partnerGroupIds = Group.get_group_ids_of_partner(str(dealer.id))
  448. groupIds.extend(partnerGroupIds)
  449. devList = Device.get_devices_by_group(groupIds).values()
  450. offlineCount, expireCount, allCount = 0, 0, 0
  451. for dev in devList: # type: DeviceDict
  452. allCount += 1
  453. if not dev.online:
  454. offlineCount += 1
  455. if dev.is_authorized_to_dealer(str(dealer.id)) and (dev.sim_expire_notify or dev.is_expired):
  456. expireCount += 1
  457. onlineCount = allCount - offlineCount
  458. payload.update({'onlineCount': onlineCount, 'offlineCount': offlineCount})
  459. payload['adShow'] = currentDealer.adShow
  460. payload['feedback'] = FeedBack.get_unhandled_count(ownerId=str(dealer.id))
  461. if expireCount > 0:
  462. payload['simCardTip'] = {
  463. 'expireCount': expireCount,
  464. 'todoMsg': TodoMessage.sim_expire_message(str(currentDealer.id), expireCount)
  465. }
  466. payload['pushBrokerUrl'] = currentDealer.pushBrokerUrl
  467. payload['isPurePartner'] = currentDealer.isPurePartner
  468. payload['inhouseApp'] = currentDealer.is_inhouse_wallet
  469. # 获取agent的相关信息
  470. resultResponse = JsonResponse({'result': 1, 'description': None, 'payload': payload})
  471. resultResponse = Agent.record_cookie(currentDealer.agentId, resultResponse)
  472. return resultResponse
  473. @error_tolerate(nil=JsonErrorResponse(u'上分失败,请重试'))
  474. @permission_required(ROLE.dealer, ROLE.subaccount)
  475. def onPoints(request):
  476. # type: (WSGIRequest)->JsonResponse
  477. """
  478. 远程上分, 支持经销商和代理商进行操作,代理商通过上分测试机器系统流程正确。
  479. :param request:
  480. :return:
  481. """
  482. TYPE_POINTS = ''
  483. TYPE_CHARGE_CARD = 'chargeCard'
  484. def __points__(dev, ruleId):
  485. smartBox = ActionDeviceBuilder.create_action_device(dev)
  486. if dev.support_reliable:
  487. orderNo = dev.ownerId[-10:]+ConsumeRecord.make_no()
  488. order = ConsumeRecord(orderNo=orderNo, openId=dev.ownerId)
  489. order.package = dev.get('washConfig',{}).get(ruleId)
  490. order.attachParas = attachParas
  491. smartBox.start_device_realiable(order)
  492. lineInfo = {'port':attachParas.get('chargeIndex'), 'status':Const.DEV_WORK_STATUS_WORKING}
  493. Device.update_port_control_cache(dev.devNo, lineInfo)
  494. else:
  495. smartBox.start(ruleId, openId = None, attachParas = attachParas)
  496. address = Group.get_group(dev['groupId'])['address']
  497. groupName = Group.get_group(dev['groupId'])['groupName']
  498. score = dev.get('washConfig', {}).get(ruleId, {}).get('coins', 0)
  499. UpscoreRecord(
  500. logicalCode=dev['logicalCode'],
  501. devNo=devNo,
  502. ownerId=ownerId,
  503. time=datetime.datetime.now(),
  504. score=score,
  505. address=address,
  506. groupName=groupName,
  507. devType=dev['devType']['name'],
  508. type=TYPE_POINTS
  509. ).save()
  510. def __charge_card(dev, price):
  511. smartBox = ActionDeviceBuilder.create_action_device(dev)
  512. smartBox.remote_charge_card(price)
  513. address = Group.get_group(dev['groupId'])['address']
  514. groupName = Group.get_group(dev['groupId'])['groupName']
  515. UpscoreRecord(
  516. logicalCode=dev['logicalCode'],
  517. devNo=devNo,
  518. ownerId=ownerId,
  519. time=datetime.datetime.now(),
  520. score=price,
  521. address=address,
  522. groupName=groupName,
  523. devType=dev['devType']['name'],
  524. type=TYPE_CHARGE_CARD
  525. ).save()
  526. def __huopo_points(dev):
  527. ruleId = "1"
  528. smartBox = ActionDeviceBuilder.create_action_device(dev)
  529. smartBox.start(ruleId, openId = None, attachParas = attachParas)
  530. address = Group.get_group(dev['groupId'])['address']
  531. groupName = Group.get_group(dev['groupId'])['groupName']
  532. score = 0
  533. UpscoreRecord(
  534. logicalCode=dev['logicalCode'],
  535. devNo=devNo,
  536. ownerId=ownerId,
  537. time=datetime.datetime.now(),
  538. score=score,
  539. address=address,
  540. groupName=groupName,
  541. devType=dev['devType']['name'],
  542. type=TYPE_POINTS
  543. ).save()
  544. def __policy_points__(dev, ruleId):
  545. smartBox = ActionDeviceBuilder.create_action_device(dev)
  546. if dev.support_reliable:
  547. orderNo = dev.ownerId[-10:]+ConsumeRecord.make_no()
  548. order = ConsumeRecord(orderNo=orderNo, openId=dev.ownerId)
  549. order.package = smartBox.prepare_package(ruleId, attachParas)
  550. order.attachParas = attachParas
  551. smartBox.start_device_realiable(order)
  552. lineInfo = {
  553. 'port': attachParas.get('chargeIndex'),
  554. 'status': Const.DEV_WORK_STATUS_WORKING,
  555. 'nickName': '经销商远程上分',
  556. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  557. }
  558. data = smartBox._check_package(order.package)
  559. if 'needTime' in data:
  560. lineInfo.update({'needTime': data['needTime']})
  561. if 'needElec' in data:
  562. lineInfo.update({'needElec': data['needElec']})
  563. Device.update_port_control_cache(dev.devNo, lineInfo)
  564. address = Group.get_group(dev['groupId'])['address']
  565. groupName = Group.get_group(dev['groupId'])['groupName']
  566. UpscoreRecord(
  567. logicalCode=dev['logicalCode'],
  568. devNo=devNo,
  569. ownerId=ownerId,
  570. time=datetime.datetime.now(),
  571. package=order.package,
  572. address=address,
  573. groupName=groupName,
  574. devType=dev['devType']['name'],
  575. type=TYPE_POINTS
  576. ).save()
  577. try:
  578. ownerId = str(request.user.bossId)
  579. logicalCode = request.POST.get('logicalCode', None)
  580. attachParas = json.loads(request.POST.get('attachParas', '{}'))
  581. attachParas['onPoints'] = True
  582. type = request.POST.get('type', '')
  583. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  584. dev = Device.get_dev(devNo)
  585. if not dev:
  586. return JsonResponse({'result': 2, 'description': u'设备不存在'})
  587. if dev['ownerId'] != ownerId:
  588. return JsonResponse({'result': 2, 'description': u'不是你家设备,不能操作喔'})
  589. dealer = dev.owner
  590. agent = Agent.objects.filter(id=str(dealer.agentId)).first() # type: Agent
  591. if 'disable_dealer_onPoints_and_sendCoins' in agent.features:
  592. return JsonResponse(
  593. {'result': 0, 'description': '设备无法使用该功能奥, 如有问题, 请联系代理商', 'payload': {}})
  594. # 霍珀的道闸适配
  595. if dev["devType"]["code"] == Const.DEVICE_TYPE_CODE_HP_GATE:
  596. __huopo_points(dev)
  597. return JsonResponse({'result': 1, 'description': u'success'})
  598. if dev["devType"]["code"] in support_policy_device:
  599. ruleId = request.POST.get('ruleId', None)
  600. __policy_points__(dev, ruleId)
  601. return JsonResponse({'result': 1, 'description': u'success'})
  602. if type == TYPE_POINTS:
  603. ruleId = request.POST.get('ruleId', None)
  604. # 如果是串口设备,上分的话,直接使用套餐。这里把串口和非串口的上分统一起来,行为应该有创建者创建具备行为的实例
  605. if not ruleId:
  606. return JsonResponse(
  607. {'result': 0, 'description': u'没有找到对应的套餐信息,请您重新选择其他分值.或者检查设备是否没有注册到系统', 'payload': {}})
  608. __points__(dev, ruleId)
  609. elif type == TYPE_CHARGE_CARD:
  610. price = int(request.POST.get('coins', 0))
  611. if price <= 0:
  612. return JsonResponse({'result': 0, 'description': u'充值金额错,请重新输入', 'payload': {}})
  613. __charge_card(dev, price)
  614. return JsonResponse({'result': 1, 'description': u'success'})
  615. except ServiceException, e:
  616. logger.exception(e)
  617. return JsonResponse(e.result)
  618. @permission_required(ROLE.dealer, ROLE.subaccount)
  619. def onPointsRecords(request):
  620. # type: (WSGIRequest)->JsonResponse
  621. """
  622. 上分记录查询
  623. :param request:
  624. :return:
  625. """
  626. ownerId = str(request.user.bossId)
  627. pageIndex = int(request.GET.get('pageIndex', 1))
  628. pageSize = int(request.GET.get('pageSize', 10))
  629. objs = UpscoreRecord.objects.filter(ownerId=ownerId).order_by('-time')
  630. rcdList = []
  631. total = 0
  632. sumCoins = 0
  633. sumCoinsTotal = 0
  634. sumCharge = 0
  635. sumChargeTotal = 0
  636. for obj in objs:
  637. if obj.type == 'chargeCard':
  638. sumCharge += obj.score
  639. sumChargeTotal += 1
  640. else:
  641. sumCoins += obj.score
  642. sumCoinsTotal += 1
  643. total += 1
  644. rcdList.append({
  645. 'logicalCode': obj.logicalCode,
  646. 'devNo': obj.devNo,
  647. 'createdStr': obj.time.strftime('%Y-%m-%d %H:%M:%S'),
  648. 'coins': obj.score,
  649. 'et_type_name': obj.devType,
  650. 'address': obj.address,
  651. 'groupName': obj.groupName,
  652. 'type': obj.type})
  653. return JsonResponse({
  654. "result": 1,
  655. "description": None,
  656. "payload": {
  657. "sumCoins": sumCoins,
  658. 'sumCoinsTotal': sumCoinsTotal,
  659. 'sumCharge': sumCharge,
  660. 'sumChargeTotal': sumChargeTotal,
  661. "rcds": {
  662. "total": total,
  663. "items": rcdList[(pageIndex - 1) * pageSize:pageIndex * pageSize],
  664. }
  665. }
  666. })
  667. @permission_required(ROLE.dealer, ROLE.subaccount)
  668. def handlerKeepingOrder(request):
  669. """
  670. 关闭订单取消订单
  671. 霍珀道闸 由于出现后付费的情况,可能存在两种情况需要将订单取消 用户扫码进门,创建了订单但是门没开 用户扫码出门,钱已经扣了但门没开
  672. 此接口 供经销商对于此类订单的处理
  673. """
  674. TYPE_CANCEL = "cancel"
  675. TYPE_CLOSE = "close"
  676. _id = request.GET.get("id")
  677. _type = request.GET.get("type")
  678. # 取消订单
  679. sp = ServiceProgress.objects.get(id=_id)
  680. sp.isFinished = True
  681. sp.finished_time = int(time.time())
  682. order = ConsumeRecord.objects.get(id=sp.consumes[0])
  683. if _type == TYPE_CLOSE:
  684. order.isNormal = True
  685. order.finishedTime = datetime.datetime.now()
  686. order.remarks = u"经销商 %s 关闭订单" % request.user.nickname
  687. serviceInfo = {
  688. "finishedTime": str(order.finishedTime)[:19],
  689. }
  690. order.serviceInfo = serviceInfo
  691. elif _type == TYPE_CANCEL:
  692. order.finishedTime = datetime.datetime.now()
  693. order.remarks = u"经销商 %s 取消订单" % request.user.nickname
  694. order.isNormal = False
  695. try:
  696. sp.save()
  697. order.save()
  698. except Exception as e:
  699. logger.exception(e)
  700. return JsonResponse({'result': 0, 'description': u'数据查询出错', 'payload': {}})
  701. else:
  702. # 清除该停车数量 无论是终止订单还是取消订单,其进车数量始终 需要 -1
  703. key = "maxParking"
  704. if order.attachParas.get("vCardId"):
  705. key = "VIPMaxParking"
  706. serviceInfo = HuopoCacheMgr.get_parking_cache(order.groupId)
  707. if serviceInfo is not None:
  708. parkingInfo = serviceInfo.get("parkingInfo", {})
  709. parkingNum = parkingInfo.get(key, 0)
  710. else:
  711. parkingInfo = {}
  712. parkingNum = 0
  713. if parkingNum > 0:
  714. parkingNum -= 1
  715. parkingInfo.update({key: parkingNum})
  716. HuopoCacheMgr.set_parking_cache(order.groupId, {"parkingInfo": parkingInfo})
  717. return JsonResponse({'result': 1, 'description': u'success'})
  718. @permission_required(ROLE.dealer, ROLE.subaccount)
  719. def getKeepingOrder(request):
  720. """
  721. 获取正在进行的订单
  722. """
  723. pageIndex = int(request.GET.get("pageIndex", 1))
  724. pageSize = int(request.GET.get("pageSize", 10))
  725. ownerId = str(request.user.bossId)
  726. logicalCode = request.GET.get('logicalCode', None)
  727. attachParas = json.loads(request.POST.get('attachParas', '{}'))
  728. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  729. dev = Device.get_dev(devNo)
  730. if not dev:
  731. return JsonResponse({'result': 0, 'description': u'设备不存在'})
  732. if dev['ownerId'] != ownerId:
  733. return JsonResponse({'result': 0, 'description': u'不是你家设备,不能操作喔'})
  734. sps = ServiceProgress.objects.filter(device_imei=devNo, devTypeCode=dev["devType"]["code"], isFinished=False).all()
  735. dataList = list()
  736. for sp in sps:
  737. user = MyUser.objects.filter(openId=sp.open_id).first()
  738. order = ConsumeRecord.objects.get(id=sp.consumes[0])
  739. tempData = {
  740. "id": sp.id,
  741. "nickname": user.nickname,
  742. "avatar": user.avatar,
  743. "startTime": order.time
  744. }
  745. dataList.append(tempData)
  746. return JsonResponse(
  747. {'result': 1,
  748. 'description': u'',
  749. 'payload':
  750. {
  751. "total": len(dataList),
  752. "dataList": dataList[(pageIndex-1)*pageSize: pageIndex*pageSize]
  753. }
  754. })
  755. # 获取默认地址
  756. @permission_required(ROLE.dealer, ROLE.subaccount)
  757. def groupInfo(request):
  758. # 获取默认地址
  759. def groupInfoDefault(request):
  760. # type: (WSGIRequest)->JsonResponse
  761. groupId = request.GET.get('groupId', None)
  762. ownerId = str(request.user.bossId)
  763. group = Group.get_group(groupId)
  764. if group is None:
  765. return JsonResponse({"result": 0, "description": u"没有找到地址信息", "payload": {}})
  766. if group['ownerId'] == ownerId:
  767. group['isManager'] = True
  768. else:
  769. group['isManager'] = False
  770. groupOwner = Dealer.get_dealer(group['ownerId'])
  771. group['managerName'] = groupOwner['nickname'] + " " + groupOwner['username']
  772. group['partner'] = group['partnerDict'].values()
  773. for partner in group['partner']:
  774. if partner['id'] == ownerId:
  775. partner['self'] = True
  776. else:
  777. reload_parter = Dealer.get_dealer(partner['id'])
  778. partner['tel'] = reload_parter['username']
  779. partner['name'] = reload_parter['nickname']
  780. partner['self'] = False
  781. # 添加 合伙人商户的状态给前台显示 如果合伙人商户的状态是 初始状态 需要为合伙人绑定银行卡
  782. partner = Dealer.objects.get(id=partner["id"])
  783. district = District.get_district(group['districtId'])
  784. group['district'] = district
  785. if not group['isManager']:
  786. for i in range(len(group['partner'])-1,-1,-1):
  787. if not group['partner'][i]['self']:
  788. del group['partner'][i]
  789. return JsonResponse({"result": 1, "description": None, "payload": group})
  790. current_user = request.user # type: UserSearchable
  791. return groupInfoDefault(request)
  792. @permission_required(ROLE.dealer, ROLE.subaccount)
  793. def groupIncomeData(request):
  794. # type: (WSGIRequest)->JsonResponse
  795. """
  796. 查询地址组的收益
  797. 地址组收益的记录方式已经发生了改变 对于收益的部分 记录在 daily.incomeMap下面的数据,每个经销商一条,为总的收益,没有明细划分
  798. :param request:
  799. :return:
  800. """
  801. def get_group_info(g, _id):
  802. isM = _id == g.get("ownerId")
  803. if not isM:
  804. p = round_2_digits(float(g.get("partnerDict", dict()).get(_id, dict()).get("percent", 0)))
  805. else:
  806. fullPercent = 100
  807. for _partner in g.get("partnerDict", dict()).values():
  808. fullPercent -= float(_partner.get("percent", 0))
  809. p = round_2_digits(float(fullPercent))
  810. return isM, p
  811. current_user = request.user # type: Dealer
  812. dealerId = str(current_user.bossId)
  813. pageIndex = int(request.GET.get("pageIndex", 1))
  814. pageSize = int(request.GET.get("pageSize", 10))
  815. startDate = request.GET.get("startTime")
  816. endDate = request.GET.get("endTime")
  817. startDate, endDate = current_user.limit_filter_date(startDate, endDate)
  818. if endDate < startDate:
  819. return JsonResponse({
  820. 'result': 1, 'description': '', 'payload': {
  821. "total": 0,
  822. "dataList": [],
  823. "adShow": current_user.adShow
  824. }})
  825. else:
  826. searchKey = request.GET.get("searchKey", None)
  827. # 通过searchKey 获取组地址 作为查询的筛选条件
  828. # TODO 这个地方有一个问题在于 如果 地址组的合伙人一旦修改 之前的合伙人无法看到历史的数据 而新的合伙人能看到之前的数据
  829. groupIds = Group.search_group_ids_of_dealer(
  830. dealerId, searchKey
  831. ) + Group.search_group_ids_of_partner(
  832. dealerId, searchKey
  833. )
  834. groupIdSlice = groupIds[(pageIndex - 1) * pageSize: pageSize * pageIndex]
  835. if not groupIdSlice:
  836. return JsonResponse({
  837. 'result': 1, 'description': '', 'payload': {
  838. "total": len(groupIds),
  839. "dataList": [],
  840. "adShow": current_user.adShow
  841. }})
  842. groupStatisticMap = GroupDailyStatsModelProxy.get_groups_income_statistic(groupIds=groupIdSlice, startDate=startDate, endDate=endDate, dealerId=dealerId)
  843. groupDevCountMap = Device.get_device_count_by_group(groupIdSlice)
  844. rptDict = GroupReport.get_rpt(groupIdSlice, startDate, endDate) # 投币的信息
  845. # 经销商的特性判断 的相关信息的获取
  846. dealer = Dealer.objects.get(id=dealerId)
  847. showOfflineCoin = True if 'show_offline_coins' in dealer.features else False
  848. # 整合数据
  849. dataList = list()
  850. for _groupId in groupIdSlice:
  851. # 统计信息的过滤
  852. groupStatistic = groupStatisticMap.get(_groupId, {})
  853. # 要提前将这个不存在的统计值pop出来
  854. dealerActualIncome = RMB(groupStatistic.pop("dealerActualIncome", 0))
  855. incomeList = translate_income(groupStatistic)
  856. totalIncome = sum_rmb(_['value'] for _ in incomeList)
  857. # 组信息 以及分成比例的计算
  858. group = Group.get_group(_groupId) or dict()
  859. isManager, percent = get_group_info(group, dealerId)
  860. value = {
  861. "groupName": group.get("groupName", ""),
  862. "groupId": _groupId,
  863. "address": group.get("address", ""),
  864. "equipmentCount": groupDevCountMap.get(_groupId, 0),
  865. "isManager": isManager,
  866. "percent": percent,
  867. "agentProfitShare": request.user.agentProfitShare,
  868. "offlineCoins": rptDict.get(_groupId, dict()).get('lineCoins', 0),
  869. "incomeList": incomeList,
  870. "totalIncome": totalIncome,
  871. "dealerActualIncome": dealerActualIncome
  872. }
  873. if not showOfflineCoin:
  874. value.pop('offlineCoins', None)
  875. dataList.append(value)
  876. # 对 totalIncome 排序 优先返回金额最多的地址组
  877. dataList = sorted(dataList, key=lambda x: float(x["totalIncome"]), reverse=True)
  878. total = len(groupIds)
  879. return JsonResponse({"result": 1, "description": None, "payload": {
  880. "total": total,
  881. "dataList": dataList,
  882. "adShow": current_user.adShow
  883. }})
  884. @permission_required(ROLE.dealer, ROLE.subaccount)
  885. def getDevOffLineCoinStatByGroupId(request):
  886. # type: (WSGIRequest)->JsonResponse
  887. groupId = request.GET.get('groupId')
  888. group = Group.get_group(groupId)
  889. if not group:
  890. return JsonErrorResponse(u'找不到组ID')
  891. pageIndex = int(request.GET.get('pageIndex', 1))
  892. pageSize = int(request.GET.get('pageSize', 10))
  893. startDate = defaultTodayDate(request.GET.get('startTime'))
  894. endDate = defaultTodayDate(request.GET.get('endTime'))
  895. total = Device.get_collection().find({'groupId': groupId}).count()
  896. devNoList = Device.get_devNos_by_group([groupId])
  897. devInfo = Device.get_dev_by_nos(devNoList)
  898. dataList = [
  899. {
  900. 'logicalCode': devInfo[devNo]['logicalCode'],
  901. 'groupNumber': devInfo[devNo]['groupNumber'],
  902. 'devTypeName': devInfo[devNo].get('devType', {}).get('name', ''),
  903. 'offlineCoins': rpt['lineCoins'],
  904. }
  905. for devNo, rpt in DevReport.get_rpt(devNoList, startDate, endDate).iteritems()
  906. ]
  907. return JsonResponse(
  908. {
  909. 'result': 1,
  910. 'description': '',
  911. 'payload':
  912. {
  913. 'total': total,
  914. 'groupName': group['groupName'],
  915. 'dataList': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  916. }
  917. }
  918. )
  919. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  920. @permission_required(ROLE.dealer, ROLE.subaccount)
  921. def groupIncomeByGroupId(request):
  922. # type: (WSGIRequest)->JsonResponse
  923. """
  924. 获取 单一地址组的 收益 聚合信息
  925. :param request:
  926. :return:
  927. """
  928. dealerId = str(request.user.bossId)
  929. groupId = request.GET.get("groupId")
  930. startDate = request.GET.get("startTime")
  931. endDate = request.GET.get("endTime")
  932. if not groupId:
  933. return JsonErrorResponse(description=u'未提供地址ID')
  934. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  935. return JsonErrorResponse(description=u'无权限查看')
  936. group = Group.get_group(groupId)
  937. if not group:
  938. return JsonErrorResponse(description=u'组不存在')
  939. groupStatistic = GroupDailyStatsModelProxy.get_one_group_income_statistic(groupId, startDate, endDate)
  940. incomeTotalList = [{"name": u"总收益", "value": RMB(groupStatistic.get("totalIncome", 0))}]
  941. for _item in translate_income(groupStatistic):
  942. if _item.get("value", RMB(0)) > RMB(0):
  943. incomeTotalList.append(_item)
  944. return JsonResponse(
  945. {
  946. 'result': 1,
  947. 'description': 'ok',
  948. 'payload': {
  949. 'groupName': group['groupName'],
  950. "incomeTotalList": incomeTotalList
  951. }
  952. }
  953. )
  954. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  955. @permission_required(ROLE.dealer, ROLE.subaccount)
  956. def groupConsumptionByGroupId(request):
  957. # type: (WSGIRequest)->JsonResponse
  958. """
  959. 获取 单一地址组的 收益 聚合信息
  960. :param request:
  961. :return:
  962. """
  963. dealerId = str(request.user.bossId)
  964. groupId = request.GET.get("groupId")
  965. startDate = request.GET.get("startTime")
  966. endDate = request.GET.get("endTime")
  967. if not groupId:
  968. return JsonErrorResponse(description=u'未提供地址ID')
  969. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  970. return JsonErrorResponse(description=u'无权限查看')
  971. group = Group.get_group(groupId)
  972. if not group:
  973. return JsonErrorResponse(description=u'组不存在')
  974. groupStatistic = GroupDailyStatsModelProxy.get_one_group_consumption_statistic(groupId, startDate, endDate)
  975. agent = Agent.objects.get(id=request.user.agentId) # type: Agent
  976. consumptionTotalList = list()
  977. for _item in translate_consumption(groupStatistic, agent.hide_consume_kinds_dealer):
  978. if _item.get("value", Quantity(0)) > Quantity(0):
  979. consumptionTotalList.append(_item)
  980. return JsonResponse(
  981. {
  982. 'result': 1,
  983. 'description': 'ok',
  984. 'payload': {
  985. 'groupName': group['groupName'],
  986. "incomeTotalList": consumptionTotalList
  987. }
  988. }
  989. )
  990. EXTRA_INCOME_DEVICE_TYPE_CODES = [Const.DEVICE_TYPE_CODE_WASHCAR_LSHB]
  991. def realtime_income_available(typeCode):
  992. # type:(str)->bool
  993. return typeCode in EXTRA_INCOME_DEVICE_TYPE_CODES
  994. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  995. @permission_required(ROLE.dealer, ROLE.subaccount)
  996. def getRealtimeIncomeByDev(request):
  997. # type: (WSGIRequest)->JsonResponse
  998. # TODO 建立一个缓存的permission map 来将经销商ID与设备等相关权限对应起来
  999. logicalCode = request.GET.get('logicalCode')
  1000. device = Device.get_dev_by_logicalCode(logicalCode)
  1001. if not device:
  1002. return JsonErrorResponse(description=u'设备不存在')
  1003. typeCode = device['devType']['code']
  1004. if realtime_income_available(typeCode):
  1005. return JsonErrorResponse(description=u'不支持当前设备查询实时收入')
  1006. translation = {
  1007. 'cardFee': u'刷卡总额',
  1008. 'coinFee': u'投币总额',
  1009. 'mobileFee': u'支付总额'
  1010. }
  1011. if typeCode == Const.DEVICE_TYPE_CODE_CHARGING_SIJIANG:
  1012. try:
  1013. smartBox = ActionDeviceBuilder.create_action_device(device)
  1014. conf = smartBox.get_dev_consume_count()
  1015. return JsonResponse(
  1016. {
  1017. 'result': 1,
  1018. 'description': '',
  1019. 'payload':
  1020. {
  1021. 'realTimeIncome': [
  1022. {'name': translation[k], 'value': v} for k, v in conf.iteritems() if k in translation
  1023. ]
  1024. }
  1025. })
  1026. except ServiceException as e:
  1027. logger.debug('cannot get_extra_income_by_specific_devices device=%s' % (device,))
  1028. logger.exception(e)
  1029. return JsonErrorResponse(description=u'网络不畅通,请稍后再试')
  1030. elif typeCode == Const.DEVICE_TYPE_CODE_WASHCAR_LSHB:
  1031. try:
  1032. # 获取设备上的卡的总收入、投币的总收入
  1033. smartBox = ActionDeviceBuilder.create_action_device(device)
  1034. mapping = {
  1035. 'cardFee': smartBox.get_card_count(),
  1036. 'coinFee': smartBox.get_coins_count()
  1037. }
  1038. return JsonResponse(
  1039. {
  1040. 'result': 1,
  1041. 'description': '',
  1042. 'payload': {
  1043. 'realTimeIncome': [{'name': translation[k], 'value': v} for k, v in mapping.iteritems() if
  1044. k in translation]
  1045. }
  1046. })
  1047. except ServiceException as e:
  1048. logger.debug('cannot get_extra_income_by_specific_devices device=%s' % (device,))
  1049. logger.exception(e)
  1050. return JsonErrorResponse(description=u'网络不畅通,请稍后再试')
  1051. else:
  1052. return JsonErrorResponse(description=u'不支持当前设备查询实时收入')
  1053. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  1054. @permission_required(ROLE.dealer, ROLE.subaccount)
  1055. def groupEquipmentIncomeByGroupId(request):
  1056. # type: (WSGIRequest)->JsonResponse
  1057. """
  1058. 获取组下设备按日期收益聚合数据
  1059. :param request:
  1060. :return:
  1061. """
  1062. # TODO Nicolas 此接口以及 groupEquipmentConsumptionByGroupId 存在问题
  1063. # TODO Nicolas 当该地址下设备信息发生变更的时候 ,通过 GroupDaily 获取的信息 和通过 DeviceDaily 聚合获取的信息会不一致
  1064. dealerId = str(request.user.bossId)
  1065. groupId = request.GET.get("groupId", None)
  1066. pageIndex = int(request.GET.get('pageIndex', 1))
  1067. pageSize = int(request.GET.get('pageSize', 10))
  1068. startDate = request.GET.get('startTime')
  1069. endDate = request.GET.get('endTime')
  1070. if groupId is None:
  1071. return JsonErrorResponse(description=u'未找到地址组,请重试')
  1072. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  1073. return JsonErrorResponse(description=u'无权限查看')
  1074. group = Group.get_group(groupId)
  1075. if not group:
  1076. return JsonErrorResponse(description=u'组不存在')
  1077. # 获取设备的日统计信息
  1078. logicalCodes = Device.get_logicalCode_by_groupId(groupId)
  1079. logicalCodeSlice = sorted(logicalCodes[(pageIndex - 1) * pageSize: pageIndex * pageSize])
  1080. statisticMap = DeviceDailyStatsModelProxy.get_devices_income_statistic(logicalCodeSlice, startDate, endDate)
  1081. dataList = list()
  1082. for logicalCode in logicalCodeSlice:
  1083. devStatistic = translate_income(statisticMap.get(logicalCode, dict()))
  1084. devStatistic = [_statistic for _statistic in devStatistic if _statistic["value"] > RMB(0)]
  1085. dev = Device.get_dev_by_l(logicalCode)
  1086. dataList.append({
  1087. "incomeList": devStatistic,
  1088. "logicalCode": logicalCode,
  1089. "groupId": groupId,
  1090. "type": dev.get("devType", dict()).get("name"),
  1091. 'groupNumber': dev.get('groupNumber'),
  1092. 'realtimeIncomeAvailable': realtime_income_available(dev.get('devType', dict()).get('code'))
  1093. })
  1094. return JsonResponse(
  1095. {
  1096. 'result': 1,
  1097. 'description': None,
  1098. 'payload': {
  1099. 'total': len(logicalCodes),
  1100. 'dataList': dataList
  1101. }
  1102. }
  1103. )
  1104. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  1105. @permission_required(ROLE.dealer, ROLE.subaccount)
  1106. def groupEquipmentConsumptionByGroupId(request):
  1107. # type: (WSGIRequest)->JsonResponse
  1108. """
  1109. 获取组下设备按日期消费聚合数据
  1110. :param request:
  1111. :return:
  1112. """
  1113. dealerId = str(request.user.bossId)
  1114. groupId = request.GET.get("groupId", None)
  1115. pageIndex = int(request.GET.get('pageIndex', 1))
  1116. pageSize = int(request.GET.get('pageSize', 10))
  1117. startDate = request.GET.get('startTime')
  1118. endDate = request.GET.get('endTime')
  1119. if groupId is None:
  1120. return JsonErrorResponse(description=u'未找到地址组,请重试')
  1121. if groupId not in Group.get_group_ids_of_dealer_and_partner(dealerId):
  1122. return JsonErrorResponse(description=u'无权限查看')
  1123. group = Group.get_group(groupId)
  1124. if not group:
  1125. return JsonErrorResponse(description=u'组不存在')
  1126. # 获取设备的日统计信息
  1127. logicalCodes = Device.get_logicalCode_by_groupId(groupId)
  1128. logicalCodeSlice = sorted(logicalCodes[(pageIndex-1)*pageSize: pageIndex*pageSize])
  1129. statisticMap = DeviceDailyStatsModelProxy.get_devices_consumption_statistic(logicalCodeSlice, startDate, endDate)
  1130. agent = Agent.objects.get(id = request.user.agentId) # type: Agent
  1131. dataList = list()
  1132. for logicalCode in logicalCodeSlice:
  1133. devStatistic = translate_consumption(statisticMap.get(logicalCode, dict()), hides = agent.hide_consume_kinds_dealer)
  1134. devStatistic = [_statistic for _statistic in devStatistic if _statistic["value"] > Quantity(0)]
  1135. dev = Device.get_dev_by_l(logicalCode)
  1136. dataList.append({
  1137. "consumptionList": devStatistic,
  1138. "logicalCode": logicalCode,
  1139. "groupId": groupId,
  1140. "type": dev.get("devType", dict()).get("name"),
  1141. 'groupNumber': dev.get('groupNumber'),
  1142. })
  1143. return JsonResponse(
  1144. {
  1145. 'result': 1,
  1146. 'description': "",
  1147. 'payload': {
  1148. 'total': len(logicalCodes),
  1149. 'dataList': dataList
  1150. }
  1151. }
  1152. )
  1153. def get_income_by_cat(stat, date_range, field):
  1154. return RMB(stat.get(date_range, {}).get('income', {}).get(field, 0))
  1155. def get_daily_income_by_cat(stat, field):
  1156. return get_income_by_cat(stat, 'daily', field)
  1157. def get_monthly_income_by_cat(stat, field):
  1158. return get_income_by_cat(stat, 'monthly', field)
  1159. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1160. def lastMonthIncome(request):
  1161. """
  1162. 按月统计 经销商的月收益
  1163. 获取的数据是当月的收益数据累加的 以及 每天的收益累计总和
  1164. :param request:
  1165. :return:
  1166. """
  1167. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1168. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y-%m"))
  1169. startDate, endDate = get_start_and_end_by_month(monthStr = timeStr)
  1170. rpts = {r['date']: r for r in DealerReport.get_rpts(dealerId, startDate, endDate)}
  1171. # 获取每一天的数据 首先要对时间参数进行鉴别 如果是本月的话,那么最后一天就是今天
  1172. dataList = list()
  1173. totalIncome, payIncome, offlineCoins = RMB(0), RMB(0), VirtualCoin(0)
  1174. rv = DealerDailyStatsModelProxy.get_days_income_stat(dealerId, timeStr)
  1175. for day, stat in rv.iteritems():
  1176. day_offline_count = VirtualCoin(rpts.get(day, {}).get('lineCoins', 0))
  1177. offlineCoins += day_offline_count
  1178. day_pay_income = RMB(get_in(["income", format(DEALER_INCOME_SOURCE.RECHARGE)], stat, default = 0)) + \
  1179. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.REDPACK)], stat, default = 0)) + \
  1180. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.RECHARGE_CARD)], stat, default = 0)) + \
  1181. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.RECHARGE_VIRTUAL_CARD)], stat, default = 0)) + \
  1182. RMB(get_in(["income", format(DEALER_INCOME_SOURCE.REFUND_CASH)], stat, default = 0))
  1183. payIncome += day_pay_income
  1184. day_total_income = RMB(get_in(["totalIncome"], stat, default = 0))
  1185. totalIncome += day_total_income
  1186. dataList.append({
  1187. 'dateStr': day,
  1188. 'dateText': u'%s年%s月%s日' % tuple(day.split('-')),
  1189. 'payIncome': day_pay_income,
  1190. 'offlineCoins': day_offline_count,
  1191. 'totalIncome': day_total_income
  1192. })
  1193. if dealerId == '5d132407003048494763a51b':
  1194. if int(timeStr[0:4]) < 2021:
  1195. dataList = []
  1196. offlineCoins = 0
  1197. payIncome = 0
  1198. totalIncome = 0
  1199. else:
  1200. pass
  1201. return JsonOkResponse(payload=
  1202. {
  1203. "adShow": request.user.adShow,
  1204. "totalIncome": totalIncome,
  1205. "payIncome": payIncome,
  1206. "offlineCoins": offlineCoins,
  1207. "dataList": dataList
  1208. })
  1209. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1210. def lastYearIncome(request):
  1211. # type: (WSGIRequest)->JsonResponse
  1212. """
  1213. 按年统计经销商的收益
  1214. :param request:
  1215. :return:
  1216. """
  1217. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1218. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y"))
  1219. timeStr = Dealer.limit_filter_year(dealerId, timeStr[0:4])
  1220. if not timeStr:
  1221. return JsonOkResponse(payload = {'adShow': request.user.adShow, 'dataList': []})
  1222. else:
  1223. startDay, endDay = get_start_and_end_by_year(timeStr)
  1224. monthRange = [datetime.datetime.strftime(item, "%Y-%m") for item in get_date_range(startDay, endDay, "MS")]
  1225. offline_report = DealerReportModelProxy.get_year_by_month(dealerId = dealerId, yearStr = timeStr)
  1226. # 获取一年里面 按月聚合分组的数据
  1227. statisticMap = DealerDailyStatsModelProxy.get_one_year_income_as_month(dealerId = dealerId, yearStr = timeStr)
  1228. dataList = list()
  1229. for month in monthRange:
  1230. monthIncomeMap = statisticMap.get(month, dict())
  1231. tempMonthStatistics = {
  1232. "totalIncome": RMB(monthIncomeMap.get("totalIncome", 0)),
  1233. "offlineCoins": VirtualCoin(
  1234. offline_report.get('%d-%02d' % tuple(map(int, month.split('-'))), {}).get('lineCoins', 0)),
  1235. "dateStr": month,
  1236. "dateText": u"{}年{}月".format(*month.split("-")),
  1237. "payIncome": sum([_v for _k, _v in monthIncomeMap.items() if
  1238. _k in [DEALER_INCOME_SOURCE.RECHARGE_VIRTUAL_CARD,
  1239. DEALER_INCOME_SOURCE.RECHARGE_CARD,
  1240. DEALER_INCOME_SOURCE.RECHARGE,
  1241. DEALER_INCOME_SOURCE.REFUND_CASH,
  1242. DEALER_INCOME_SOURCE.REDPACK]], RMB(0))
  1243. }
  1244. dataList.append(tempMonthStatistics)
  1245. return JsonOkResponse(payload = {'adShow': request.user.adShow, 'dataList': dataList})
  1246. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1247. def lastMonthConsumption(request):
  1248. # type: (WSGIRequest)->JsonResponse
  1249. """
  1250. 按月统计 经销商的消耗信息
  1251. :param request:
  1252. :return:
  1253. """
  1254. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1255. dealer = Dealer.objects.get(id=dealerId)
  1256. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y-%m"))
  1257. _year = Dealer.limit_filter_year(dealerId, timeStr[0:4])
  1258. if not _year:
  1259. return JsonOkResponse(payload = {'dataList': []})
  1260. else:
  1261. agent = Agent.objects.get(id = request.user.agentId)
  1262. dataList = list()
  1263. rv = DealerDailyStatsModelProxy.get_days_consume_stat(dealerId, timeStr)
  1264. for _day, stat in rv.iteritems():
  1265. consumptionList = translate_consumption(get_in(["consumption"], stat, dict()),
  1266. hides = agent.hide_consume_kinds_dealer)
  1267. if "not_show_about_elec" in dealer.features:
  1268. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"消耗电量"]
  1269. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"电费成本"]
  1270. dataList.append({
  1271. "dateStr": _day,
  1272. "dateText": u"{}年{}月{}日".format(*_day.split("-")),
  1273. "consumptionList": consumptionList
  1274. })
  1275. return JsonOkResponse(payload = {'dataList': dataList})
  1276. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  1277. def lastYearConsumption(request):
  1278. # type: (WSGIRequest)->JsonResponse
  1279. """
  1280. 一年的消费概览
  1281. :param request:
  1282. :return:
  1283. """
  1284. dealerId = request.GET.get('dealerId') or str(request.user.bossId)
  1285. timeStr = request.GET.get("time", datetime.date.today().strftime("%Y"))
  1286. timeStr = Dealer.limit_filter_year(dealerId, timeStr)
  1287. if not timeStr:
  1288. return JsonOkResponse(payload = {'dataList': []})
  1289. else:
  1290. # 获取统计的时间范围 获取月份的区间
  1291. startDay, endDay = get_start_and_end_by_year(timeStr)
  1292. monthRange = [datetime.datetime.strftime(item, "%Y-%m") for item in get_date_range(startDay, endDay, "MS")]
  1293. # 获取一年里面 按月聚合分组的消费数据
  1294. statisticMap = DealerDailyStatsModelProxy.get_one_year_consume_as_month(dealerId = dealerId, yearStr = timeStr)
  1295. # 消费信息 某些字段和特性相关联 先取出代理商的特性 留作判断
  1296. agent = Agent.objects.get(id = request.user.agentId)
  1297. dataList = list()
  1298. for _month in monthRange:
  1299. _item = statisticMap.get(_month, dict())
  1300. consumptionList = translate_consumption(_item, hides=agent.hide_consume_kinds_dealer)
  1301. dataList.append({
  1302. "dateStr": _month,
  1303. "dateText": u"{}年{}月".format(*_month.split("-")),
  1304. "consumptionList": consumptionList
  1305. })
  1306. return JsonOkResponse(payload={'dataList': dataList})
  1307. @permission_required(ROLE.dealer, ROLE.subaccount)
  1308. def updateInfo(request):
  1309. # type: (WSGIRequest)->JsonResponse
  1310. """
  1311. 支持经销商更改用户信息
  1312. :param request:
  1313. :return:
  1314. """
  1315. name = request.POST.get('name', '')
  1316. if NAME_RE.match(name) is None:
  1317. logger.info('update dealer name doesn\'t fit format, name=%s' % (name.encode('utf-8'),))
  1318. return JsonResponse({"result": 0, "description": "请输入正确格式的名称(2-20位)"})
  1319. if check_role(request.user, ROLE.dealer):
  1320. dealer = Dealer.objects(id=request.user.bossId).first() # type: Union[Dealer,None]
  1321. if dealer is None:
  1322. return JsonResponse({"result": 0, "description": "该经销商不存在"})
  1323. updated = dealer.update_dealer(ownerId=str(dealer.id), nickname=name)
  1324. if not updated:
  1325. logger.info('Dealer [updateInfo] failed, name=%s' % (name.encode('utf-8'),))
  1326. return JsonResponse({"result": 0, "description": u'更新失败,请重试'})
  1327. else:
  1328. return JsonResponse({"result": 1, "description": None})
  1329. else:
  1330. subaccount = SubAccount.objects(id=request.user.id).first() # type: Union[Dealer,None]
  1331. if subaccount is None:
  1332. return JsonResponse({"result": 0, "description": "该经销商不存在"})
  1333. updated = subaccount.update(nickname=name)
  1334. if not updated:
  1335. logger.info('subaccount [updateInfo] failed, name=%s' % (name.encode('utf-8'),))
  1336. return JsonResponse({"result": 0, "description": u'更新失败,请重试'})
  1337. else:
  1338. return JsonResponse({"result": 1, "description": None})
  1339. @permission_required(ROLE.dealer, ROLE.subaccount)
  1340. def verifyNewPhoneNumber(request):
  1341. # type: (WSGIRequest)->JsonResponse
  1342. """
  1343. 修改经销商手机号
  1344. :param request:
  1345. :return:
  1346. """
  1347. code = request.POST.get('code')
  1348. if not code:
  1349. return JsonResponse({"result": 0, "description": u'请输入验证码'})
  1350. phoneNumber = request.POST.get('phone')
  1351. if PHONE_NUMBER_RE.match(phoneNumber) is None:
  1352. logger.info('phone number format error, phone=%s' % phoneNumber)
  1353. return JsonResponse({"result": 0, "description": u"请输入正确的手机号码"})
  1354. if check_role(request.user, ROLE.dealer):
  1355. dealer = Dealer.objects(id=request.user.bossId).first() # type: Optional[Dealer]
  1356. if dealer is None:
  1357. return JsonResponse({"result": 0, "description": u"该经销商不存在"})
  1358. # : 检测是否系统内已有该号码,为了防止混淆
  1359. if Dealer.objects(username=phoneNumber).first():
  1360. return JsonResponse({"result": 0, "description": u"已存在与该手机号码绑定的账户"})
  1361. status, msg = dealerRegisterSMSProvider.verify(phoneNumber, code)
  1362. if status:
  1363. updated = dealer.update_dealer(ownerId=str(dealer.id), username=phoneNumber)
  1364. if updated:
  1365. Dealer.invalid_cache(dealer.id)
  1366. return JsonResponse({"result": 1, "description": None})
  1367. else:
  1368. return JsonResponse({"result": 0, "description": u'更换失败'})
  1369. else:
  1370. return JsonResponse({"result": 0, "description": msg})
  1371. else:
  1372. subAccount = SubAccount.objects(id=request.user.id,
  1373. agentId=request.user.agentId).first() # type: Optional[Dealer]
  1374. if subAccount is None:
  1375. return JsonResponse({"result": 0, "description": u"该子账号不存在"})
  1376. # : 检测是否系统内已有该号码,为了防止混淆
  1377. if SubAccount.objects(username=phoneNumber, agentId=request.user.agentId).first():
  1378. return JsonResponse({"result": 0, "description": u"已存在与该手机号码绑定的子账户"})
  1379. status, msg = dealerRegisterSMSProvider.verify(phoneNumber, code)
  1380. if status:
  1381. updated = subAccount.update(username=phoneNumber)
  1382. if updated:
  1383. return JsonResponse({"result": 1, "description": None})
  1384. else:
  1385. return JsonResponse({"result": 0, "description": u'更换失败'})
  1386. else:
  1387. return JsonResponse({"result": 0, "description": msg})
  1388. @permission_required(ROLE.dealer, ROLE.subaccount)
  1389. def setAddressFree(request):
  1390. # type: (WSGIRequest)->JsonResponse
  1391. """
  1392. 设置部分地址为免费地址, 其同一地址下所有设备都会供免费使用
  1393. :param request:
  1394. :return:
  1395. """
  1396. payload = parse_json_payload(request.body)
  1397. groupId = payload.get('groupId', None)
  1398. isFree = payload.get('isFree', False)
  1399. currentDealer = request.user.myBoss # type: Optional[Dealer]
  1400. if currentDealer.get_feature('disable_set_group_free').get('disable_set_group_free', False):
  1401. return JsonResponse(
  1402. {'result': 0, 'description': '设备无法使用该功能奥, 如有问题, 请联系代理商', 'payload': {}})
  1403. if groupId is None:
  1404. return JsonResponse({"result": 0, "description": u'地址不可为空'})
  1405. try:
  1406. Group.update_group(group_id=groupId, isFree=isFree)
  1407. return JsonResponse({"result": 1, "description": None})
  1408. except Exception as e:
  1409. logger.exception(e)
  1410. return JsonResponse({"result": 0, "description": u'修改失败'})
  1411. #### `经销商报表版块` ###############################################################
  1412. @permission_required(ROLE.dealer, ROLE.subaccount)
  1413. def dateCoins(request):
  1414. """
  1415. TODO 线下投币相关数据与收益计算展现彻底分离,接口需要重新审视
  1416. :param request:
  1417. :return:
  1418. """
  1419. ownerId = str(request.user.bossId)
  1420. now = datetime.datetime.now()
  1421. rpt = Accounting.getOwnerIncome(ownerId, now)
  1422. return JsonResponse({"result": 1, "description": None, 'payload': {"coins": rpt["lineCoins"]}})
  1423. @permission_required(ROLE.dealer, ROLE.subaccount)
  1424. def dateCoinsDetail(request):
  1425. """
  1426. TODO 线下投币相关数据与收益计算展现彻底分离,接口需要重新审视
  1427. :param request:
  1428. :return:
  1429. """
  1430. ownerId = str(request.user.bossId)
  1431. pageIndex = int(request.GET.get('pageIndex', 1))
  1432. pageSize = int(request.GET.get('pageSize', 10))
  1433. nowDate = datetime.datetime.now().strftime('%Y-%m-%d')
  1434. groupIds = Group.get_group_ids_of_dealer(ownerId)
  1435. devNos = Device.get_devNos_by_group(groupIds)
  1436. keys = [devCoinTmpl(devNo, nowDate) for devNo in devNos]
  1437. devCoinDict = reportCache.get_many(keys)
  1438. devNoList = []
  1439. for key, coins in devCoinDict.items():
  1440. coins = int(coins)
  1441. if coins == 0:
  1442. continue
  1443. tempList = key.split('_')
  1444. devNo = tempList[1]
  1445. devNoList.append({'devNo': devNo, 'coins_count': coins})
  1446. sorted(devNoList, key=lambda dev: dev['coins_count'], reverse=True)
  1447. total = len(devNoList)
  1448. resultDevDictList = devNoList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  1449. devNoList = [dev['devNo'] for dev in resultDevDictList]
  1450. devDict = Device.get_dev_by_nos(devNoList)
  1451. groupIds = [dev['groupId'] for dev in devDict.values()]
  1452. groupDict = Group.get_groups_by_group_ids(groupIds)
  1453. dataList = []
  1454. for dev in resultDevDictList:
  1455. if dev['devNo'] not in devDict:
  1456. logger.warning('dev<IMEI={}> not belong to dealer<id={}>'.format(dev['devNo'], ownerId))
  1457. continue
  1458. devDetail = devDict[dev['devNo']]
  1459. groupDetail = groupDict[devDetail['groupId']]
  1460. dataList.append({
  1461. 'value': devDetail['logicalCode'],
  1462. 'coins_count': dev['coins_count'],
  1463. "online": devDetail["online"],
  1464. "remark": devDetail["remarks"],
  1465. "type": devDetail['devType']['name'],
  1466. "groupNumber": devDetail["groupNumber"],
  1467. "groupName": groupDetail['groupName'],
  1468. "status": devDetail['status'],
  1469. "statusInfo": devDetail['statusInfo']
  1470. })
  1471. return JsonResponse({"result": 1, "description": None, 'payload': {"total": total, "dataList": dataList}})
  1472. ########################
  1473. #### 经销商收益消费数据中心
  1474. ########################
  1475. @require_GET
  1476. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益统计失败'))
  1477. @permission_required(ROLE.dealer, ROLE.subaccount)
  1478. def getIncomeStatistics(request):
  1479. # type: (WSGIRequest)->JsonResponse
  1480. """
  1481. 经销商经营统计 首页获取入口
  1482. :param request:
  1483. :return:
  1484. """
  1485. currentDealer = request.user # type: cast(Dealer)
  1486. groupIds = Group.get_group_ids_of_dealer_and_partner(str(currentDealer.bossId))
  1487. stats = [
  1488. {
  1489. "name": u"完成订单",
  1490. "value": GroupDailyStat.get_today_recharge_count(groupIds=groupIds),
  1491. "effect": "good",
  1492. "unit": "",
  1493. "necessary": True
  1494. }
  1495. ]
  1496. agent = Agent.objects(id=currentDealer.agentId).get() # type: Agent
  1497. start, end = today_datetime_range()
  1498. if not agent.supports('hide_dealer_newly_user_added_count'):
  1499. stats.append({
  1500. "name": u"新增用户",
  1501. "value": MyUser.get_new_user_count(groupIds=groupIds, start=start, end=end),
  1502. "effect": "good",
  1503. "unit": "",
  1504. "necessary": True
  1505. })
  1506. dailyStat = DealerDailyStat.get_today(currentDealer.bossId)
  1507. consumption = dailyStat.get("consumption", dict())
  1508. for kind in agent.hide_consume_kinds_dealer:
  1509. consumption.pop(kind, None)
  1510. for kind, value in consumption.iteritems():
  1511. stats.append(
  1512. {
  1513. "source": kind,
  1514. "name": DEALER_CONSUMPTION_AGG_KIND_TRANSLATION.get(kind, ''),
  1515. "value": to_quantity(kind, value),
  1516. "effect": "good",
  1517. "unit": DEALER_CONSUMPTION_AGG_KIND_UNIT.get(kind, ''),
  1518. "necessary": False
  1519. }
  1520. )
  1521. # 将非必须的并且值为 0的过滤掉
  1522. todayStatList = filter(lambda _: float(str((_.get("value", 0)))) > 0 or _.get("necessary"), stats)
  1523. now = datetime.datetime.now()
  1524. monthStr = MONTH_DATE_KEY.format(year=now.year, month=now.month)
  1525. return JsonOkResponse(
  1526. payload={
  1527. "monthIncome": DealerDailyStatsModelProxy.get_one_month_income(
  1528. dealerId = currentDealer.bossId, monthStr = monthStr),
  1529. "todayIncome": DealerDailyStat.get_today_income(dealerId = currentDealer.bossId),
  1530. 'todayRefundCash': abs(DealerDailyStat.get_today_refund_cash(dealerId = currentDealer.bossId)),
  1531. "todayStatList": todayStatList
  1532. }
  1533. )
  1534. @require_GET
  1535. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益消费来源失败'))
  1536. @permission_required(ROLE.dealer, ROLE.subaccount)
  1537. def getIncomeConsumptionCategories(request):
  1538. # type: (WSGIRequest)->JsonResponse
  1539. """
  1540. :param request:
  1541. :return:
  1542. """
  1543. currentDealer = request.user # type: cast(Dealer)
  1544. expand = lambda _: [{'text': v, 'value': k} for k, v in _.items()]
  1545. return JsonResponse(
  1546. {
  1547. 'result': 1,
  1548. 'description': '',
  1549. 'payload': {
  1550. 'income': expand(currentDealer.income_aggregate_source),
  1551. 'consumption': expand(currentDealer.consumption_aggregate_source)
  1552. }
  1553. })
  1554. @require_GET
  1555. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益列表失败'))
  1556. @permission_required(ROLE.dealer, ROLE.subaccount)
  1557. def getIncomeList(request):
  1558. # type: (WSGIRequest)->JsonResponse
  1559. """
  1560. 经销商经营统计的列表 从incomeProxy维度读取
  1561. :param request:
  1562. :return:
  1563. """
  1564. current_dealer = request.user # type: Union[Dealer, SubAccount]
  1565. current_dealer_id = str(current_dealer.bossId)
  1566. pageIndex = int(request.GET.get('pageIndex', 1))
  1567. pageSize = int(request.GET.get('pageSize', 10))
  1568. startTime = request.GET.get("startTime")
  1569. endTime = request.GET.get("endTime")
  1570. logicalCode = request.GET.get("logicalCode")
  1571. source = request.GET.get("secondary")
  1572. groupId = request.GET.get('groupId')
  1573. if groupId and groupId == 'undefined':
  1574. return JsonErrorResponse(description=u'地址过滤参数错误,请刷新后重试')
  1575. if not groupId:
  1576. groupIds = [ObjectId(groupId) for groupId in Group.get_group_ids_of_dealer_and_partner(current_dealer_id)]
  1577. else:
  1578. groupIds = [ObjectId(groupId)]
  1579. searchKey = request.GET.get("searchKey")
  1580. filters = {
  1581. "groupId__in": groupIds,
  1582. }
  1583. if logicalCode:
  1584. filters.update({"logicalCode": logicalCode})
  1585. # 将source为 保险的排除 经销商的主营收益仅仅为以下几种
  1586. if source:
  1587. sources = [source]
  1588. else:
  1589. sources = [
  1590. DEALER_INCOME_SOURCE.REFUND_CASH,
  1591. DEALER_INCOME_SOURCE.RECHARGE,
  1592. DEALER_INCOME_SOURCE.REDPACK,
  1593. DEALER_INCOME_SOURCE.OFFLINE_COIN,
  1594. DEALER_INCOME_SOURCE.LEDGER_CONSUME,
  1595. ]
  1596. filters.update({"source__in": sources})
  1597. if searchKey:
  1598. filters.update({"searchKey": searchKey})
  1599. startTime, endTime = current_dealer.limit_filter_date(startTime, endTime)
  1600. if startTime > endTime:
  1601. return JsonResponse({
  1602. 'result': 1,
  1603. 'description': None,
  1604. 'payload': {
  1605. 'total': 0,
  1606. 'adShow': current_dealer.adShow,
  1607. 'totalAmount': RMB(0),
  1608. 'dataList': [],
  1609. }
  1610. })
  1611. # 获取收益集合
  1612. st = datetime.datetime.strptime(startTime, "%Y-%m-%d")
  1613. et = datetime.datetime.strptime(endTime, "%Y-%m-%d")
  1614. incomeQuery = DealerIncomeProxy.objects.filter(dateTimeAdded__gte=st, dateTimeAdded__lt=et+datetime.timedelta(days=1), **filters) # type: CustomQuerySet
  1615. total, totalAmount = incomeQuery.sum_and_count("actualAmountMap.{}".format(current_dealer_id))
  1616. # 第一次循环提取出收益模型以及其对应的充值单号
  1617. incomes = list()
  1618. ref_ids = list()
  1619. for _income in incomeQuery.paginate(pageIndex, pageSize): # type: DealerIncomeProxy
  1620. incomes.append(_income)
  1621. ref_ids.append(_income.ref_id)
  1622. # 最后看是否需要执行内存合单
  1623. dataList = list()
  1624. for _record in incomes:
  1625. _data = _record.to_dict(dealerId=current_dealer_id)
  1626. dataList.append(_data)
  1627. return JsonResponse(
  1628. {
  1629. 'result': 1,
  1630. 'description': "",
  1631. 'payload': {
  1632. 'total': total,
  1633. 'adShow': current_dealer.adShow,
  1634. 'totalAmount': RMB(totalAmount),
  1635. 'dataList': dataList,
  1636. }
  1637. }
  1638. )
  1639. @require_GET
  1640. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取收益详情失败'))
  1641. @permission_required(ROLE.dealer, ROLE.subaccount)
  1642. def getIncomeDetail(request):
  1643. # type: (WSGIRequest)->JsonResponse
  1644. """
  1645. 根据 存在收入代理里的`ref_id`来获取真实的收入对应的对象,以拼装出真实的详情
  1646. :param request:
  1647. :return:
  1648. """
  1649. currentDealerId = str(request.user.bossId)
  1650. _id = request.GET.get("id")
  1651. _ref_id = request.GET.get("ref_id")
  1652. if not any([_id, _ref_id]) or 'groupId' not in request.GET:
  1653. return JsonErrorResponse(description=u'参数错误,请刷新后再试')
  1654. filters = {"id": _id} if _id else {"ref_id": ObjectId(_ref_id)}
  1655. filters.update({'shard_filter': {'groupId': request.GET.get('groupId')}})
  1656. record = ClientDealerIncomeModelProxy.get_one(**filters) # type: DealerIncomeProxy
  1657. if not record:
  1658. return JsonErrorResponse(description=u"未查询到该笔订单")
  1659. data = record.ref_detail(currentDealerId)
  1660. startKey = data.get("startKey", None)
  1661. if startKey:
  1662. consumeRecord = ConsumeRecord.objects(startKey=data.get('startKey', '')).first()
  1663. if consumeRecord is not None:
  1664. data.update({'orderNo': consumeRecord.orderNo})
  1665. data.update({'consumeId': str(consumeRecord.id)})
  1666. rechargeRecord = RechargeRecord.objects.filter(id=record.ref_id).first()
  1667. if rechargeRecord is not None and rechargeRecord.via == 'redpack':
  1668. data.update({'gateway': 'redpack'})
  1669. # 新加入一个判断,如果是group owner则显示全部正常信息,如果不是只显示全部金额和自己分到的金额信息
  1670. # 判断是否是group owner,如果是group显示全部完整信息
  1671. for partnerInfo in data['incomePartitionList']:
  1672. if partnerInfo['owner']:
  1673. if partnerInfo['role'] == 'me':
  1674. return JsonResponse({'result': 1, 'description': '', 'payload': data})
  1675. # 判断是role是否是me,如果不是本人信息则不显示
  1676. for i in range(len(data['incomePartitionList']) - 1, -1, -1):
  1677. if data['incomePartitionList'][i]['role'] != 'me':
  1678. del data['incomePartitionList'][i]
  1679. return JsonResponse({'result': 1, 'description': '', 'payload': data})
  1680. @require_GET
  1681. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取消费列表失败'))
  1682. @permission_required(ROLE.dealer, ROLE.subaccount)
  1683. def getConsumptionList(request):
  1684. # type: (WSGIRequest)->JsonResponse
  1685. """
  1686. :param request:
  1687. :return:
  1688. """
  1689. def coin_quantity(amount):
  1690. # type:(float)->Quantity
  1691. return Quantity(amount, places=consumption_unit_precision(DEALER_CONSUMPTION_AGG_KIND.COIN))
  1692. current_dealer = request.user # type: cast(Dealer)
  1693. current_dealer_id = str(current_dealer.bossId)
  1694. pageIndex = int(request.GET.get('pageIndex', 1))
  1695. pageSize = int(request.GET.get('pageSize', 10))
  1696. startTime = request.GET.get('startTime')
  1697. endTime = request.GET.get('endTime')
  1698. startTime, endTime = current_dealer.limit_filter_date(startTime, endTime)
  1699. if endTime < startTime:
  1700. return JsonResponse({
  1701. 'result': 1,
  1702. 'description': None,
  1703. 'payload': {
  1704. 'total': 0,
  1705. 'adShow': current_dealer.adShow,
  1706. 'totalAmount': RMB(0),
  1707. 'dataList': []
  1708. }
  1709. })
  1710. else:
  1711. logicalCode = request.GET.get("logicalCode")
  1712. source = request.GET.get("secondary")
  1713. groupId = request.GET.get('groupId')
  1714. filters = {
  1715. "status__in": [
  1716. ConsumeRecord.Status.FINISHED,
  1717. ConsumeRecord.Status.END,
  1718. ConsumeRecord.Status.TIMEOUT,
  1719. ConsumeRecord.Status.WAIT_PAY,
  1720. ConsumeRecord.Status.CREATED,
  1721. ]
  1722. }
  1723. if not groupId:
  1724. filters.update({
  1725. 'ownerId__in': Dealer.get_cooperative_dealer_ids(current_dealer_id),
  1726. 'groupId__in': Dealer.get_cooperative_group_ids(current_dealer_id)
  1727. })
  1728. else:
  1729. group = Group.get_group(groupId) # type: GroupDict
  1730. filters.update({
  1731. 'shard_filter': {'ownerId': group.ownerId},
  1732. 'groupId': groupId
  1733. })
  1734. searchKey = request.GET.get("searchKey")
  1735. if logicalCode:
  1736. filters.update({
  1737. "logicalCode": logicalCode
  1738. })
  1739. if source:
  1740. filters.update({"aggInfo__{}__exists".format(source): True})
  1741. if searchKey:
  1742. filters.update({"searchKey": searchKey})
  1743. # 获取的是总的数据条目
  1744. records = ConsumeRecord.objects.filter(
  1745. dateTimeAdded__gte=to_datetime(startTime, "%Y-%m-%d"),
  1746. dateTimeAdded__lt=to_datetime(endTime, "%Y-%m-%d")+datetime.timedelta(days=1),
  1747. **filters
  1748. )
  1749. total, totalAmount = records.sum_and_count("coin")
  1750. totalAmount = coin_quantity(totalAmount)
  1751. return JsonResponse(
  1752. {
  1753. 'result': 1,
  1754. 'description': None,
  1755. 'payload':
  1756. {
  1757. 'total': total,
  1758. 'adShow': current_dealer.adShow,
  1759. 'totalAmount': totalAmount,
  1760. 'dataList': [
  1761. _record.to_dealer_list() for _record in
  1762. records.paginate(pageIndex, pageSize)
  1763. ],
  1764. }
  1765. })
  1766. @require_GET
  1767. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取消费详情失败'))
  1768. @permission_required(ROLE.dealer, ROLE.subaccount)
  1769. def getConsumptionDetail(request):
  1770. # type: (WSGIRequest)->JsonResponse
  1771. """
  1772. 消费详情应该附上成本信息(如果有)
  1773. 通过RECHARGE查询CONSUME有两种情况. 一个是CONSUME一定在RECHARGE之后; 还有一个是
  1774. 后支付, RECHARGE后建立起来. 这种情况下会在RECHARGE保存consumeid
  1775. :param request:
  1776. :return:
  1777. """
  1778. id_ = request.GET.get('id')
  1779. start_key = request.GET.get('startKey')
  1780. filters = {'shard_filter': {"ownerId": request.GET.get('ownerId')}}
  1781. if id_:
  1782. filters.update({"id": str(id_)})
  1783. record = ClientConsumeModelProxy.get_one(**filters) # type: ConsumeRecord
  1784. elif start_key:
  1785. filters.update({"startKey": start_key, "hint": [("startKey", 1)]})
  1786. record = ClientConsumeModelProxy.get_one(foreign_id=request.GET.get('ref_id'),
  1787. **filters) # type: ConsumeRecord
  1788. else:
  1789. logger.error("[getConsumptionDetail] not id and not startKey !")
  1790. return JsonErrorResponse(description=u'参数错误,请刷新后再试')
  1791. payload = record.to_detail()
  1792. if payload.has_key('aggInfo'):
  1793. newAggInfo = [remove_some_desc_for_consume(value, u'使用时长') for value in payload['aggInfo']]
  1794. payload['aggInfo'] = newAggInfo
  1795. if record.isNormal:
  1796. device = Device.get_dev(record.devNo) # type: DeviceDict
  1797. if device:
  1798. payload.update({
  1799. 'showPG': device.support_power_graph
  1800. })
  1801. else:
  1802. payload.update({'showPG': False})
  1803. return JsonOkResponse(payload=payload)
  1804. @require_POST
  1805. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"关闭订单失败"))
  1806. @permission_required(ROLE.dealer)
  1807. def closeOrder(request):
  1808. payload = json.loads(request.body)
  1809. orderId = payload.get("orderId", "")
  1810. order = ClientConsumeModelProxy.get_one(id=orderId)
  1811. order.status = "finished"
  1812. order.save()
  1813. return JsonOkResponse()
  1814. @permission_required(ROLE.dealer, ROLE.subaccount)
  1815. def groupConsumptionData(request):
  1816. # type: (WSGIRequest)->JsonResponse
  1817. """
  1818. 经销商旗下所有组的消费数据
  1819. :param request:
  1820. :return:
  1821. """
  1822. def get_group_info(g, _id):
  1823. isM = _id == g.get("ownerId")
  1824. if not isM:
  1825. p = round_2_digits(float(g.get("partnerDict", dict()).get(_id, dict()).get("percent", 0)))
  1826. else:
  1827. fullPercent = 100
  1828. for _partner in g.get("partnerDict", dict()).values():
  1829. fullPercent -= float(_partner.get("percent", 0))
  1830. p = round_2_digits(float(fullPercent))
  1831. return isM, p
  1832. current_user = request.user # type: Dealer
  1833. dealerId = str(current_user.bossId)
  1834. dealer = Dealer.objects.get(id=dealerId)
  1835. pageIndex = int(request.GET.get("pageIndex", 1))
  1836. pageSize = int(request.GET.get("pageSize", 10))
  1837. startDate = request.GET.get("startTime")
  1838. endDate = request.GET.get("endTime")
  1839. startDate, endDate = current_user.limit_filter_date(startDate, endDate)
  1840. if endDate < startDate:
  1841. return JsonResponse({
  1842. 'result': 1,
  1843. 'description': '',
  1844. 'payload': {
  1845. 'dataList': [],
  1846. 'total': 0,
  1847. 'adShow': current_user.adShow
  1848. }
  1849. })
  1850. else:
  1851. searchKey = request.GET.get("searchKey", None)
  1852. # 通过searchKey 获取组地址 作为查询的筛选条件
  1853. groupIds = Group.search_group_ids_of_dealer(dealerId, searchKey) + \
  1854. Group.search_group_ids_of_partner(dealerId, searchKey)
  1855. # 每个地址组一个单位 ,根据地址组ID来完成对数据分页
  1856. groupIdSlice = groupIds[(pageIndex - 1) * pageSize: pageSize * pageIndex]
  1857. groupStatisticMap = GroupDailyStatsModelProxy.get_groups_consumption_statistic(groupIds=groupIdSlice,
  1858. startDate=startDate,
  1859. endDate=endDate)
  1860. groupDevCountMap = Device.get_device_count_by_group(groupIdSlice)
  1861. agent = Agent.objects.get(id=current_user.agentId)
  1862. isHiddenUsedTime = True if 'hiddenUsedTime' in agent.features else False
  1863. dataList = list()
  1864. for _groupId in groupIdSlice:
  1865. groupStatistic = groupStatisticMap.get(_groupId, dict())
  1866. consumptionList = translate_consumption(groupStatistic, hides=agent.hide_consume_kinds_dealer)
  1867. # 志高电子隐藏经销商后台消耗电量和电费成本统计
  1868. if "not_show_about_elec" in dealer.features:
  1869. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"消耗电量"]
  1870. [consumptionList.pop(consumptionList.index(_c)) for _c in consumptionList if _c.get("name") == u"电费成本"]
  1871. if isHiddenUsedTime:
  1872. consumptionList = [_c for _c in consumptionList if _c.get("name") != u"使用时长"]
  1873. group = Group.get_group(_groupId)
  1874. isManager, percent = get_group_info(group, dealerId)
  1875. dataList.append({
  1876. 'groupName': group['groupName'],
  1877. 'groupId': group['groupId'],
  1878. 'address': group['address'],
  1879. 'equipmentCount': groupDevCountMap.get(_groupId, 0),
  1880. 'agentProfitShare': request.user.agentProfitShare,
  1881. 'isManager': group.get("ownerId") == dealerId,
  1882. 'consumptionList': consumptionList
  1883. })
  1884. dataList = sorted(dataList, key=lambda x: float(x['equipmentCount']), reverse=True)
  1885. total = len(groupIds)
  1886. return JsonResponse({
  1887. 'result': 1,
  1888. 'description': '',
  1889. 'payload': {
  1890. 'dataList': dataList,
  1891. 'total': total,
  1892. 'adShow': request.user.adShow
  1893. }
  1894. })
  1895. ##################################################################################
  1896. #### `经销商信息设置` ###############################################################
  1897. ##################################################################################
  1898. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新失败'))
  1899. @permission_required(ROLE.dealer, ROLE.subaccount)
  1900. def resetPassword(request):
  1901. # type: (WSGIRequest)->JsonResponse
  1902. dealer = request.user
  1903. oldPassword = request.POST.get('oldPassword', "")
  1904. if not oldPassword:
  1905. return JsonErrorResponse(description=u"请输入旧密码")
  1906. limitManager = LimitAttemptsManager('resetPassword', oldPassword)
  1907. if limitManager.is_exceeded_limit():
  1908. return JsonErrorResponse(description=u'超出输入错误次数限制,请明日再试')
  1909. if dealer.check_password(oldPassword):
  1910. password = request.POST.get('password', "")
  1911. if password == "":
  1912. return JsonErrorResponse(description=u"请输入密码")
  1913. else:
  1914. dealer.set_password(password)
  1915. request.session['password'] = password
  1916. limitManager.clear()
  1917. return JsonOkResponse()
  1918. else:
  1919. limitManager.incr()
  1920. return JsonErrorResponse(description=u'旧密码输入错误,您还可输入%s次' % limitManager.times_left())
  1921. # : 开关
  1922. # : 可考虑以后整合成一个接口
  1923. # : @url('service/toggleSwitches')
  1924. # : def f(request):
  1925. # : dealer.update(**json.loads(request.body))
  1926. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  1927. @permission_required(ROLE.dealer, ROLE.subaccount)
  1928. def setWithdrawMsgSwitch(request):
  1929. # type: (WSGIRequest)->JsonResponse
  1930. ownerId = str(request.user.bossId)
  1931. payload = json.loads(request.body) if request.body else {}
  1932. if not payload:
  1933. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  1934. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  1935. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  1936. updated = Dealer.objects(id=ownerId).update(withdrawlNotify=payload.get('on', False))
  1937. if updated:
  1938. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  1939. else:
  1940. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  1941. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  1942. @permission_required(ROLE.dealer, ROLE.subaccount)
  1943. def setOfflineNotifySwitch(request):
  1944. # type: (WSGIRequest)->JsonResponse
  1945. """
  1946. :param request:
  1947. :return:
  1948. """
  1949. ownerId = str(request.user.bossId)
  1950. payload = json.loads(request.body) if request.body else {}
  1951. if not payload:
  1952. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  1953. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  1954. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  1955. updated = Dealer.objects(id=ownerId).update(offlineNotifySwitch=payload.get('on', False))
  1956. if updated:
  1957. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  1958. else:
  1959. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  1960. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  1961. @permission_required(ROLE.dealer, ROLE.subaccount)
  1962. def saveOfflineNotifyTime(request):
  1963. # type: (WSGIRequest)->JsonResponse
  1964. """
  1965. :param request:
  1966. :return:
  1967. """
  1968. ownerId = str(request.user.bossId)
  1969. payload = json.loads(request.body) if request.body else {}
  1970. if not payload:
  1971. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  1972. if payload['offlineNotifyTime'] and (not request.user.isManagerialOpenIdBound):
  1973. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  1974. updated = Dealer.objects(id=ownerId).update(offlineNotifyTime=str(payload.get('offlineNotifyTime', '')))
  1975. if updated:
  1976. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  1977. else:
  1978. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  1979. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  1980. @permission_required(ROLE.dealer, ROLE.subaccount)
  1981. def toggleNewUserPaymentOrderPushSwitch(request):
  1982. # type: (WSGIRequest)->JsonResponse
  1983. """
  1984. 用户支付订单后,即时推送给经销商
  1985. :param request:
  1986. :return:
  1987. """
  1988. ownerId = str(request.user.bossId)
  1989. payload = json.loads(request.body) if request.body else {}
  1990. if not payload:
  1991. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  1992. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  1993. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  1994. updated = Dealer.objects(id=ownerId).update(newUserPaymentOrderPushSwitch=payload.get('on', False))
  1995. if updated:
  1996. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  1997. else:
  1998. return JsonResponse({"result": 0, "description": u'更新写入失败', 'payload': {}})
  1999. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  2000. @permission_required(ROLE.dealer, ROLE.subaccount)
  2001. def toggleDailyIncomeReportPushSwitch(request):
  2002. # type: (WSGIRequest)->JsonResponse
  2003. """
  2004. 每日9点推送昨日报表
  2005. :param request:
  2006. :return:
  2007. """
  2008. ownerId = str(request.user.bossId)
  2009. payload = json.loads(request.body) if request.body else {}
  2010. if not payload:
  2011. return JsonResponse({"result": 0, "description": u'数据不完整, 更新失败', 'payload': {}})
  2012. if payload['on'] and (not request.user.isManagerialOpenIdBound):
  2013. return JsonResponse({"result":-1, "description": u"请先绑定微信号接收消息"})
  2014. updated = Dealer.objects(id=ownerId).update(dailyIncomeReportPushSwitch=payload.get('on', False))
  2015. if updated:
  2016. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2017. else:
  2018. return JsonResponse({"result": 0, "description": u'更新失败', 'payload': {}})
  2019. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'查询错误'))
  2020. @permission_required(ROLE.dealer, ROLE.subaccount)
  2021. def paymentOrderRecords(request):
  2022. # type: (WSGIRequest)->JsonResponse
  2023. """
  2024. 经销商后台查询充值订单(仅仅查询充值订单的 退币一些列的不要展示了)
  2025. :param request:
  2026. :return:
  2027. """
  2028. ownerId = str(request.user.bossId)
  2029. payload = json.loads(request.body)
  2030. pageIndex = payload.get("pageIndex")
  2031. pageSize = payload.get("pageSize")
  2032. startTime = payload.get("startTime")
  2033. endTime = payload.get("endTime")
  2034. if not endTime:
  2035. endTime = datetime.datetime.now()
  2036. else:
  2037. endTime = get_tomorrow_zero_time(datetime.datetime.strptime(endTime, "%Y-%m-%d"))
  2038. if not startTime:
  2039. startTime = get_zero_time(endTime)
  2040. else:
  2041. startTime = get_zero_time(datetime.datetime.strptime(startTime, "%Y-%m-%d"))
  2042. if startTime > endTime:
  2043. startTime = endTime
  2044. orderStatus = payload.get("orderStatus")
  2045. groupInfo = payload.get("group", dict())
  2046. deviceInfo = payload.get("device", dict())
  2047. queryFilters = {
  2048. 'dateTimeAdded': {
  2049. '$gte': startTime,
  2050. '$lt': endTime
  2051. },
  2052. "via": {
  2053. "$in": map(format, [
  2054. USER_RECHARGE_TYPE.RECHARGE_MIX,
  2055. USER_RECHARGE_TYPE.RECHARGE,
  2056. USER_RECHARGE_TYPE.RECHARGE_CARD,
  2057. USER_RECHARGE_TYPE.RECHARGE_VIRTUAL_CARD,
  2058. USER_RECHARGE_TYPE.RECHARGE_CASH,
  2059. USER_RECHARGE_TYPE.RECHARGE_MONTHLY_PACKAGE,
  2060. USER_RECHARGE_TYPE.RECHARGE_REDPACK,
  2061. USER_RECHARGE_TYPE.RECHARGE_INSURANCE
  2062. ])
  2063. }
  2064. }
  2065. search_key = payload.get('searchKey', None)
  2066. if search_key:
  2067. if len(search_key) < 15:
  2068. dev = Device.get_dev_by_logicalCode(search_key)
  2069. if dev:
  2070. queryFilters.update({'devNo': dev.devNo})
  2071. if 'devNo' not in queryFilters:
  2072. queryFilters.update({
  2073. '$or': [
  2074. {'orderNo': search_key},
  2075. {'wxOrderNo': search_key},
  2076. {'transactionId': search_key}
  2077. ]
  2078. })
  2079. else:
  2080. # 订单的状态
  2081. if orderStatus:
  2082. queryFilters.update({"result": orderStatus})
  2083. # 查找的逻辑 自下从上查找 依次是 设备 --> 组 --> 当前查询人 --> 空查询
  2084. # TODO 这个地方的信息安全性 完全依赖上次调度的接口, 目前没有做检查 记得加上
  2085. if deviceInfo:
  2086. queryFilters.update({"devNo": deviceInfo.get("devNo"), "ownerId": deviceInfo.get("ownerId")})
  2087. elif groupInfo:
  2088. queryFilters.update({"groupId": groupInfo.get("groupId"), "ownerId": groupInfo.get("ownerId")})
  2089. else:
  2090. # TODO 这个地方有个BUG 经销商的ID 防止部分新加入的组合伙人 能看到之前组的经营统计信息
  2091. groupIds = list(set(Group.get_group_ids_of_dealer_and_partner(ownerId)))
  2092. groups = Group.get_groups_by_group_ids(groupIds)
  2093. dealer_id_list = list(set([group['ownerId'] for group in groups.values()]))
  2094. queryFilters.update({
  2095. 'ownerId': {'$in': dealer_id_list},
  2096. 'groupId': {'$in': groupIds}
  2097. })
  2098. logger.debug('query recharges between {} and {}. filters = {}'.format(startTime, endTime, queryFilters))
  2099. # 添加筛选条件 选出不是交易子单的订单
  2100. query_set = RechargeRecord.objects.filter(__raw__=queryFilters).filter(attachParas__tradeOrderId=None).order_by('-dateTimeAdded') # type: CustomQuerySet
  2101. totalSum = query_set.sum(RechargeRecord.money.name)
  2102. total_count = query_set.count()
  2103. records = query_set.paginate(pageIndex, pageSize)
  2104. dataList = list()
  2105. for _item in records: # type: RechargeRecord
  2106. # 订单的基本信息
  2107. data = {
  2108. 'id': str(_item.id),
  2109. 'ownerId': _item.ownerId,
  2110. 'gateway': _item.gateway if _item.gateway else 'wechat',
  2111. 'result': _item.result if _item.result else '',
  2112. 'totalFee': _item.money if _item.money else 0,
  2113. 'address': _item.address if _item.address else '',
  2114. 'name': _item.groupName if _item.groupName else '',
  2115. 'nickname': _item.nickname if _item.nickname else '',
  2116. 'devTypeName': _item.dev_type_name,
  2117. 'groupNumber': _item.groupNumber if _item.groupNumber else '',
  2118. 'value': Device.get_logicalCode_by_devNo(_item.devNo) if _item.devNo else '',
  2119. 'wechatTrxid': _item.wxOrderNo if _item.wxOrderNo else '',
  2120. 'outTradeNo': _item.orderNo if _item.orderNo else '',
  2121. 'createdTime': _item.to_datetime_str(_item.dateTimeAdded),
  2122. 'description': _item.my_description if _item.my_description else '',
  2123. 'userId': _item.openId if _item.openId else '',
  2124. 'groupId': _item.groupId if _item.groupId else '',
  2125. 'via': _item.via if _item.via else '',
  2126. 'isQuickPay': _item.isQuickPay if _item.isQuickPay else False,
  2127. 'startKey': _item.attachParas.get('startKey', '') if _item.result == 'success' else '',
  2128. 'consumeId': _item.attachParas.get('consumeRecordId', ''),
  2129. 'isLedgered': _item.is_ledgered,
  2130. 'notLedgerDesc': _item.notLedgerDesc
  2131. }
  2132. # TODO 需要修改 加上子订单的信息
  2133. tradeOrders = RechargeRecord.objects.filter(
  2134. openId=_item.openId,
  2135. attachParas__tradeOrderId=str(_item.id)
  2136. )
  2137. _subs = list()
  2138. for _trade in tradeOrders: # type: RechargeRecord
  2139. _subData = {
  2140. 'id': str(_trade.id),
  2141. 'ownerId': _trade.ownerId,
  2142. 'gateway': _trade.gateway if _trade.gateway else 'wechat',
  2143. 'result': _trade.result if _trade.result else '',
  2144. 'totalFee': _trade.money if _trade.money else 0,
  2145. 'address': _trade.address if _trade.address else '',
  2146. 'name': _trade.groupName if _trade.groupName else '',
  2147. 'nickname': _trade.nickname if _trade.nickname else '',
  2148. 'devTypeName': _trade.dev_type_name,
  2149. 'groupNumber': _trade.groupNumber if _trade.groupNumber else '',
  2150. 'value': Device.get_logicalCode_by_devNo(_trade.devNo) if _trade.devNo else '',
  2151. 'wechatTrxid': _trade.wxOrderNo if _trade.wxOrderNo else '',
  2152. 'outTradeNo': _trade.orderNo if _trade.orderNo else '',
  2153. 'createdTime': _trade.to_datetime_str(_trade.dateTimeAdded),
  2154. 'description': _trade.my_description if _trade.my_description else '',
  2155. 'userId': _trade.openId if _trade.openId else '',
  2156. 'groupId': _trade.groupId if _trade.groupId else '',
  2157. 'via': _trade.via if _trade.via else '',
  2158. 'isQuickPay': _trade.isQuickPay if _trade.isQuickPay else False,
  2159. 'startKey': _trade.attachParas.get('startKey', '') if _trade.result == 'success' else '',
  2160. 'consumeId': _trade.attachParas.get('consumeRecordId', ''),
  2161. 'isLedgered': _trade.is_ledgered,
  2162. 'notLedgerDesc': _trade.notLedgerDesc
  2163. }
  2164. _subs.append(_subData)
  2165. data["subs"] = _subs
  2166. dataList.append(data)
  2167. return JsonResponse({
  2168. "result": 1,
  2169. "description": "",
  2170. 'payload': {
  2171. "page": pageIndex,
  2172. "pageSize": pageSize,
  2173. "total": total_count,
  2174. "totalSum":totalSum,
  2175. "items": dataList
  2176. }
  2177. })
  2178. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'查询错误'))
  2179. @permission_required(ROLE.dealer, ROLE.subaccount)
  2180. def consumeOrderRecords(request):
  2181. # type: (WSGIRequest)->JsonResponse
  2182. """
  2183. 经销商后台查询消费订单
  2184. :param request:
  2185. :return:
  2186. """
  2187. ownerId = str(request.user.bossId)
  2188. payload = json.loads(request.body)
  2189. pageIndex = payload.get("pageIndex")
  2190. pageSize = payload.get("pageSize")
  2191. startTime = payload.get("startTime")
  2192. endTime = payload.get("endTime")
  2193. if not endTime:
  2194. endTime = datetime.datetime.now()
  2195. else:
  2196. endTime = get_tomorrow_zero_time(datetime.datetime.strptime(endTime, "%Y-%m-%d"))
  2197. if not startTime:
  2198. startTime = get_zero_time(endTime)
  2199. else:
  2200. startTime = get_zero_time(datetime.datetime.strptime(startTime, "%Y-%m-%d"))
  2201. if startTime > endTime:
  2202. startTime = endTime
  2203. groupInfo = payload.get("group", dict())
  2204. deviceInfo = payload.get("device", dict())
  2205. filters = {
  2206. 'dateTimeAdded': {
  2207. '$gte': startTime,
  2208. '$lt': endTime
  2209. }
  2210. }
  2211. search_key = payload.get('searchKey', None)
  2212. if search_key:
  2213. if len(search_key) < 15:
  2214. dev = Device.get_dev_by_logicalCode(search_key)
  2215. if dev:
  2216. filters.update({'devNo': dev.devNo})
  2217. if 'devNo' not in filters:
  2218. filters.update({
  2219. 'orderNo': search_key
  2220. })
  2221. else:
  2222. # 查找的逻辑 自下从上查找 依次是 设备 --> 组 --> 当前查询人 --> 空查询
  2223. # TODO 这个地方的信息安全性 完全依赖上次调度的接口, 目前没有做检查 记得加上
  2224. if deviceInfo:
  2225. filters.update({"devNo": deviceInfo.get("devNo"), "ownerId": deviceInfo.get("ownerId")})
  2226. elif groupInfo:
  2227. filters.update({"groupId": groupInfo.get("groupId"), "ownerId": groupInfo.get("ownerId")})
  2228. else:
  2229. # TODO 这个地方有个BUG 经销商的ID 防止部分新加入的组合伙人 能看到之前组的经营统计信息
  2230. groupIds = list(set(Group.get_group_ids_of_dealer_and_partner(ownerId)))
  2231. groups = Group.get_groups_by_group_ids(groupIds)
  2232. dealer_id_list = list(set([group['ownerId'] for group in groups.values()]))
  2233. filters.update({
  2234. 'ownerId': {'$in': dealer_id_list},
  2235. 'groupId': {'$in': groupIds}
  2236. })
  2237. logger.debug('query consumes between {} and {}. filters = {}'.format(startTime, endTime, filters))
  2238. records = ConsumeRecord.objects.filter(__raw__=filters).order_by("-dateTimeAdded") # type: CustomQuerySet
  2239. count = records.count()
  2240. dataList = []
  2241. for rcd in records.paginate(pageIndex, pageSize):
  2242. try:
  2243. dataList.append(rcd.to_detail())
  2244. except Exception as e:
  2245. logger.exception(e)
  2246. continue
  2247. return JsonOkResponse(payload={"dataList": dataList, "total": count})
  2248. @permission_required(ROLE.dealer, ROLE.subaccount)
  2249. def discountRuleData(request):
  2250. # type: (WSGIRequest)->JsonResponse
  2251. groupId = request.GET.get('groupId', None)
  2252. ownerId = str(request.user.bossId)
  2253. if groupId is None:
  2254. ruleList = []
  2255. for k, v in request.user.format_default_discount.items():
  2256. ruleList.append({'ruleId': k, 'payAmount': k, 'coins': v})
  2257. return JsonResponse({"result": 1,
  2258. "description": None,
  2259. 'payload': {"ruleList": ruleList, "groupData": {}}})
  2260. else:
  2261. group = Group.get_group(groupId)
  2262. if group is None:
  2263. return JsonResponse({"result": 0, "description": u"找不到组", 'payload': {}})
  2264. devNos = Device.get_devNos_by_group([groupId])
  2265. group['equipmentCount'] = len(devNos)
  2266. if ownerId == group['ownerId']:
  2267. group['isManager'] = True
  2268. else:
  2269. group['isManager'] = False
  2270. ruleList = []
  2271. for k, v in group['ruleDict'].items():
  2272. ruleList.append({'ruleId': k, 'payAmount': k, 'coins': v})
  2273. return JsonResponse({"result": 1,
  2274. "description": None,
  2275. 'payload': {"ruleList": ruleList, "groupData": group}})
  2276. @permission_required(ROLE.dealer, ROLE.subaccount)
  2277. def discountCardRuleData(request):
  2278. """
  2279. 经销商端的卡优惠获取显示
  2280. # 新的规则修改为
  2281. 如果经销商设置有卡优惠规则 返还卡优惠规则
  2282. 如果经销商没有设置卡优惠规则 但是设置有金币优惠规则 返还金币优惠规则
  2283. 两个都没有设置 默认卡优惠规则
  2284. :param request:
  2285. :return:
  2286. """
  2287. groupId = request.GET.get("groupId", None)
  2288. # 没有组ID的情况获取的是经销商的默认 优惠套餐
  2289. ruleList = list()
  2290. if not groupId:
  2291. for k, v in request.user.format_card_discount.items():
  2292. ruleList.append({"ruleId": k, "payAmount": k, "coins": v})
  2293. return JsonOkResponse(payload={"ruleList": ruleList, "groupData": {}})
  2294. group = Group.get_group(groupId)
  2295. if not group:
  2296. return JsonErrorResponse(description=u"错误的地址信息")
  2297. # 经销商没有设置过卡的优惠规则
  2298. if not group.get("cardRuleDict"):
  2299. cardRuleDict = request.user.defaultCardDiscountConfig
  2300. Group.objects.filter(id=groupId).update(cardRuleDic=cardRuleDict)
  2301. Group.CacheMgr.invalid_group_cache([groupId])
  2302. group = Group.get_group(groupId)
  2303. devNos = Device.get_devNos_by_group([groupId])
  2304. ownerId = str(request.user.bossId)
  2305. group['equipmentCount'] = len(devNos)
  2306. if ownerId == group['ownerId']:
  2307. group['isManager'] = True
  2308. else:
  2309. group['isManager'] = False
  2310. ruleList = []
  2311. for k, v in group['cardRuleDict'].items():
  2312. ruleList.append({'ruleId': k, 'payAmount': k, 'coins': v})
  2313. return JsonResponse({"result": 1,
  2314. "description": None,
  2315. 'payload': {"ruleList": ruleList, "groupData": group}})
  2316. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新错误'))
  2317. @permission_required(ROLE.dealer, ROLE.subaccount)
  2318. def saveDiscountRule(request):
  2319. # type: (WSGIRequest)->JsonResponse
  2320. """
  2321. TODO TO REFACTOR
  2322. :param request:
  2323. :return:
  2324. """
  2325. currentDealer = request.user # type: cast(Dealer)
  2326. # 校验优惠规则
  2327. def check_rule_data(fields, rules):
  2328. for ruleDict in rules:
  2329. for field in fields:
  2330. if len(str(ruleDict[field])) > 12:
  2331. return False, u"%s数额超过限制" % ruleDict[field]
  2332. try:
  2333. float(ruleDict[field])
  2334. except ValueError:
  2335. return False, u"%s类型错误,请输入数字" % ruleDict[field]
  2336. return True, u''
  2337. def update_rule(ruleDict, rules):
  2338. isNewlyAdded = lambda d: d["payAmount"] not in ruleDict.keys()
  2339. if len(ruleDict) >= 10 and any(map(isNewlyAdded, rules)):
  2340. raise ParameterError(u'最多只能设置10条优惠充值信息')
  2341. for rule in rules:
  2342. if rule['ruleId']:
  2343. ruleDict.pop(str(rule['ruleId']), None)
  2344. if rule['ruleId'] != 0 and (float(rule['coins']) in ruleDict.values()):
  2345. raise ParameterError(u'同一套餐下,不能出现充不一样的钱,但是兑币的数目却相同')
  2346. ruleDict.update({str(rule['payAmount']): float(rule['coins'])})
  2347. return ruleDict
  2348. payload = json.loads(request.body) if request.body else {}
  2349. ruleList = payload.get('ruleData', None)
  2350. if ruleList is None:
  2351. return JsonErrorResponse(description=u'没有找到正确的规则')
  2352. status, msg = check_rule_data(["payAmount", "coins"], ruleList)
  2353. if not status:
  2354. return JsonErrorResponse(description=msg)
  2355. groupId = payload.get('groupId', None)
  2356. # groupId为空表示修改默认充值套餐
  2357. if groupId is None:
  2358. try:
  2359. newRuleDict = update_rule(currentDealer.format_default_discount, ruleList)
  2360. currentDealer.update(defaultDiscountConfig=newRuleDict)
  2361. return JsonResponse({"result": 1, "description": '', 'payload': {}})
  2362. except ParameterError as e:
  2363. return JsonErrorResponse(description=e.message)
  2364. else:
  2365. try:
  2366. group = Group.objects(id=groupId).first() # type: Group
  2367. if not group:
  2368. return JsonErrorResponse(description=u'组不存在,请刷新后再试')
  2369. isRecovery = payload.get('isRecovery', 'N')
  2370. if isRecovery == 'Y':
  2371. rule_dict = currentDealer.format_default_discount
  2372. else:
  2373. rule_dict = group.format_rule_dict
  2374. update_rule(rule_dict, ruleList)
  2375. Group.update_group(group_id=groupId, ruleDict=rule_dict)
  2376. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2377. except ParameterError as e:
  2378. return JsonErrorResponse(description=e.message)
  2379. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"更新错误"))
  2380. @permission_required(ROLE.dealer, ROLE.subaccount)
  2381. def saveDiscountCardData(request):
  2382. """
  2383. 保存卡优惠设置
  2384. :param request:
  2385. :return:
  2386. """
  2387. def _check(rules, fieldnames=None):
  2388. """
  2389. 校验 ruleList 的每一个字段和字段值
  2390. :param rules:
  2391. :param fieldnames:
  2392. :return:
  2393. """
  2394. if fieldnames is None:
  2395. fieldnames = ["payAmount", "coins"]
  2396. for ruleDict in rules:
  2397. for field in fieldnames:
  2398. if len(str(ruleDict[field])) > 12:
  2399. return False, u"%s数额超过限制" % ruleDict[field]
  2400. try:
  2401. float(ruleDict[field])
  2402. except ValueError:
  2403. return False, u"%s类型错误,请输入数字" % ruleDict[field]
  2404. return True, u""
  2405. def _update(ruleDict, rules):
  2406. """
  2407. 更新优惠套餐
  2408. :param ruleDict:
  2409. :param rules:
  2410. :return:
  2411. """
  2412. isNewlyAdded = lambda d: d["payAmount"] not in ruleDict.keys()
  2413. if len(ruleDict) >= 10 and any(map(isNewlyAdded, rules)):
  2414. raise ParameterError(u'最多只能设置10条优惠充值信息')
  2415. for rule in rules:
  2416. if rule['ruleId']:
  2417. ruleDict.pop(str(rule['ruleId']), None)
  2418. if rule['ruleId'] != 0 and (float(rule['coins']) in ruleDict.values()):
  2419. raise ParameterError(u'同一套餐下,不能出现充不一样的钱,但是兑币的数目却相同')
  2420. ruleDict.update({str(rule['payAmount']): float(rule['coins'])})
  2421. return ruleDict
  2422. payload = json.loads(request.body) if request.body else dict()
  2423. ruleList = payload.get("ruleData", None)
  2424. if ruleList is None:
  2425. return JsonErrorResponse(description=u"请设置正确的优惠规则")
  2426. status, msg = _check(ruleList)
  2427. if not status:
  2428. return JsonErrorResponse(description=msg)
  2429. groupId = payload.get("groupId", None)
  2430. if groupId is None:
  2431. try:
  2432. newDict = _update(request.user.format_card_discount, ruleList)
  2433. request.user.update(defaultCardDiscountConfig=newDict)
  2434. except ParameterError as e:
  2435. return JsonErrorResponse(description=e.message)
  2436. else:
  2437. return JsonOkResponse(payload={})
  2438. else:
  2439. try:
  2440. group = Group.objects(id=groupId).first() # type: Group
  2441. if not group:
  2442. return JsonErrorResponse(description=u'组不存在,请刷新后再试')
  2443. isRecovery = payload.get('isRecovery', 'N')
  2444. # if isRecovery == 'Y':
  2445. # rule_dict = request.user.format_card_discount
  2446. # else:
  2447. rule_dict = group.format_card_dict
  2448. newDict = _update(rule_dict, ruleList)
  2449. Group.update_group(group_id=groupId, cardRuleDict=newDict)
  2450. except ParameterError as e:
  2451. return JsonErrorResponse(description=e.message)
  2452. else:
  2453. return JsonOkResponse(payload={})
  2454. @permission_required(ROLE.dealer, ROLE.subaccount)
  2455. def delDiscountRule(request):
  2456. # type: (WSGIRequest)->JsonResponse
  2457. ruleId = request.POST.get('ruleId', None)
  2458. if not ruleId:
  2459. return JsonResponse({"result": 0, "description": u"缺少参数ruleId或为空", 'payload': {}})
  2460. groupId = request.POST.get('groupId', None)
  2461. if not groupId:
  2462. default_discount = request.user.format_default_discount
  2463. default_discount.pop(ruleId, None)
  2464. request.user.update(defaultDiscountConfig=default_discount)
  2465. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2466. else:
  2467. try:
  2468. group = Group.objects(id=str(groupId)).first()
  2469. if not group:
  2470. return JsonResponse({"result": 0, "description": u"组不存在,请刷新后再试", 'payload': {}})
  2471. rule_dict = group.format_rule_dict # type: dict
  2472. rule_dict.pop(ruleId, None)
  2473. Group.update_group(group_id=groupId, ruleDict=rule_dict)
  2474. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2475. except Exception, e:
  2476. logger.exception("update db error=%s,groupId=%s" % (e, groupId))
  2477. return JsonResponse({"result": 0, "description": u"更新异常,请重试", 'payload': {}})
  2478. @permission_required(ROLE.dealer, ROLE.subaccount)
  2479. def delDiscountCardData(request):
  2480. """
  2481. 删除卡优惠设置
  2482. :param request:
  2483. :return:
  2484. """
  2485. ruleId = request.POST.get('ruleId', None)
  2486. if not ruleId:
  2487. return JsonResponse({"result": 0, "description": u"缺少参数ruleId或为空", 'payload': {}})
  2488. groupId = request.POST.get('groupId', None)
  2489. if not groupId:
  2490. default_discount = request.user.format_card_discount
  2491. default_discount.pop(ruleId, None)
  2492. request.user.update(defaultCardDiscountConfig=default_discount)
  2493. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2494. else:
  2495. try:
  2496. group = Group.objects(id=str(groupId)).first()
  2497. if not group:
  2498. return JsonResponse({"result": 0, "description": u"组不存在,请刷新后再试", 'payload': {}})
  2499. rule_dict = group.format_card_dict # type: dict
  2500. rule_dict.pop(ruleId, None)
  2501. Group.update_group(group_id=groupId, cardRuleDict=rule_dict)
  2502. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  2503. except Exception, e:
  2504. logger.exception("update db error=%s,groupId=%s" % (e, groupId))
  2505. return JsonResponse({"result": 0, "description": u"更新异常,请重试", 'payload': {}})
  2506. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取经销商信息错误'))
  2507. @permission_required(ROLE.dealer, ROLE.subaccount)
  2508. def accountInfo(request):
  2509. # type: (WSGIRequest)->JsonResponse
  2510. if check_role(request.user, ROLE.dealer):
  2511. dealer = Dealer.objects(id=str(request.user.bossId)).get() # type: Dealer
  2512. payload = dealer.to_dict()
  2513. else:
  2514. subaccount = SubAccount.objects(id=str(request.user.id)).get() # type: subaccount
  2515. payload = subaccount.to_dict()
  2516. agent = Agent.objects(id=payload['agentId']).first() # type: Agent
  2517. payload['servicePhone'] = agent.service_phone
  2518. payload['serviceQrcodeUrl'] = agent.serviceQrcodeUrl
  2519. return JsonResponse({"result": 1, "description": None, 'payload': payload})
  2520. ####`经销商金融版块(提现,银行卡信息)` ####################################################
  2521. @permission_required(ROLE.dealer, ROLE.subaccount)
  2522. def walletData(request):
  2523. # type: (WSGIRequest)->JsonResponse
  2524. dealerId = str(request.user.bossId)
  2525. dealer = Dealer.objects(id=dealerId).first() # type: Optional[Dealer]
  2526. if not dealer:
  2527. return JsonErrorResponse(description=u"没有找到经销商")
  2528. my_source_key = dealer.current_wallet_withdraw_source_key
  2529. inhouse_source_key = Agent.get_inhouse_prime_agent().current_wallet_withdraw_source_key
  2530. device_income_list = []
  2531. for source_key, balance in dealer.deviceBalance.iteritems():
  2532. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  2533. device_income_list.append({
  2534. 'id': source_key,
  2535. 'balance': balance.balance,
  2536. 'name': current_platform(source_key, my_source_key),
  2537. 'current': source_key == my_source_key
  2538. })
  2539. ad_income_list = []
  2540. for source_key, balance in dealer.adBalance.iteritems():
  2541. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  2542. ad_income_list.append({
  2543. 'id': source_key,
  2544. 'balance': balance.balance,
  2545. 'name': current_platform(source_key, inhouse_source_key),
  2546. 'current': source_key == inhouse_source_key
  2547. })
  2548. ledger_income_list = []
  2549. for source_key, balance in dealer.ledgerBalance.iteritems():
  2550. if WithdrawGateway.is_ledger(source_key) and balance.balance != RMB(0):
  2551. ledger_income_list.append({
  2552. 'id': source_key,
  2553. 'balance': balance.balance,
  2554. 'name': current_platform(source_key, inhouse_source_key),
  2555. 'current': source_key == inhouse_source_key
  2556. })
  2557. payload = {
  2558. }
  2559. if len(device_income_list) > 0:
  2560. payload.update({
  2561. DEALER_INCOME_TYPE.DEVICE_INCOME: device_income_list
  2562. })
  2563. if len(ad_income_list) > 0:
  2564. payload.update({
  2565. DEALER_INCOME_TYPE.AD_INCOME: ad_income_list
  2566. })
  2567. if len(ledger_income_list) > 0:
  2568. payload.update({
  2569. DEALER_INCOME_TYPE.LEDGER_CONSUME: ledger_income_list
  2570. })
  2571. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  2572. # 经销商获取提现短信验证码
  2573. @error_tolerate(nil=DefaultJsonErrorResponse)
  2574. @permission_required(ROLE.dealer)
  2575. def getWithdrawCode(request):
  2576. # type: (WSGIRequest)->JsonResponse
  2577. currentDealer = request.user # type: Dealer
  2578. toNumber = request.user.username
  2579. agentId = request.user.agentId
  2580. agent = Agent.get_agent(agentId)
  2581. productName = agent['productName']
  2582. if not currentDealer.monitorPhone: # 没有监管的,直接发送验证码到本机
  2583. status, msg = dealerWithdrawSMSProvider.get(phoneNumber=toNumber,
  2584. productName=productName,
  2585. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  2586. else:
  2587. toNumber = currentDealer.monitorPhone
  2588. status, msg = dealerMonitorWithdrawSMSProvider.get(phoneNumber=toNumber,
  2589. productName=productName,
  2590. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  2591. if not status:
  2592. return JsonErrorResponse(description=msg)
  2593. else:
  2594. return JsonOkResponse()
  2595. @permission_required(ROLE.dealer)
  2596. def withdrawalsHistoryList(request):
  2597. # type: (WSGIRequest)->JsonResponse
  2598. """
  2599. 需要连同整个提现数据层整改
  2600. :param request:
  2601. :return:
  2602. """
  2603. current_user = request.user # type: Dealer
  2604. pageIndex = int(request.GET.get('pageIndex', 1))
  2605. pageSize = int(request.GET.get('pageSize', 10))
  2606. status = request.GET.get('status')
  2607. ownerId = str(request.user.bossId)
  2608. startTime = '2016-01-01'
  2609. startTime, _ = current_user.limit_filter_date(startTime, None)
  2610. startTime = datetime.datetime.strptime(startTime, "%Y-%m-%d")
  2611. if status:
  2612. records = WithdrawRecord.objects(ownerId=ownerId,
  2613. role=request.user.role,
  2614. status=status,
  2615. postTime__gte=startTime).order_by('-postTime')
  2616. else:
  2617. records = WithdrawRecord.objects(ownerId=ownerId,
  2618. role=request.user.role,
  2619. postTime__gte=startTime).order_by('-postTime')
  2620. return JsonResponse({
  2621. "result": 1,
  2622. "description": None,
  2623. 'payload': {
  2624. "total": records.count(),
  2625. "withdrawalTotal": RMB(records(status=WithdrawStatus.SUCCEEDED).sum('amount')),
  2626. "dataList": [
  2627. {
  2628. 'bankName': record.parentBankName,
  2629. 'paymentId': str(record.id),
  2630. 'withdrawalsDate': record.postTime.strftime("%Y-%m-%d %H:%M:%S"),
  2631. 'amount': record.amount,
  2632. 'statusText': translate_withdraw_state(record.status),
  2633. 'refunded': record.refunded
  2634. } for record in records.paginate(pageIndex, pageSize)
  2635. ]
  2636. }
  2637. })
  2638. @permission_required(ROLE.dealer)
  2639. def dealerWithdraw(request):
  2640. # type: (WSGIRequest)->JsonResponse
  2641. """
  2642. :param request:
  2643. :return:
  2644. """
  2645. payload = json.loads(request.body)
  2646. pay_type = payload.get('payType')
  2647. assert pay_type in (
  2648. WITHDRAW_PAY_TYPE.WECHAT, WITHDRAW_PAY_TYPE.BANK, WITHDRAW_PAY_TYPE.ALIPAY), 'not support this pay type'
  2649. if pay_type == WITHDRAW_PAY_TYPE.WECHAT:
  2650. open_id = payload.get('openId')
  2651. if not open_id:
  2652. return JsonResponse({"result": 0, "description": u'鉴权失败,请刷新后再试', 'payload': {}})
  2653. request.user.withdraw_open_id = open_id
  2654. amount = RMB(payload.get('amount', 0.0))
  2655. assert amount > RMB(0), 'amount must be bigger than zero'
  2656. status, msg = request.user.withdraw_sms_provider.verify(phoneNumber = request.user.withdraw_sms_phone_number,
  2657. smsCode = payload.get('code'))
  2658. if not status:
  2659. return JsonResponse({"result": 0, "description": msg, 'payload': {}})
  2660. withdraw_service = DealerWithdrawService(payee = request.user,
  2661. income_type = payload.get('sourceType'),
  2662. amount = amount,
  2663. pay_type = pay_type,
  2664. bank_card_no = payload.get('bankAccount', ''))
  2665. result = withdraw_service.execute(source_key = payload.get('sourceId'), recurrent = False)
  2666. logger.debug('withdraw result is: {}'.format(result))
  2667. return JsonResponse(result)
  2668. @permission_required(ROLE.dealer, ROLE.subaccount)
  2669. def paymentInfo(request):
  2670. # type: (WSGIRequest)->JsonResponse
  2671. """
  2672. 展示提现页面数据
  2673. :param request:
  2674. :return:
  2675. """
  2676. ownerId = str(request.user.bossId)
  2677. paymentId = request.GET.get('paymentId', None)
  2678. if not paymentId:
  2679. return JsonErrorResponse(description=u'没有提供提现单ID')
  2680. record = WithdrawRecord.objects(id=str(paymentId)).first() # type: Optional[WithdrawRecord]
  2681. if not record:
  2682. return JsonErrorResponse(description=u"没有找到提现记录")
  2683. return JsonOkResponse(
  2684. payload={
  2685. 'type': record.parentBankName,
  2686. 'amount': record.amount,
  2687. 'preBalance': record.balance,
  2688. 'serviceFee': record.serviceFee,
  2689. 'actualPay': record.actualPay,
  2690. 'refunded': record.refunded,
  2691. 'statusText': translate_withdraw_state(record.status),
  2692. 'description': record.description,
  2693. 'withdrawalsDate': record.postTime.strftime("%Y-%m-%d %H:%M:%S")
  2694. }
  2695. )
  2696. @permission_required(ROLE.dealer)
  2697. def getDealerAutoWithdrawCode(request):
  2698. # type: (WSGIRequest)->JsonResponse
  2699. """
  2700. 经销商确认开启自动提现
  2701. :param request:
  2702. :return:
  2703. """
  2704. try:
  2705. phoneNumber = request.GET.get('phoneNumber', None)
  2706. if not phoneNumber:
  2707. return JsonErrorResponse(description=u'手机号码为空')
  2708. agent = Agent.get_agent(request.user.agentId)
  2709. productName = agent['productName']
  2710. status, msg = dealerAutoWithdrawSMSProvider.get(phoneNumber=phoneNumber,
  2711. productName=productName,
  2712. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  2713. if not status:
  2714. return JsonErrorResponse(description=msg)
  2715. else:
  2716. return JsonOkResponse()
  2717. except Exception as e:
  2718. logger.exception(e)
  2719. return JsonErrorResponse()
  2720. #### `Utils related` ###########################################################
  2721. @permission_required(ROLE.dealer, ROLE.subaccount)
  2722. def deviceMem(request):
  2723. # type: (WSGIRequest)->JsonResponse
  2724. logicalCode = request.GET.get('logicalCode')
  2725. if not logicalCode:
  2726. return JsonErrorResponse(description=u'未提供设备逻辑编码')
  2727. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  2728. dev = Device.get_dev(devNo)
  2729. return JsonResponse(dev)
  2730. @permission_required(ROLE.dealer, ROLE.subaccount)
  2731. def deviceInfo(request):
  2732. # type: (WSGIRequest)->JsonResponse
  2733. logicalCode = request.GET.get('logicalCode', '')
  2734. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  2735. dev = Device.get_dev(devNo)
  2736. if dev is None:
  2737. return JsonErrorResponse(description=u'设备不存在')
  2738. return JsonResponse(MessageSender.send(dev, DeviceCmdCode.GET_DEVINFO, {'IMEI': devNo}))
  2739. @permission_required(ROLE.dealer, ROLE.subaccount)
  2740. def getServiceInfo(request):
  2741. # type: (WSGIRequest)->JsonResponse
  2742. currentDealer = request.user.myBoss # type: Optional[Dealer]
  2743. if not currentDealer:
  2744. return JsonResponse({"result": 0, "description": u"没有找到经销商"})
  2745. value = {
  2746. "qrcodeUrl": currentDealer.qrcodeUrl,
  2747. "serviceName": currentDealer.serviceName,
  2748. "servicePhone": currentDealer.servicePhone
  2749. }
  2750. return JsonResponse({"result": 1, "description": "", 'payload': value})
  2751. @permission_required(ROLE.dealer)
  2752. def saveServiceInfo(request):
  2753. # type: (WSGIRequest)->JsonResponse
  2754. ownerId = request.user.bossId # type: ObjectId
  2755. qrcodeUrl = request.POST.get('qrcodeUrl')
  2756. serviceName = request.POST.get('serviceName')
  2757. if serviceName:
  2758. if NAME_RE.match(serviceName) is None:
  2759. logger.error('name formatting error, name=%s' % serviceName)
  2760. return JsonResponse({"result": 0, "description": u"请输入正确格式的名称, 2-20位"})
  2761. servicePhone = request.POST.get('servicePhone')
  2762. if servicePhone:
  2763. if PHONE_NUMBER_RE.match(servicePhone) is None:
  2764. logger.error('phone number format error, phone=%s' % servicePhone)
  2765. return JsonResponse({"result": 0, "description": u"请输入正确的手机号码"})
  2766. status, desc = dealerRegisterSMSProvider.verify(servicePhone, request.POST.get('code'))
  2767. if not status:
  2768. return JsonErrorResponse(desc)
  2769. result = Dealer.update_dealer(ownerId, qrcodeUrl=qrcodeUrl, serviceName=serviceName, servicePhone=servicePhone)
  2770. if not result:
  2771. return JsonResponse({"result": 0, "description": u"更新经销商服务信息错误"})
  2772. return JsonResponse({"result": 1, "description": "", 'payload': {}})
  2773. # : 报告老板
  2774. @permission_required(ROLE.dealer, ROLE.subaccount)
  2775. def userFeedbackRecords(request):
  2776. # type: (WSGIRequest)->JsonResponse
  2777. """
  2778. 获取用户反馈记录
  2779. :param request:
  2780. :return:
  2781. """
  2782. ownerId = str(request.user.bossId)
  2783. searchKey = request.GET.get('searchKey', '')
  2784. feedType = request.GET.get('feedType', '')
  2785. pageIndex = int(request.GET.get('pageIndex', '1'))
  2786. pageSize = int(request.GET.get('pageSize', '10'))
  2787. status = request.GET.get('status', None)
  2788. if status and status != 'null':
  2789. status = int(status)
  2790. else:
  2791. status = None
  2792. dateStart = request.GET.get('dateStart', '')
  2793. if dateStart == '':
  2794. startTime = '2000-01-01 00:00:00'
  2795. else:
  2796. startTime = dateStart + " 00:00:00"
  2797. dateEnd = request.GET.get('dateEnd', '')
  2798. if dateEnd == '':
  2799. endTime = '2100-01-01 00:00:00'
  2800. else:
  2801. endTime = dateEnd + " 23:59:59"
  2802. query = {
  2803. 'ownerId': str(ownerId),
  2804. '$and': [
  2805. {
  2806. 'createTime': {
  2807. '$gte': startTime
  2808. }
  2809. },
  2810. {
  2811. 'createTime': {
  2812. '$lte': endTime
  2813. }
  2814. },
  2815. ],
  2816. }
  2817. if feedType:
  2818. if feedType == 'other':
  2819. feed_type_list = ['refund', 'upper']
  2820. query.update({
  2821. 'feedType': {'$in': feed_type_list},
  2822. 'consumeRecordOrderNo': {'$in': [None, '']}
  2823. })
  2824. else:
  2825. feed_type_list = [feedType]
  2826. query.update({
  2827. 'feedType': {'$in': feed_type_list}
  2828. })
  2829. if status is not None:
  2830. query.update({
  2831. 'status': status
  2832. })
  2833. results = FeedBack.objects(__raw__ = query).search(searchKey).order_by('-createTime')
  2834. total = results.count()
  2835. rv = []
  2836. for item in results.paginate(pageIndex, pageSize): # type: FeedBack
  2837. rv.append(item.summary)
  2838. data = {'page': pageIndex, 'total': total, 'pageSize': pageSize, 'items': rv}
  2839. return JsonResponse({'result': 1, 'description': "", 'payload': data})
  2840. @permission_required(ROLE.dealer, ROLE.subaccount)
  2841. def userFeedbackInfo(request):
  2842. # type: (WSGIRequest)->JsonResponse
  2843. fdId = str(request.GET.get('id'))
  2844. fd = FeedBack.objects(id = fdId).first() # type: FeedBack
  2845. if not fd:
  2846. return JsonResponse({'result': 0, 'description': u"投诉订单不存在,请刷新页面重试", 'payload': {}})
  2847. else:
  2848. return JsonResponse({'result': 1, 'description': "", 'payload': fd.detail})
  2849. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'处理失败'))
  2850. @permission_required(ROLE.dealer, ROLE.subaccount)
  2851. def userFeedbackHandle(request):
  2852. # type: (WSGIRequest)->JsonResponse
  2853. """
  2854. :param request:
  2855. :return:
  2856. """
  2857. payload = json.loads(request.body) if request.body else {}
  2858. if not payload:
  2859. return JsonErrorResponse(description = u'传入数据为空')
  2860. action = payload.get('action')
  2861. if not action:
  2862. return JsonOkResponse()
  2863. dealerRemark = payload.get('dealerRemark', u'(未填写回复内容)')
  2864. dealerImgList = payload.get('dealerImgList', [])
  2865. options = {} if dealerRemark is None else {'dealerRemark': dealerRemark, 'dealerImgList': dealerImgList}
  2866. feedback = FeedBack.objects(id = payload['id']).first() # type: Optional[FeedBack]
  2867. if not feedback:
  2868. return JsonErrorResponse(description = u'没有找到该反馈单')
  2869. dealer = Dealer.objects(id = feedback.ownerId).first() # type: Optional[Dealer]
  2870. if not dealer:
  2871. return JsonErrorResponse(description = u'未找到该反馈单的经销商')
  2872. feedType = feedback.feedType
  2873. if feedback.my_logicalCode:
  2874. device = Device.objects(logicalCode = feedback.my_logicalCode).first() # type: Optional[Device]
  2875. else:
  2876. device = None
  2877. if not device:
  2878. return JsonErrorResponse(description = u'找不到相关设备')
  2879. wechat_mp_proxy = get_wechat_user_manager_mp_proxy(dealer) # type: WechatClientProxy
  2880. user = MyUser.objects(openId = feedback.openId, groupId = feedback.my_group_id).first() # type: Optional[MyUser]
  2881. if not user:
  2882. logger.warning('user<openId={}> not exists for feedback<id={}>'.format(feedback.openId, str(feedback.id)))
  2883. if action in ['close', 'reject']:
  2884. feedback.handle(action, **options)
  2885. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2886. 'title': u'您反馈的问题已经处理' if action == 'close' else u'您反馈的问题已经被驳回',
  2887. 'event': '%s:%s' % (feedback.message_type, feedback.description),
  2888. 'remark': '%s: %s' % (u'设备老板回复', dealerRemark),
  2889. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2890. }) if user else None
  2891. return JsonOkResponse()
  2892. elif action == 'stop':
  2893. assert feedType == 'fault', u'投诉类型错误'
  2894. device.set_fault()
  2895. feedback.handle(action, **options)
  2896. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2897. 'title': u'您反馈的问题已经处理',
  2898. 'event': u'设备已经暂停使用,等待维修中',
  2899. 'remark': '%s: %s' % (u'设备老板回复', dealerRemark),
  2900. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2901. }) if user else None
  2902. return JsonResponse({'result': 1, 'description': "", 'payload': {}})
  2903. elif action == 'refund':
  2904. if not user:
  2905. return JsonErrorResponse(description = u'用户不存在,无法派币')
  2906. agent = Agent.objects.get(id = request.user.agentId)
  2907. if 'coinIsMoney' in agent.features:
  2908. return JsonResponse({'result': 2, 'description': u"代理商的配置,不允许给用户派币", 'payload': {}})
  2909. refundCoins = VirtualCoin(payload.get('refundCoins'))
  2910. if refundCoins > VirtualCoin(0):
  2911. inced = user.incr_balance(refundCoins)
  2912. if not inced:
  2913. logger.error('failed to incr balance for %r' % (user,))
  2914. return JsonErrorResponse(description = u'退币失败')
  2915. RechargeRecord.from_feedback(feedback, refundCoins).save()
  2916. feedback.handle(action, **options)
  2917. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2918. 'title': u'您反馈的问题已经处理',
  2919. 'event': u'%s:%s' % (feedback.message_type, feedback.description),
  2920. 'remark': '%s: %s' % (u'设备老板回复', dealerRemark),
  2921. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2922. }) if user else None
  2923. return JsonOkResponse()
  2924. else:
  2925. logger.warning('invalid action<value={}> for feedback<id=>'.format(action, str(feedback.id)))
  2926. return JsonOkResponse()
  2927. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'处理失败'))
  2928. @permission_required(ROLE.dealer, ROLE.subaccount)
  2929. def userFeedbackBatchHandle(request):
  2930. # type: (WSGIRequest)->JsonResponse
  2931. """
  2932. :param request:
  2933. :return:
  2934. """
  2935. payload = json.loads(request.body) if request.body else {}
  2936. if not payload:
  2937. return JsonErrorResponse(description = u'传入数据为空')
  2938. dealerRemark = payload.get('dealerRemark')
  2939. options = {} if dealerRemark is None else {'dealerRemark': dealerRemark}
  2940. feedbacks = FeedBack.objects(id__in = payload['ids'])
  2941. if feedbacks.count() == 0:
  2942. return JsonErrorResponse(description = u'没有找到反馈单')
  2943. for feedback in feedbacks:
  2944. feedback.handle('close', **options)
  2945. dealer = Dealer.objects(id = feedback.ownerId).first() # type: Optional[Dealer]
  2946. if not dealer:
  2947. logger.warning(
  2948. 'not find this dealer<id={}> for feedback<id={}>'.format(feedback.ownerId, str(feedback.id)))
  2949. continue
  2950. wechat_mp_proxy = get_wechat_user_manager_mp_proxy(dealer) # type: WechatClientProxy
  2951. user = MyUser.objects(openId = feedback.openId, groupId = feedback.my_group_id).first() # type: Optional[MyUser]
  2952. if not user:
  2953. logger.warning(
  2954. 'not find this user<openId={}> for feedback<id={}>'.format(feedback.openId, str(feedback.id)))
  2955. continue
  2956. wechat_mp_proxy.notify(user.managerialOpenId, 'feedback_process', **{
  2957. 'title': u'您反馈的问题已经处理',
  2958. 'event': '%s:%s' % (feedback.message_type, feedback.description),
  2959. 'finishTime': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  2960. })
  2961. return JsonOkResponse()
  2962. @error_tolerate(nil=DefaultJsonErrorResponse)
  2963. @permission_required(ROLE.dealer, ROLE.subaccount)
  2964. def getCustomerDetailInfo(request):
  2965. # type: (WSGIRequest)->JsonResponse
  2966. """
  2967. 获取用户部分详细信息,如累计充值
  2968. :param request:
  2969. :return:
  2970. """
  2971. customerOpenId = request.GET.get('id')
  2972. if not customerOpenId:
  2973. return JsonErrorResponse(description=u'传入用户ID为空,无法获取详情')
  2974. ownerId = request.user.bossId
  2975. groupIds = list(set(Group.get_group_ids_of_dealer_and_partner(ownerId)))
  2976. users = MyUser.get_collection().find({"openId": customerOpenId, "groupId": {"$in": groupIds}})
  2977. rechargeTotal = RMB(0)
  2978. bestowTotal = RMB(0)
  2979. consumptionTotal = RMB(0)
  2980. balance = RMB(0)
  2981. nickname = ""
  2982. phone = ""
  2983. openId = ""
  2984. idStr = ""
  2985. breakRuleTimes = 0
  2986. orderRemindType = 2
  2987. for user in users:
  2988. nickname = user.get('nickname', "")
  2989. balance += (RMB(user.get("chargeBalance", 0)) + RMB(user.get("bestowBalance", 0)))
  2990. rechargeTotal += RMB(user.get("total_recharged", 0))
  2991. bestowTotal += RMB(user.get("total_bestow", 0))
  2992. consumptionTotal += RMB(user.get("total_consumed", 0))
  2993. openId = user.get("openId", "")
  2994. idStr = str(user.get('_id', ''))
  2995. if user.get('blacklistConfig', {}).get('orderRemindType', 2) != 2:
  2996. orderRemindType = user['blacklistConfig']['orderRemindType']
  2997. if user.get('blacklistConfig', {}).get('breakRuleTimes', 0) != 0:
  2998. breakRuleTimes = user['blacklistConfig']['breakRuleTimes']
  2999. if breakRuleTimes > 0 and orderRemindType != 0:
  3000. orderRemindType = 0
  3001. us = MyUser.objects(openId=user['openId'], groupId__in=groupIds)
  3002. for _ in us:
  3003. _.blacklistConfig['orderRemindType'] = orderRemindType
  3004. _.save()
  3005. status = "black" if check_black_user(dealerId=str(ownerId), openId=openId) else "white"
  3006. if idStr:
  3007. user = MyUser.objects.filter(id=idStr).first()
  3008. phone = user.phone
  3009. return JsonResponse({
  3010. 'result': 1,
  3011. 'description': None,
  3012. 'payload': {
  3013. 'balance': balance,
  3014. 'nickname': nickname,
  3015. 'phone': phone,
  3016. 'rechargeTotal': rechargeTotal,
  3017. 'consumptionTotal': consumptionTotal,
  3018. 'status': status,
  3019. 'breakRuleTimes': breakRuleTimes,
  3020. 'orderRemindType': orderRemindType
  3021. }
  3022. })
  3023. @error_tolerate(nil=DefaultJsonErrorResponse)
  3024. @permission_required(ROLE.dealer, ROLE.subaccount)
  3025. def getCustomerListUnderDealer(request):
  3026. """ 获取经销商名下的用户 按照openId做归并 查询需要根据特性来决定是否做手机号码查询"""
  3027. pageIndex = int(request.GET.get('pageIndex', 1))
  3028. pageSize = int(request.GET.get('pageSize', 10))
  3029. searchKey = request.GET.get('searchKey', "")
  3030. sortKey = request.GET.get('sortName', 'last_login')
  3031. sortOrder = request.GET.get('sortType', 'des')
  3032. isNew = True if request.GET.get('isNew', 'false') == 'true' else False
  3033. ownerId = request.user.bossId
  3034. groupIds = Group.get_group_ids_of_dealer_and_partner(ownerId=ownerId)
  3035. # 获取用户默认头像
  3036. default_avatar = Agent.get_agent(request.user.agentId).get("productLogo")
  3037. sortFilters = True if sortOrder == "des" else False
  3038. groupFilters = {
  3039. "_id": "$openId",
  3040. "chargeBalance": {"$sum": "$chargeBalance"},
  3041. "bestowBalance": {"$sum": "$bestowBalance"},
  3042. "total_recharged": {"$sum": "$total_recharged"},
  3043. "total_bestow": {"$sum": "$total_bestow"},
  3044. "total_consumed": {"$sum": "$total_consumed"},
  3045. "nickname": {"$first": "$nickname"},
  3046. "sex": {"$first": "$sex"},
  3047. "avatar": {"$first": "$avatar"},
  3048. "openId": {"$first": "$openId"},
  3049. "last_login": {"$max": "$last_login"}
  3050. }
  3051. matchFilters = {
  3052. "groupId": {"$in": groupIds}
  3053. }
  3054. by_phone = False
  3055. by_user_id = False
  3056. by_others = False
  3057. if re.match(r'1[3-9][0-9]{9}$', searchKey):
  3058. by_phone = True
  3059. elif re.match(r'^[0-9]{5,10}$', searchKey):
  3060. by_user_id = True
  3061. else:
  3062. by_others = True
  3063. # 符合手机号码的正则
  3064. if by_phone or by_user_id:
  3065. if by_phone:
  3066. agent = Agent.objects.filter(id = str(request.user.myBoss.agentId)).first() # type: Agent
  3067. if agent.supports('user_identify'):
  3068. user = MyUser.objects.filter(phoneNumber = searchKey).first()
  3069. else:
  3070. user = UniqueUser.objects.filter(phone = searchKey).first() # type: UniqueUser
  3071. else:
  3072. user = UniqueUser.objects.filter(userId=searchKey).first() # type: UniqueUser
  3073. if not user:
  3074. return JsonErrorResponse(description=u"未查询到该用户")
  3075. matchFilters.update({
  3076. 'openId': user.openId
  3077. })
  3078. else:
  3079. startTime = request.GET.get('startTime', None)
  3080. endTime = request.GET.get('endTime', None)
  3081. if startTime:
  3082. startDataTime = to_datetime(startTime + ' 00:00:00')
  3083. now = datetime.datetime.now()
  3084. if not endTime:
  3085. endDateTime = now + datetime.timedelta(days=1)
  3086. else:
  3087. endDateTime = to_datetime(endTime, "%Y-%m-%d")
  3088. if endDateTime > now:
  3089. endDateTime = now
  3090. endDateTime = endDateTime + datetime.timedelta(days=1)
  3091. if startDataTime >= endDateTime:
  3092. endDateTime = startDataTime + datetime.timedelta(days=1)
  3093. timeFilters = {
  3094. "$gte": startDataTime,
  3095. "$lt": endDateTime
  3096. }
  3097. if isNew:
  3098. timeKey = "dateTimeAdded"
  3099. else:
  3100. timeKey = "last_login"
  3101. matchFilters.update({
  3102. timeKey: timeFilters
  3103. })
  3104. if searchKey:
  3105. matchFilters.update({
  3106. "nickname": {"$regex": "%s" % searchKey}
  3107. })
  3108. users = MyUser.get_collection().aggregate([
  3109. {"$match": matchFilters},
  3110. {"$group": groupFilters},
  3111. ])
  3112. totalUsers = list(users)
  3113. if sortKey == "last_login":
  3114. totalUsers.sort(key=lambda x: x.get(sortKey), reverse=sortFilters)
  3115. else:
  3116. totalUsers.sort(key=lambda x: VirtualCoin(x.get(sortKey)), reverse=sortFilters)
  3117. tempUsers = totalUsers[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  3118. for user in tempUsers:
  3119. if not user["avatar"]: user["avatar"] = default_avatar
  3120. if 'total_recharged' in user:
  3121. user['total_recharged'] = RMB(user['total_recharged'])
  3122. if 'total_consumed' in user:
  3123. user['total_consumed'] = RMB(user['total_consumed'])
  3124. if 'chargeBalance' or 'bestowBalance' in user:
  3125. user["chargeBalance"] = RMB(user.get("chargeBalance", 0))
  3126. user["bestowBalance"] = RMB(user.get("bestowBalance", 0))
  3127. user['balance'] = user['chargeBalance'] + user['bestowBalance']
  3128. return JsonResponse({
  3129. "result": 1,
  3130. "description": None,
  3131. "payload": {
  3132. "total": len(totalUsers),
  3133. "dataList": tempUsers
  3134. }
  3135. })
  3136. @error_tolerate(nil=DefaultJsonErrorResponse)
  3137. @permission_required(ROLE.dealer, ROLE.subaccount)
  3138. def getRechargeRecordByCustomer(request):
  3139. # type: (WSGIRequest)->JsonResponse
  3140. """
  3141. 由用户详情 查询用户的充值记录
  3142. :param request:
  3143. :return:
  3144. """
  3145. pageIndex = int(request.GET.get("pageIndex"))
  3146. pageSize = int(request.GET.get("pageSize"))
  3147. openId = request.GET.get("id")
  3148. cardId = request.GET.get("cardTicketId") # 直接查看某一张虚拟卡的充值记录
  3149. startTime = request.GET.get('startTime', Const.QUERY_START_DATE)
  3150. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  3151. if cardId:
  3152. orderNoList = VirtualCardRechargeRecord.get_link_orderNo_list(
  3153. cardId = cardId, startTime = to_datetime(startTime, '%Y-%m-%d'), endTime = to_datetime(endTime, '%Y-%m-%d'))
  3154. queryFilter = {
  3155. 'orderNo__in': orderNoList
  3156. }
  3157. else:
  3158. queryFilter = {
  3159. 'ownerId__in': Dealer.get_cooperative_dealer_ids(str(request.user.bossId)),
  3160. "openId": openId,
  3161. "result": "success",
  3162. "via__in": map(format, [
  3163. USER_RECHARGE_TYPE.RECHARGE,
  3164. USER_RECHARGE_TYPE.RECHARGE_CARD,
  3165. USER_RECHARGE_TYPE.RECHARGE_VIRTUAL_CARD,
  3166. USER_RECHARGE_TYPE.RECHARGE_CASH,
  3167. USER_RECHARGE_TYPE.RECHARGE_MONTHLY_PACKAGE
  3168. ]),
  3169. 'hint': [("openId", 1)]
  3170. }
  3171. records = RechargeRecord.objects.filter(
  3172. dateTimeAdded__gte=to_datetime(startTime, '%Y-%m-%d'),
  3173. dateTimeAdded__lt=to_datetime(endTime, '%Y-%m-%d'),
  3174. **queryFilter
  3175. )
  3176. dataList = list()
  3177. for record in records.paginate(pageIndex, pageSize):
  3178. _data = {
  3179. "gateway": record.gateway or 'wechat',
  3180. "createdTime": record.created_date,
  3181. "totalFee": record.money,
  3182. "gatewayTradeNo": record.wxOrderNo,
  3183. "outTradeNo": record.orderNo,
  3184. "address": record.address,
  3185. "name": record.groupName,
  3186. "groupNumber": record.groupNumber,
  3187. "devTypeName": record.dev_type_name,
  3188. "logicalCode": record.logicalCode,
  3189. "isQuickPay": record.isQuickPay,
  3190. "result": getattr(record, "result", 'success'),
  3191. "description": getattr(record, "description", ''),
  3192. "via": record.via,
  3193. "coins": record.coins
  3194. }
  3195. if "refundOrder" in request.user.features:
  3196. _data["showRefund"] = (record.is_refund_available(request.user)) and (not record.has_refund_order)
  3197. dataList.append(_data)
  3198. total = pageIndex * pageSize if len(dataList) < pageSize else (pageIndex + 1) * pageSize
  3199. return JsonResponse({'result': 1, 'description': "", 'payload': {'dataList': dataList, 'total': total}})
  3200. @error_tolerate(nil=DefaultJsonErrorResponse)
  3201. @permission_required(ROLE.dealer, ROLE.subaccount)
  3202. def getConsumptionRecordByCustomer(request):
  3203. # type: (WSGIRequest)->JsonResponse
  3204. """
  3205. :param request:
  3206. :return:
  3207. """
  3208. pageIndex = int(request.GET.get("pageIndex", 1))
  3209. pageSize = int(request.GET.get("pageSize", 10))
  3210. openId = request.GET.get("id")
  3211. groupId = request.GET.get("groupId")
  3212. lastYear = datetime.date((datetime.date.today().year - 1), datetime.date.today().month,
  3213. datetime.date.today().day).strftime("%Y-%m-%d")
  3214. startTime = request.GET.get('startTime', lastYear)
  3215. endTime = request.GET.get('endTime', datetime.datetime.now().strftime('%Y-%m-%d'))
  3216. queryFilter = {"ownerId": str(request.user.bossId), "openId": openId}
  3217. if groupId:
  3218. queryFilter.update({"groupId": groupId})
  3219. records = ClientConsumeModelProxy.get_data_list(startTime=startTime, endTime=endTime, **queryFilter)
  3220. # 修改 列表仅仅展示基础数据 详细信息在详单中查询
  3221. dataList = []
  3222. for record in records.paginate(pageIndex, pageSize):
  3223. newData = {
  3224. "groupName": record.groupName,
  3225. "groupNumber": record.groupNumber,
  3226. "devTypeName": record.devTypeName,
  3227. "logicalCode": record.logicalCode,
  3228. "createdTime": record.dateTimeAdded,
  3229. "orderNo": record.orderNo,
  3230. "id": str(record.id),
  3231. "ownerId": record.ownerId
  3232. }
  3233. newData.update(record.service)
  3234. dev = Device.get_dev_by_logicalCode(record.logicalCode) # type: DeviceDict
  3235. if dev and dev.is_registered and dev.ownerId == record.ownerId:
  3236. if (record.devTypeCode or dev.devTypeCode) == Const.DEVICE_TYPE_CODE_HP_GATE: # 霍珀道闸分支
  3237. newData.update({'desc': record.servicedInfo.get('oper', u'未知')})
  3238. elif record.devTypeCode in support_policy_weifule + support_policy_device:
  3239. if record.status != ConsumeRecord.Status.FINISHED:
  3240. if (datetime.datetime.now() - record.dateTimeAdded).total_seconds() > 60 * 60 * 12:
  3241. newData.update({'desc': '超12小时未结束'})
  3242. if record.status == ConsumeRecord.Status.RUNNING:
  3243. newData.update({'showStopButton': True})
  3244. if record.status == ConsumeRecord.Status.END:
  3245. newData.update({'showStopButton': True})
  3246. else:
  3247. continue
  3248. dataList.append(newData)
  3249. total = pageIndex * pageSize if len(dataList) < pageSize else (pageIndex + 1) * pageSize
  3250. return JsonResponse({'result': 1, 'description': "", 'payload': {'dataList': dataList, 'total': total}})
  3251. @error_tolerate(nil=DefaultJsonErrorResponse)
  3252. @permission_required(ROLE.dealer, ROLE.subaccount)
  3253. def modifyCustomerBalance(request):
  3254. # type: (WSGIRequest)->JsonResponse
  3255. """
  3256. 给终端用户派币或扣币(通常情况不支持)
  3257. :param request:
  3258. :return:
  3259. """
  3260. currentDealer = request.user.myBoss # type: Optional[Dealer]
  3261. agent = Agent.objects.filter(id=str(currentDealer.agentId)).first() # type: Agent
  3262. if 'disable_dealer_onPoints_and_sendCoins' in agent.features:
  3263. return JsonResponse(
  3264. {'result': 0, 'description': '设备无法使用该功能奥, 如有问题, 请联系代理商', 'payload': {}})
  3265. payload = json.loads(request.body) if request.body else {}
  3266. if not payload: return JsonErrorResponse(description=u'传入数据为空')
  3267. coins = VirtualCoin(payload.get('coins', 0.0))
  3268. desc = payload.get('description')
  3269. customerOpenId = payload.get('userId')
  3270. groupId = payload.get('groupId')
  3271. ownerId = str(currentDealer.bossId)
  3272. operator = currentDealer.nickname
  3273. customer = MyUser.objects(groupId=groupId, openId=customerOpenId).first() # type: Optional[MyUser]
  3274. if not customer:
  3275. return JsonResponse({'result': 0, 'description': u'该用户不存在', 'payload': {}})
  3276. if coins < VirtualCoin(0) and -coins > customer.balance:
  3277. return JsonResponse({'result': 0, 'description': u'最多只能扣除掉%s个币' % customer.balance, 'payload': {}})
  3278. agent = Agent.objects.get(id=currentDealer.agentId)
  3279. if 'coinIsMoney' in agent.features:
  3280. return JsonResponse({'result': 0, 'description': u'代理商的配置,不允许给用户派币', 'payload': {}})
  3281. group = Group.get_group(groupId)
  3282. if group['ownerId'] != ownerId:
  3283. return JsonResponse({'result': 0, 'description': u'不是您家设备喔,不能派币', 'payload': {}})
  3284. payload = {
  3285. 'orderNo': str(uuid.uuid1()),
  3286. 'openId': customerOpenId,
  3287. 'coins': coins,
  3288. 'description': desc,
  3289. 'groupId': groupId,
  3290. 'groupName': group.groupName,
  3291. 'address': group.address,
  3292. 'ownerId': ownerId,
  3293. 'operator': operator,
  3294. 'result': 'success',
  3295. 'via': 'sendcoin'
  3296. }
  3297. record = RechargeRecord(**payload)
  3298. customer.recharge(RMB(0), RMB(coins))
  3299. record.save()
  3300. customer.account_recharge(record)
  3301. if coins > VirtualCoin(0):
  3302. try:
  3303. task_caller(
  3304. 'report_to_user_via_wechat', openId=customerOpenId,
  3305. dealerId=str(request.user.bossId),
  3306. templateName='refund_coins', **{
  3307. 'title': u'尊敬的客户,已经退回%s金币到您的余额,您下次可以接着使用。祝您生活愉快。' % coins,
  3308. 'backCount': u'金币:%s' % coins,
  3309. 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  3310. }
  3311. )
  3312. except Exception as e:
  3313. logger.exception(e)
  3314. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  3315. @error_tolerate(nil=DefaultJsonErrorResponse)
  3316. @permission_required(ROLE.dealer, ROLE.subaccount)
  3317. def getModifyCustomerBalanceRecord(request):
  3318. # type: (WSGIRequest)->JsonResponse
  3319. """
  3320. 获取派币记录
  3321. :param request:
  3322. :return:
  3323. """
  3324. pageIndex = int(request.GET.get('pageIndex', 1))
  3325. pageSize = int(request.GET.get('pageSize', 10))
  3326. customerOpenId = request.GET.get('id', None)
  3327. user = MyUser.objects(openId=customerOpenId).first()
  3328. if not user:
  3329. records = RechargeRecord.objects(
  3330. ownerId=str(request.user.bossId),
  3331. via='sendcoin').order_by('-dateTimeAdded').skip((pageIndex - 1) * pageSize).limit(pageSize)
  3332. else:
  3333. records = RechargeRecord.objects(
  3334. ownerId=str(request.user.bossId),
  3335. openId=customerOpenId,
  3336. via='sendcoin').order_by('-dateTimeAdded').skip((pageIndex - 1) * pageSize).limit(pageSize)
  3337. dataList = []
  3338. if not user:
  3339. for r in records:
  3340. u = MyUser.objects(openId=r.openId).first()
  3341. if u is None:
  3342. logger.error('invalid openId, openId=%s' % r.openId)
  3343. continue
  3344. dataList.append({
  3345. 'name': u.nickname if u.nickname is not None else '',
  3346. 'avatar': u.avatar,
  3347. 'id': customerOpenId,
  3348. 'remarks': r.my_description,
  3349. 'operator': r.operator,
  3350. 'coins': r.coins,
  3351. 'groupName': r.groupName,
  3352. 'createdTime': r.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  3353. })
  3354. else:
  3355. dataList = [
  3356. {
  3357. 'name': user.nickname if user.nickname is not None else '',
  3358. 'avatar': user.avatar,
  3359. 'id': customerOpenId,
  3360. 'remarks': r.my_description,
  3361. 'operator': r.operator,
  3362. 'coins': r.coins,
  3363. 'groupName': r.groupName,
  3364. 'createdTime': r.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  3365. } for r in records
  3366. ]
  3367. count = records.count()
  3368. if count <= pageSize:
  3369. total = (pageIndex - 1) * pageSize + count
  3370. else:
  3371. total = (pageIndex - 1) * pageSize + 100
  3372. return JsonResponse(
  3373. {
  3374. 'result': 1,
  3375. 'description': None,
  3376. 'payload':
  3377. {
  3378. 'dataList': paginate(dataList, pageIndex, pageSize),
  3379. 'total': total,
  3380. 'sendCoinsTotal': VirtualCoin(records.sum('coins'))
  3381. }
  3382. }
  3383. )
  3384. # 导出派币记录
  3385. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取派币记录失败"))
  3386. @permission_required(ROLE.dealer)
  3387. def reportModifyCustomerBalanceRecord(request):
  3388. """
  3389. 导出派币记录
  3390. """
  3391. dealer = request.user
  3392. def get_offline_task_name(task_type, user, **kwargs):
  3393. # type: (basestring, Dealer, Dict)->basestring
  3394. tmp_list = [task_type, user.username]
  3395. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  3396. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  3397. if 'groupId' in kwargs and kwargs['groupId']:
  3398. address = Group.get_group(kwargs['groupId']).get('address', '')
  3399. tmp_list.append(u'地址_%s' % (address,))
  3400. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  3401. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  3402. return '-'.join(tmp_list).replace("/", "_")
  3403. query_dict = {
  3404. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  3405. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  3406. 'pageIndex': int(request.GET.get('pageIndex', 1)),
  3407. 'pageSize': int(request.GET.get('pageSize', 10)),
  3408. 'customerOpenId': request.GET.get('id', None),
  3409. "ownerId": str(request.user.bossId),
  3410. }
  3411. offline_task_name = get_offline_task_name(
  3412. task_type=u'地址用户充值消费情况统计报表',
  3413. user=dealer,
  3414. **query_dict)
  3415. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  3416. process_func_name='export_modify_customer_balance_record_excel_from_db',
  3417. task_type=OfflineTaskType.BUSINESS_REPORT,
  3418. userid=str(dealer.id),
  3419. role=ROLE.dealer)
  3420. task_caller(func_name=offline_task.process_func_name,
  3421. offline_task_id=str(offline_task.id),
  3422. filepath=file_path,
  3423. queryDict=query_dict)
  3424. return JsonResponse({
  3425. 'result': 1,
  3426. 'description': u"请前往离线任务查看任务处理情况",
  3427. 'payload': str(offline_task.id)})
  3428. @error_tolerate(nil=DefaultJsonErrorResponse)
  3429. @permission_required(ROLE.dealer, ROLE.subaccount)
  3430. def getRefundRecord(request):
  3431. # type: (WSGIRequest)->JsonResponse
  3432. """
  3433. 获取退币记录
  3434. :param request:
  3435. :return:
  3436. """
  3437. pageIndex = int(request.GET.get('pageIndex', 1))
  3438. pageSize = int(request.GET.get('pageSize', 10))
  3439. customerOpenId = request.GET.get('id', None)
  3440. if not customerOpenId:
  3441. return JsonErrorResponse(description=u'提交的用户id为空')
  3442. user = MyUser.objects(openId=customerOpenId).first().to_dict()
  3443. records = RechargeRecord.objects(ownerId=str(request.user.bossId), openId=customerOpenId, via='refund').order_by("-dateTimeAdded")
  3444. dealer = Dealer.objects(id=str(request.user.bossId)).get()
  3445. dataList = [
  3446. {
  3447. 'name': user['nickname'],
  3448. 'avatar': user['avatar'],
  3449. 'id': customerOpenId,
  3450. 'description': r.my_description,
  3451. 'operator': dealer.nickname,
  3452. 'coins': r.coins,
  3453. 'groupName': r.groupName,
  3454. 'createdTime': r.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  3455. } for r in records
  3456. ]
  3457. total = records.count()
  3458. return JsonResponse(
  3459. {
  3460. 'result': 1,
  3461. 'description': None,
  3462. 'payload':
  3463. {
  3464. 'dataList': paginate(dataList, pageIndex, pageSize),
  3465. 'total': total,
  3466. 'refundTotal': VirtualCoin(records.sum('coins'))
  3467. }
  3468. }
  3469. )
  3470. @error_tolerate(nil=DefaultJsonErrorResponse)
  3471. @permission_required(ROLE.dealer, ROLE.subaccount)
  3472. def payGateway(request):
  3473. # type: (WSGIRequest)->JsonResponse
  3474. current_user = request.user # type: Dealer
  3475. try:
  3476. # TODO # 此处流量卡传的是param 其他 加盟 api支付的都是传 params
  3477. payload = json.loads(request.GET.get('param') or request.GET.get('params'))
  3478. order_no = payload.get('orderNo')
  3479. if not order_no:
  3480. return JsonErrorResponse(u'参数错误,请刷新后再试')
  3481. record = DealerRechargeRecord.objects(orderNo=order_no).first() # type: DealerRechargeRecord
  3482. if not record:
  3483. return JsonErrorResponse(u'订单不存在,请刷新后再试')
  3484. payment_gateway = PaymentGateway.from_gateway_key(
  3485. record.gateway,
  3486. record.payGatewayKey,
  3487. record.payAppType) # type: Optional[WechatPaymentGateway]
  3488. logger.info('dealer wechat charge: gateway = %s; orderNo = %s, totalFee = %s' % (
  3489. repr(payment_gateway), order_no, record.totalFee))
  3490. OrderCacheMgr(record).initial()
  3491. attach = {'dealerId': record.dealerId}
  3492. body = record.get_body()
  3493. # 转成以元为单位的钱,后面流程统一处理
  3494. money = RMB(record.totalFee) * Decimal('0.01')
  3495. if payment_gateway.pay_app_type == PayAppType.WECHAT:
  3496. data = payment_gateway.generate_js_payment_params(
  3497. payOpenId=payload.get('openId'),
  3498. out_trade_no=order_no,
  3499. notify_url=PAY_NOTIFY_URL.WECHAT_PAY_BACK,
  3500. money=money,
  3501. body=body,
  3502. attach=attach)
  3503. data.update({
  3504. 'outTradeNo': record.orderNo, 'adShow': current_user.ad_show
  3505. })
  3506. response = JsonResponse({'result': 1, 'description': '', 'payload': data})
  3507. else:
  3508. raise Exception(cn(u'不支持该支付类型'))
  3509. task_caller(func_name='poll_dealer_recharge_record',
  3510. delay=PollRecordDefine.DELAY_BEFORE,
  3511. expires=PollRecordDefine.TASK_EXPIRES,
  3512. record_id=str(record.id),
  3513. pay_app_type=payment_gateway.pay_app_type,
  3514. interval=PollRecordDefine.WAIT_EACH_ROUND,
  3515. total_count=PollRecordDefine.TOTAL_ROUNDS)
  3516. return response
  3517. except WeChatException as e:
  3518. logger.exception(e)
  3519. return JsonErrorResponse(description = e.tip)
  3520. except Exception as e:
  3521. logger.exception(e)
  3522. return JsonErrorResponse(description=u'系统开小差了,请刷新后再试')
  3523. @error_tolerate(nil=DefaultJsonErrorResponse)
  3524. @permission_required(ROLE.dealer, ROLE.subaccount)
  3525. def getDeviceCardList(request):
  3526. # type: (WSGIRequest)->JsonResponse
  3527. def cmp_expire_time(x, y):
  3528. if not x['simExpireDate']:
  3529. return 1
  3530. if not y['simExpireDate']:
  3531. return -1
  3532. if x['simExpireDate'] > y['simExpireDate']:
  3533. return -1
  3534. elif x['simExpireDate'] < y['simExpireDate']:
  3535. return 1
  3536. else:
  3537. return 0
  3538. searchKey = request.GET.get('searchKey', '')
  3539. dealerId = str(request.user.bossId)
  3540. agent = Agent.objects(id=request.user.agentId).first() # type: Optional[Agent]
  3541. if not agent:
  3542. logger.error('agent<id={}> is not exist.'.format(request.user.agentId))
  3543. return JsonErrorResponse(description=u'系统错误')
  3544. groupIds = Group.get_group_ids_of_dealer(dealerId)
  3545. groupDict = Group.get_groups_by_group_ids(groupIds)
  3546. devNoList = Device.get_devNos_by_group(groupIds)
  3547. devices = Device.get_dev_by_nos(devNoList).values()
  3548. annualTrafficCost = request.user.annualTrafficCost
  3549. devList = []
  3550. for dev in devices: # type: DeviceDict
  3551. try:
  3552. if searchKey in dev['groupNumber'] or searchKey in dev.devNo or searchKey in dev[
  3553. 'remarks'] or searchKey in dev.logicalCode:
  3554. group = groupDict.get(dev.groupId)
  3555. if (settings.DEBUG and dev.logicalCode.startswith('DUMMY')) or dev.is_expired or dev.sim_expire_notify:
  3556. item = {
  3557. 'logicalCode': dev.logicalCode,
  3558. 'devNo': dev.devNo,
  3559. 'devTypeName': dev.devType['name'],
  3560. 'groupName': group['groupName'],
  3561. 'groupNumber': dev['groupNumber'],
  3562. 'groupId': group['groupId'],
  3563. 'simExpireDate': dev.fixedSimExpireDate,
  3564. 'channelType': dev.channelType
  3565. }
  3566. devList.append(item)
  3567. except Exception, e:
  3568. logger.exception('[device]some error=%s' % e)
  3569. continue
  3570. devList.sort(cmp=cmp_expire_time)
  3571. pageIndex = int(request.GET.get('pageIndex', 1))
  3572. pageSize = int(request.GET.get('pageSize', 100))
  3573. items = devList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  3574. devObjs = { obj.devNo: obj for obj in Device.objects.filter(devNo__in=[item['devNo'] for item in items])}
  3575. for item in items:
  3576. dev_obj = devObjs[item['devNo']] # type: Device
  3577. trafficCardCost = dev_obj.trafficCardCost
  3578. if not trafficCardCost:
  3579. if request.user.trafficCardCost:
  3580. trafficCardCost = request.user.trafficCardCost
  3581. else:
  3582. trafficCardCost = agent.trafficCardCost
  3583. item['price'] = trafficCardCost if trafficCardCost > annualTrafficCost else annualTrafficCost
  3584. items = sorted(items, key=lambda x:x['groupId'])
  3585. return JsonResponse({
  3586. 'result': 1,
  3587. 'description': None,
  3588. 'payload': {'page': pageIndex, 'total': len(devList), 'pageSize': pageSize, 'offset': 0,
  3589. 'items': items}
  3590. })
  3591. @error_tolerate(nil=DefaultJsonErrorResponse)
  3592. @permission_required(ROLE.dealer, ROLE.subaccount)
  3593. def getSimRechargeOrderList(request):
  3594. # type: (WSGIRequest)->JsonResponse
  3595. filterQuery = Q(
  3596. __raw__ = {
  3597. 'dealerId': str(request.user.bossId),
  3598. 'product': {'$in': [DealerRechargeRecord.ProductType.SimCard, DealerRechargeRecord.ProductType.AutoSimCard]}
  3599. })
  3600. status = request.GET.get('status', None)
  3601. if status:
  3602. filterQuery &= Q(__raw__={'status': status})
  3603. else:
  3604. filterQuery &= Q(
  3605. __raw__={'status': {'$nin': [DealerRechargeRecord.PayState.Cancel, DealerRechargeRecord.PayState.Close]}})
  3606. searchKey = request.GET.get('searchKey', '')
  3607. if searchKey:
  3608. pattern = Regex.from_native(re.compile('.*' + searchKey + '.*'))
  3609. filterQuery &= (Q(__raw__={'items': {'$elemMatch': {'name': {'$regex': pattern}}}}) | Q(
  3610. __raw__={'orderNo': {"$regex": pattern}}))
  3611. records = DealerRechargeRecord.objects(
  3612. __raw__=filterQuery.to_query(DealerRechargeRecord)).order_by("-createdTime")
  3613. items = []
  3614. for record in records: # type: DealerRechargeRecord
  3615. item = {
  3616. 'name': record.name,
  3617. 'totalFee': str(RMB(float(record['totalFee']) / 100)),
  3618. 'orderNo': record.orderNo,
  3619. 'status': record.status,
  3620. 'createdTime': record.createdTime,
  3621. 'finishedTime': record.finishedTime
  3622. }
  3623. items.append(item)
  3624. pageIndex = int(request.GET.get('pageIndex', 1))
  3625. pageSize = int(request.GET.get('pageSize', 10))
  3626. return JsonResponse({
  3627. 'result': 1,
  3628. 'description': '',
  3629. 'payload': {
  3630. 'page': pageIndex, 'total': len(items), 'pageSize': pageSize, 'offset': 0,
  3631. 'items': items[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  3632. }
  3633. })
  3634. @error_tolerate(nil=DefaultJsonErrorResponse)
  3635. @permission_required(ROLE.dealer, ROLE.subaccount)
  3636. def createSimRechargeOrder(request):
  3637. # type: (WSGIRequest)->JsonResponse
  3638. current_user = request.user # type: Dealer
  3639. devNoList = set(request.POST.getlist('list[]'))
  3640. payment_gateway = get_inhourse_wechat_env_pay_gateway(
  3641. ROLE.dealer) # type: Union[WechatPaymentGateway]
  3642. record = create_dealer_sim_charge_order(payment_gateway, current_user, devNoList)
  3643. if record:
  3644. return JsonResponse({'result': 1, 'description': u'创建订单成功', 'payload': record.orderNo})
  3645. else:
  3646. return JsonErrorResponse(u'创建订单异常失败')
  3647. @error_tolerate(nil=DefaultJsonErrorResponse)
  3648. @permission_required(ROLE.dealer, ROLE.subaccount)
  3649. def cancelSimRechargeOrder(request):
  3650. # type: (WSGIRequest)->JsonResponse
  3651. try:
  3652. payload = json.loads(request.body) if request.body else {}
  3653. if not payload:
  3654. return JsonErrorResponse(description=u'数据不完整,请重试')
  3655. order_no = payload['orderNo']
  3656. order = DealerRechargeRecord.objects(orderNo=order_no).first() # type: DealerRechargeRecord
  3657. if not order:
  3658. return JsonErrorResponse(u'订单不存在,请刷新后再试')
  3659. if not order.is_unpay:
  3660. return JsonErrorResponse(u'订单已经处理,无法取消')
  3661. if order.cancel():
  3662. return JsonOkResponse('ok')
  3663. else:
  3664. return JsonErrorResponse(u'订单已经处理,无法取消')
  3665. except Exception as e:
  3666. logger.exception('unable to cancel dealer order, error=%s' % (e,))
  3667. return JsonErrorResponse(description=u"系统错误")
  3668. @error_tolerate(nil=DefaultJsonErrorResponse)
  3669. @permission_required(ROLE.dealer, ROLE.subaccount)
  3670. def getSimRechargeOrderDetail(request):
  3671. # type: (WSGIRequest)->JsonResponse
  3672. try:
  3673. orderNo = request.GET.get('orderNo')
  3674. order = DealerRechargeRecord.objects(orderNo = orderNo).first() # type: DealerRechargeRecord
  3675. if not order:
  3676. return JsonErrorResponse(u'订单不存在,请刷新后再试')
  3677. else:
  3678. return JsonResponse({'result': 1, 'description': '', 'payload':
  3679. {
  3680. 'orderNo': order.orderNo,
  3681. 'totalFee': '%.02f' % (float(order.totalFee) / 100),
  3682. 'status': order.status,
  3683. 'createdTime': order.createdTime,
  3684. 'items': order.items
  3685. }})
  3686. except Exception as e:
  3687. logger.exception('get dealer pay order list failure, error = %s' % (e,))
  3688. return JsonErrorResponse(description = u'查询订单失败')
  3689. @error_tolerate(nil=DefaultJsonErrorResponse)
  3690. def getOwnerAgents(request):
  3691. try:
  3692. username = request.GET.get('username')
  3693. managerId = request.GET.get('managerId')
  3694. logger.debug('getOwnerAgents: username = %s; managerId = %s' % (username, managerId))
  3695. agents = [str(a.id) for a in Agent.objects(managerId=str(managerId)).all()]
  3696. items = []
  3697. dealers = Dealer.get_collection().find({'username': username, 'agentId': {'$in': agents}})
  3698. for dealer in dealers:
  3699. agentId = dealer['agentId']
  3700. agent = Agent.get_agent(agentId)
  3701. item = {
  3702. 'agentId': agentId,
  3703. 'userHeadImg': agent['avatar'],
  3704. 'agentLogoUrl': agent['productLogo'],
  3705. 'agentBrandName': agent['productName'],
  3706. 'displayName': agent['productName']
  3707. }
  3708. items.append(item)
  3709. return JsonResponse({
  3710. 'result': 1,
  3711. 'description': None,
  3712. 'payload': {'total': len(items),
  3713. 'items': items}
  3714. })
  3715. except Exception as e:
  3716. logger.exception('get dealer owner agents failure, error = %s' % (e,))
  3717. return JsonErrorResponse(description=u'网络错误,请刷新后再试')
  3718. @error_tolerate(nil=DefaultJsonErrorResponse)
  3719. @permission_required(ROLE.dealer, ROLE.subaccount)
  3720. def getEquipmentTotal(request):
  3721. # type: (WSGIRequest)->JsonResponse
  3722. dealerId = str(request.user.bossId)
  3723. groupIds = Group.get_group_ids_of_dealer(dealerId)
  3724. devNoList = Device.get_devNos_by_group(groupIds)
  3725. return JsonResponse({'result': 1, 'description': '', 'payload': len(devNoList)})
  3726. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'设备类型不支持'))
  3727. @permission_required(ROLE.dealer, ROLE.subaccount)
  3728. def getPackageList(request):
  3729. # type: (WSGIRequest)->JsonResponse
  3730. devTypeId = request.GET.get('typeId', None)
  3731. if not devTypeId:
  3732. return JsonResponse({'result': 0, 'description': u'设备类型为空', 'payload': {}})
  3733. dealer = request.user.myBoss # type: Dealer
  3734. devType = DeviceType.objects.filter(id=str(devTypeId)).first() # type: DeviceType
  3735. if devType['code'] in support_policy_weifule + support_policy_device:
  3736. isTemp = request.GET.get('isTemp', None) == 'true'
  3737. from apps.web.core.models import DriverAdapter
  3738. adapter = DriverAdapter.get_driver_adapter(devType['code'], None)
  3739. if adapter.support_device_package:
  3740. payload = adapter.get_reg_model(dealer, devTypeId, isTemp=isTemp)
  3741. return JsonResponse({'result': 1, 'description': None, 'payload': payload})
  3742. dataList = {}
  3743. if devTypeId in dealer.defaultWashConfig:
  3744. dataList = dealer.defaultWashConfig[devTypeId]
  3745. if not dataList:
  3746. dataList = DeviceType.objects(id=str(devTypeId)).get().package
  3747. no_unit_list = filter(lambda x: x.get("unit") == None, dataList)
  3748. if len(no_unit_list) == len(dataList):
  3749. datalist = map(lambda x: (x.update({"unit": "分钟"}), x)[1], dataList)
  3750. displaySwitchs = {}
  3751. if hasattr(devType, "displayPriceSwitch"):
  3752. displaySwitchs.update({"displayPriceSwitch": devType.displayPriceSwitch})
  3753. if hasattr(devType, "displayCoinsSwitch"):
  3754. displaySwitchs.update({"displayCoinsSwitch": devType.displayCoinsSwitch})
  3755. if hasattr(devType, "displayTimeSwitch"):
  3756. displaySwitchs.update({"displayTimeSwitch": devType.displayTimeSwitch})
  3757. if hasattr(devType, "setPulseAble"):
  3758. displaySwitchs.update({"setPulseAble": devType.setPulseAble})
  3759. if hasattr(devType, "setBasePriceAble"):
  3760. displaySwitchs.update({"setBasePriceAble": devType.setBasePriceAble})
  3761. if devType['code'] in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG]:
  3762. displaySwitchs = {
  3763. 'displayPriceSwitch': True,
  3764. 'displayCoinsSwitch': False,
  3765. 'displayTimeSwitch': False,
  3766. 'setPulseAble': False,
  3767. 'setBasePriceAble': False,
  3768. }
  3769. return JsonResponse({'result': 1, 'description': None, 'payload': {'ruleList':dataList, 'displaySwitchs':displaySwitchs}})
  3770. # ## 经销商绑定微信(为了接受微信推送)
  3771. @permission_required(ROLE.dealer, ROLE.subaccount)
  3772. def getDealerBindWechatSMSCode(request):
  3773. # type: (WSGIRequest)->JsonResponse
  3774. """
  3775. :param request:
  3776. :return:
  3777. """
  3778. try:
  3779. phoneNumber = request.user.username
  3780. agent = Agent.get_agent(request.user.agentId)
  3781. productName = agent['productName']
  3782. if not phoneNumber:
  3783. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  3784. status, msg = dealerBindWechatSMSProvider.get(phoneNumber=phoneNumber,
  3785. productName=productName,
  3786. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  3787. if not status:
  3788. return JsonResponse({'result': 0, 'description': msg})
  3789. else:
  3790. return JsonResponse({'result': 1, 'description': ''})
  3791. except Exception, e:
  3792. logger.exception('unable to get %s' % e)
  3793. return JsonResponse({'result': 0, 'description': ''})
  3794. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误'))
  3795. @permission_required(ROLE.dealer, ROLE.subaccount)
  3796. def verifyNewWechatBinding(request):
  3797. # type: (WSGIRequest)->JsonResponse
  3798. """
  3799. 跳转到微信授权页面绑定
  3800. :param request:
  3801. :return:
  3802. """
  3803. currentDealer = request.user # type: cast(Dealer)
  3804. code = request.POST.get('code')
  3805. if not code:
  3806. return JsonErrorResponse(description=u'code未提供')
  3807. status, msg = dealerBindWechatSMSProvider.verify(phoneNumber=request.user.username, smsCode=code)
  3808. if not status:
  3809. return JsonErrorResponse(description=msg)
  3810. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_MANAGER)
  3811. return JsonResponse(
  3812. {
  3813. 'result': 1,
  3814. 'description': None,
  3815. 'payload': {
  3816. 'redirect_uri': auth_bridge.generate_auth_url_user_scope(
  3817. redirect_uri=DEALER_BIND_WECHAT_URL)
  3818. }
  3819. })
  3820. @error_tolerate(logger=logger, nil=DealerBindIdResponseRedirect(result='error'))
  3821. @permission_required(ROLE.dealer, ROLE.subaccount)
  3822. def verifyNewWechatBindingCallback(request):
  3823. # type: (WSGIRequest)->JsonResponse
  3824. """
  3825. 绑定后台openId
  3826. TODO: 加入变更记录
  3827. :param request:
  3828. :return:
  3829. """
  3830. auth_code = request.GET.get('code')
  3831. if not auth_code:
  3832. return JsonErrorResponse(description=u'未收到code,请刷新重试')
  3833. currentDealer = request.user # type: cast(Dealer)
  3834. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_MANAGER)
  3835. user_info = auth_bridge.get_user_info(auth_code=auth_code)
  3836. user_info_payload = {
  3837. 'avatar': user_info['avatar'],
  3838. 'country': user_info['country'],
  3839. 'province': user_info['province'],
  3840. 'city': user_info['city'],
  3841. 'sex': user_info['sex'],
  3842. 'nickname': user_info['nickname']
  3843. }
  3844. logger.debug('dealer(id=%s) is binding wechat for messaging, bridge=%s' % (str(request.user.bossId), auth_bridge))
  3845. dealerWechatBindingUpdated = request.user.update(
  3846. managerialAppId=auth_bridge.app.appid,
  3847. managerialOpenId=user_info['openId'],
  3848. wechatAuthUserInfo=user_info_payload,
  3849. managerialWechatBoundTime=datetime.datetime.now())
  3850. if dealerWechatBindingUpdated:
  3851. return DealerBindIdResponseRedirect(result='ok')
  3852. else:
  3853. return DealerBindIdResponseRedirect(result='error')
  3854. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误'))
  3855. @permission_required(ROLE.dealer, ROLE.subaccount)
  3856. def getBoundWechat(request):
  3857. # type: (WSGIRequest)->JsonResponse
  3858. """
  3859. 获取绑定后台openId的用户信息
  3860. :param request:
  3861. :return:
  3862. """
  3863. ownerId = str(request.user.bossId)
  3864. dealer = Dealer.objects(id=ownerId).get() # type: Dealer
  3865. return JsonResponse(
  3866. {
  3867. "result": 1,
  3868. "description": None,
  3869. 'payload': {
  3870. "bound": dealer.isManagerialOpenIdBound,
  3871. "avatar": dealer.wechatAuthUserInfo.get('avatar'),
  3872. "sex": dealer.wechatAuthUserInfo.get('sex'),
  3873. "nickname": dealer.wechatAuthUserInfo.get('nickname')
  3874. }
  3875. })
  3876. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  3877. def setAdShow(request):
  3878. # type: (WSGIRequest)->JsonResponse
  3879. try:
  3880. payload = json.loads(request.body) if request.body else {}
  3881. if not payload:
  3882. return JsonErrorResponse(description=u'数据不完整,请重试')
  3883. user = Dealer.objects.get(id=payload['id']) if 'id' in payload else request.user # type: Dealer
  3884. adShow = payload.get('adShow', user.adShow)
  3885. user.adShow = adShow
  3886. user.save()
  3887. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  3888. except DoesNotExist, e:
  3889. logger.exception("dealer does not exist, error = %s" % e)
  3890. return JsonResponse({"result": 0, "description": u'经销商不存在', 'payload': {}})
  3891. except Exception, e:
  3892. logger.exception("set adShow error = %s" % e)
  3893. return JsonResponse({"result": 0, "description": u'系统错误', 'payload': {}})
  3894. @permission_required(ROLE.manager)
  3895. def getDealerDetailList(request):
  3896. # type: (WSGIRequest)->JsonResponse
  3897. """
  3898. 厂商获取经销商详情
  3899. :param request:
  3900. :return:
  3901. """
  3902. def count_devices(ownerId):
  3903. devNoList = [device['devNo'] for device in
  3904. Device.get_collection().find({'ownerId': ownerId, 'groupId': {'$ne': ''}}, {'devNo': 1, '_id': 0})]
  3905. allCount = len(devNoList)
  3906. devDict = Device.get_dev_by_nos(devNoList)
  3907. if not devDict:
  3908. return 0, 0, 0
  3909. onlineCount = 0
  3910. for devNo, dev in devDict.items():
  3911. if dev["online"]:
  3912. onlineCount += 1
  3913. offlineCount = allCount - onlineCount
  3914. return onlineCount, offlineCount, allCount
  3915. mid = str(request.user.id)
  3916. pageIndex = int(request.GET.get('pageIndex', 1))
  3917. pageSize = int(request.GET.get('pageSize', 10))
  3918. agentId = request.GET.get('agentId', None)
  3919. searchKey = request.GET.get('searchKey', None)
  3920. dealers = Dealer.search(searchKey)
  3921. agentMap = {str(agent.id): agent.username for agent in Agent.objects(managerId=mid)}
  3922. agentIds = agentMap.keys()
  3923. if agentId:
  3924. dealers = dealers.filter(agentId=agentId)
  3925. elif agentIds:
  3926. dealers = dealers.filter(agentId__in=agentIds)
  3927. total = dealers.count()
  3928. dealers_per_page = dealers.skip((pageIndex - 1) * pageSize).limit(pageSize)
  3929. dataList = []
  3930. for d in dealers_per_page:
  3931. report = Accounting.getOwnerIncome(str(d.id), now=datetime.datetime.now())
  3932. onlineCount, offlineCount, allCount = count_devices(str(d.id))
  3933. hasZJFirePlatform = True
  3934. ZJFirePlatform = {}
  3935. try:
  3936. obj = Company.objects.get(ownerId=str(d.id))
  3937. ZJFirePlatform = {
  3938. 'companyName': obj.name,
  3939. 'companyCode': obj.code,
  3940. 'companyAddress': obj.address,
  3941. 'contactsName': obj.contactName,
  3942. 'contactsTel': obj.telephone,
  3943. 'deviceManufacturer': obj.manufacturer
  3944. }
  3945. hasZJFirePlatform = True
  3946. except Exception, e:
  3947. pass
  3948. now = datetime.datetime.now()
  3949. today = now.strftime(Const.DATE_FMT)
  3950. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(d.id), 'date':today}, {'daily':1, 'activedDevRatio':1})
  3951. if rcds.count() == 0:
  3952. todayIncome = 0
  3953. todayRechargeIncome = 0
  3954. todayChargeCardIncome = 0
  3955. else:
  3956. info = rcds[0]
  3957. todayIncome = info.get('daily', {}).get('totalIncome', 0)
  3958. income = info.get('daily', {}).get('income', {})
  3959. todayRechargeIncome = income.get('recharge', 0)
  3960. todayChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('virtualChargeCard', 0))
  3961. monthDay = MONTH_DATE_KEY.format(year=now.year, month=now.month)
  3962. rcds = DealerMonthlyStat.get_collection().find({'dealerId':ObjectId(d.id), 'date':monthDay}, {'addedUserCount':1})
  3963. if rcds.count() == 0:
  3964. userCountAddedThisMonth = 0
  3965. else:
  3966. info = rcds[0]
  3967. userCountAddedThisMonth = rcds[0].get('addedUserCount', 0)
  3968. detail = d.to_dict()
  3969. dataList.append({
  3970. 'id': str(d.id),
  3971. 'name': d.nickname,
  3972. 'tel': d.username,
  3973. 'agentInfo': agentMap.get(detail['agentId'], ''),
  3974. 'dateTimeAdded': d.dateTimeAdded,
  3975. 'lineCoins': report['lineCoins'],
  3976. 'payIncome': todayIncome,
  3977. 'todayRechargeIncome': todayRechargeIncome,
  3978. 'todayChargeCardIncome': todayChargeCardIncome,
  3979. 'userCount':d.userCount,
  3980. 'userCountAddedThisMonth':userCountAddedThisMonth,
  3981. 'devTotalNum': allCount,
  3982. 'offlineTotal': offlineCount,
  3983. 'onlineTotal': onlineCount,
  3984. 'detail': json_dumps(detail),
  3985. 'ZJFirePlatform': ZJFirePlatform,
  3986. 'hasZJFirePlatform': hasZJFirePlatform,
  3987. 'disableDevice': True if "dealerDisableDevice" in d.features else False
  3988. })
  3989. return JsonResponse({
  3990. 'result': 1,
  3991. 'description': '',
  3992. 'payload': {
  3993. 'total': total,
  3994. 'dataList': dataList
  3995. }
  3996. })
  3997. @permission_required(ROLE.manager)
  3998. def getDealerListByAgent(request):
  3999. # type: (WSGIRequest)->JsonResponse
  4000. """
  4001. :param request:
  4002. :return:
  4003. """
  4004. agentIds = json.loads(request.body).get('agentIds', [])
  4005. agents = {str(_.id): _.nickname for _ in Agent.objects(id__in=agentIds)}
  4006. if not agents: return JsonResponse({'result': 1, 'payload': []})
  4007. dataList = [
  4008. {
  4009. 'dealerName': _.nickname,
  4010. 'dealerId': str(_.id),
  4011. 'agentId': str(_.agentId),
  4012. 'agentName': agents[str(_.agentId)]
  4013. }
  4014. for _ in Dealer.objects(agentId__in=agentIds)
  4015. ]
  4016. return JsonResponse({'result': 1, 'payload': {'dataList': dataList, 'total': len(dataList)}})
  4017. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取设备列表失败'))
  4018. @permission_required(ROLE.dealer, ROLE.subaccount)
  4019. def equipmentList(request):
  4020. # type: (WSGIRequest)->JsonResponse
  4021. def _get_port_status(portDict):
  4022. allPorts = portDict.get("allPorts", 0)
  4023. usedPorts = portDict.get("usedPorts", 0)
  4024. usePorts = portDict.get("usePorts", 0)
  4025. return allPorts, usedPorts, usePorts
  4026. dealerId = str(request.user.bossId)
  4027. pageIndex = int(request.GET.get('pageIndex', 1))
  4028. pageSize = int(request.GET.get('pageSize', 10))
  4029. equipmentGroupId = request.GET.get('equipmentGroupId')
  4030. online = request.GET.get('online')
  4031. searchKey = request.GET.get('searchKey', '')
  4032. sort = request.GET.get('sort', 'logicalCode')
  4033. partnerGroupList = Group.get_group_ids_of_partner(dealerId)
  4034. ownGroupList = Group.get_group_ids_of_dealer(dealerId)
  4035. groupIds = partnerGroupList + ownGroupList
  4036. if not equipmentGroupId:
  4037. selectedGroupIds = groupIds
  4038. else:
  4039. selectedGroupIds = [equipmentGroupId]
  4040. if not online:
  4041. onlineStates = [0, 1]
  4042. else:
  4043. onlineStates = [int(online)]
  4044. groupDict = Group.get_groups_by_group_ids(selectedGroupIds)
  4045. devNoList = Device.get_devNos_by_group(selectedGroupIds)
  4046. devs = Device.get_dev_by_nos(devNoList).values()
  4047. devDict, deviceCount = {}, 0
  4048. devCacheMap = Device.get_many_dev_control_cache(devNoList)
  4049. showPortStatus = bool(request.user.feature_boolean_map.get("showPortStatus", None))
  4050. for dev in devs: # type: DeviceDict
  4051. if dev.online not in onlineStates:
  4052. continue
  4053. group = groupDict.get(dev['groupId'])
  4054. if group is None:
  4055. continue
  4056. if any(map(lambda _: searchKey in _, (dev['devNo'],
  4057. dev['remarks'],
  4058. dev['logicalCode'],
  4059. group['groupName'],
  4060. group['address']))):
  4061. isFault = dev.get('isFault', False)
  4062. isDND = dev.is_DND_now
  4063. item = {
  4064. 'id': dev.devNo,
  4065. 'logicalCode': dev.logicalCode,
  4066. 'name': group['groupName'],
  4067. 'groupId': group['groupId'],
  4068. 'type': dev.devType['name'],
  4069. 'typeId': dev.devType['id'],
  4070. 'devType': dev.devType,
  4071. 'unit': dev.devType.get('unit', DeviceType.unit.default),
  4072. 'online': dev.online,
  4073. 'signal': dev.signal,
  4074. 'timeBased': dev.devType.get('timeBased', DeviceType.timeBased.default),
  4075. 'autoRefundEnable': dev.devType.get('autoRefundEnable', DeviceType.autoRefundEnable.default),
  4076. 'channelType': dev.channelType,
  4077. 'isManager': False if dev['groupId'] in partnerGroupList else True,
  4078. 'serviceState': dev.get('serviceState', Const.ServiceState.Normal.name),
  4079. 'remarks': dev.get('remarks', Device.remarks.default),
  4080. 'status': dev.status,
  4081. 'statusInfo': dev.statusInfo,
  4082. 'isFault': isFault,
  4083. 'isDND': isDND,
  4084. 'offTimeDate': datetime.datetime.fromtimestamp(int(str(dev.offTime)[0:10])).strftime('%Y-%m-%d %H:%M:%S') if dev.offTime is not None else '',
  4085. 'tag': group.get("tag", ""),
  4086. "deviceWarning": dev.is_warning
  4087. }
  4088. # 最近离线时间小于2017年的都为空
  4089. offTimeYear = int(item['offTimeDate'][0:4])
  4090. if offTimeYear < 2017:
  4091. item['offTimeDate'] = ''
  4092. if showPortStatus:
  4093. # 这个地方需要添加 具体的端口 使用情况 故障、工作、空闲等 使用情况从缓存中直接读取,如果不存在 则没有,不去具体查询设备
  4094. devCache = devCacheMap.get(device_control_cache_key(dev["devNo"]), {})
  4095. allPorts, usedPorts, usePorts = _get_port_status(devCache)
  4096. hasPort = showPortStatus and bool(allPorts)
  4097. item.update({"hasPort": hasPort})
  4098. if hasPort: item.update(
  4099. {"portStatus":
  4100. {
  4101. "all": allPorts,
  4102. "idle": usePorts,
  4103. "used": usedPorts,
  4104. }
  4105. }
  4106. )
  4107. else:
  4108. item.update({"hasPort": False})
  4109. if not dev.online and Device.utils_is_expired(dev):
  4110. item.update({'simExpireDate': dev.formatSimExpireDate, 'simStatus': dev.simStatus})
  4111. if dev['groupId'] in devDict:
  4112. devDict[dev['groupId']].append(item)
  4113. else:
  4114. devDict[dev['groupId']] = [item]
  4115. # 近7日平均使用率
  4116. if dev.devType.get('features', {}).get('7_days_average_utilization_rate', False) is True:
  4117. nowDateTime = datetime.datetime.now()
  4118. sevenDaysAgoDateTime = nowDateTime - datetime.timedelta(days=7)
  4119. consumeRecords = ConsumeRecord.objects(devNo=dev.devNo, dateTimeAdded__gte=sevenDaysAgoDateTime, dateTimeAdded__lte=nowDateTime)
  4120. sevenDaysAverage = round(((float(consumeRecords.count()) / 7) / 10) * 100, 2)
  4121. item.update({'sevenDaysAverage': sevenDaysAverage})
  4122. deviceCount += 1
  4123. showGroups = paginate(sorted(devDict.keys(), reverse=False), pageSize=pageSize, pageIndex=pageIndex)
  4124. devList = []
  4125. for keyGrp in showGroups:
  4126. devList.extend(devDict[keyGrp])
  4127. if sort == 'logicalCode':
  4128. tempList = natural_sort(array=devList, key='logicalCode', reverse=False)
  4129. elif sort == 'devType':
  4130. tempList = sorted(devList, key=lambda x: x['devType']['name'])
  4131. elif sort == 'remarks':
  4132. tempList = sorted(devList, key=lambda x: x['remarks'], reverse=True)
  4133. elif sort == "tag":
  4134. tempList = devList
  4135. else:
  4136. raise InvalidParameter(u'搜索条件不合法')
  4137. if sort == "tag":
  4138. devList = sorted(tempList, key=lambda x: x['tag'], reverse=True)
  4139. else:
  4140. devList = sorted(tempList, key=lambda x: x['groupId'])
  4141. return JsonResponse({
  4142. "result": 1,
  4143. "description": None,
  4144. 'payload': {
  4145. "total": deviceCount,
  4146. "groupCount": len(devDict.keys()),
  4147. "dataList": devList
  4148. }
  4149. })
  4150. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取库存列表失败'))
  4151. @permission_required(ROLE.dealer, ROLE.subaccount)
  4152. def equipmentListForStock(request):
  4153. # type: (WSGIRequest)->JsonResponse
  4154. ownerId = str(request.user.bossId)
  4155. equipmentGroupId = request.GET.get('equipmentGroupId', 'all')
  4156. online = request.GET.get('online', 'all')
  4157. searchKey = request.GET.get('searchKey', '')
  4158. groupIds, devTempList = Device.filter(dealerId=ownerId, searchKey=searchKey, online=online,
  4159. equipmentGroupId=equipmentGroupId)
  4160. devList = []
  4161. for dev in devTempList:
  4162. if not dev.has_key('quantity'):
  4163. continue
  4164. devList.append(dev)
  4165. return JsonResponse({
  4166. "result": 1,
  4167. "description": None,
  4168. 'payload': {
  4169. "total": len(groupIds),
  4170. "groupCount": len(devList),
  4171. "dataList": devList
  4172. }
  4173. })
  4174. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'解绑失败'))
  4175. @permission_required(ROLE.dealer, ROLE.subaccount)
  4176. @request_limit_by_user(operation='unbindDevice', limit=100, logger=logger)
  4177. def unbindDevice(request):
  4178. def unbindDeviceDefault(request):
  4179. # type: (WSGIRequest)->JsonResponse
  4180. """
  4181. 经销商解绑设备
  4182. ..modified 去掉对代理商串货的限制
  4183. :param request:
  4184. :return:
  4185. """
  4186. owner_id = str(request.user.bossId)
  4187. devNo = request.POST.get('value', None)
  4188. if devNo is None:
  4189. return JsonResponse({"result": 0, "description": u"缺少参数", 'payload': {}})
  4190. dev = Device.get_dev(devNo) # type: DeviceDict
  4191. devType = dev['devType']
  4192. groupId = dev['groupId']
  4193. if dev is None:
  4194. return JsonResponse({"result": 0, "description": u"该设备不存在,请刷新后再试", 'payload': {}})
  4195. if not dev.is_registered:
  4196. return JsonResponse({"result": 0, "description": u"该设备没有注册,不需要解绑", 'payload': {}})
  4197. if dev.ownerId != owner_id:
  4198. return JsonResponse({"result": 0, "description": u"不是您的设备,不能够解绑", 'payload': {}})
  4199. try:
  4200. Device.un_register(dev=dev, operator=request.user.human_id)
  4201. dealer = Dealer.objects.get(id=owner_id)
  4202. dealer.devCount -= 1
  4203. dealer.save()
  4204. except RentDeviceError as rde:
  4205. return JsonErrorResponse(rde.message)
  4206. except Exception as e:
  4207. logger.exception(
  4208. 'un register failure. error = %s, devNo = %s, ownerId = %s' % (e, devNo, str(request.user.bossId)))
  4209. return JsonResponse({"result": 0, "description": u"系统错误", 'payload': {}})
  4210. group = Group.get_group(groupId)
  4211. if group.get('swapFlag', False):
  4212. agentId = request.user.agentId
  4213. agent = Agent.objects(id=agentId).first()
  4214. if agent:
  4215. devNum = 0
  4216. if 'majorDeviceType' in devType and (u'直流' in devType['majorDeviceType'] or u'交流' in devType['majorDeviceType']):
  4217. devNum = -1
  4218. SwapGroup.update_swap_time_and_num(groupId, devNum)
  4219. SwapContract.update_swap_time_and_num(groupId, owner_id, agentId, agent.managerId, devNum)
  4220. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4221. current_user = request.user # type: UserSearchable
  4222. if not current_user.normal:
  4223. return JsonResponse({"result": 0, "description": u"账号异常,不能进行该操作", 'payload': {}})
  4224. return unbindDeviceDefault(request)
  4225. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'解绑失败'))
  4226. @permission_required(ROLE.dealer, ROLE.subaccount)
  4227. @request_limit_by_user(operation='unbindAllNode', limit=100, logger=logger)
  4228. def unbindAllNode(request):
  4229. # 获取主机的子节点
  4230. lc = request.POST.get('logicalCode', None)
  4231. master = Device.get_dev_by_l(lc) # type: DeviceDict
  4232. nodeList = master.deviceAdapter.get_node_list()
  4233. if not nodeList:
  4234. return JsonResponse({"result": 0, "description": u"该设备不存在,请刷新后再试", 'payload': {}})
  4235. owner_id = str(request.user.bossId)
  4236. # TODO 和刘崇确认 此处先简单修复 然后后续可能进行优化
  4237. # 进行检查 保证所有设备都是 该经销商的
  4238. errDevs = list()
  4239. for node in nodeList: # type: DeviceDict
  4240. if not node.is_registered:
  4241. continue
  4242. if node.ownerId != owner_id:
  4243. errDevs.append(node.logicalCode)
  4244. if errDevs:
  4245. return JsonErrorResponse(description=u"设备{} 不是您的设备 无法解绑".format(" ".join(errDevs)))
  4246. # 再解除经销商绑定
  4247. for node in nodeList:
  4248. if not node.is_registered:
  4249. continue
  4250. Device.un_register(dev=node, operator=request.user.human_id)
  4251. dealer = Dealer.objects.get(id=owner_id)
  4252. dealer.devCount -= 1
  4253. dealer.save()
  4254. return JsonOkResponse()
  4255. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除套餐失败'))
  4256. @permission_required(ROLE.dealer, ROLE.subaccount)
  4257. def delPackages(request):
  4258. # type: (WSGIRequest)->JsonResponse
  4259. curr_user = request.user # type: Union[Dealer, SubAccount]
  4260. if not curr_user.normal:
  4261. return JsonErrorResponse(description=u'账号异常,不能进行该操作')
  4262. devNo = request.POST.get('devNo', None)
  4263. ruleId = request.POST.get('ruleId', None)
  4264. if devNo is None or ruleId is None:
  4265. return JsonResponse({"result": 0, "description": u"缺少参数", 'payload': {}})
  4266. dev = Device.get_dev(devNo)
  4267. if dev is None:
  4268. return JsonResponse({"result": 0, "description": u"找不到设备", 'payload': {}})
  4269. try:
  4270. dev['washConfig'].pop(ruleId)
  4271. except Exception, e:
  4272. logger.exception('pop washconfig error=%s,ruleId=%s,devNo=%s' % (e, ruleId, devNo))
  4273. return JsonResponse({"result": 0, "description": u'该套餐已经被删除了,请刷新页面', 'payload': {}})
  4274. try:
  4275. Device.get_collection().update_one({'devNo': devNo}, {'$set': {'washConfig': dev['washConfig']}})
  4276. Device.invalid_device_cache(devNo)
  4277. except Exception, e:
  4278. logger.exception('update device washconfig error=%s,devNo=%s,washConfig=%s' % (e, devNo, dev['washConfig']))
  4279. return JsonResponse({"result": 0, "description": u'保存套餐出错,请稍候再试', 'payload': {}})
  4280. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4281. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取套餐失败'))
  4282. @permission_required(ROLE.dealer, ROLE.agent, ROLE.subaccount)
  4283. def getPackages(request):
  4284. # type: (WSGIRequest)->JsonResponse
  4285. lc = request.GET.get('logicalCode', None)
  4286. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  4287. if dev is None:
  4288. return JsonErrorResponse(description=u"找不到设备")
  4289. maxCoins = dev.get('maxCoins', 4)
  4290. devNo = dev.devNo
  4291. # 设备没注册, 走脉冲测试
  4292. if not dev.ownerId:
  4293. devData = {
  4294. 'id': devNo,
  4295. 'maxCoins': maxCoins,
  4296. 'devNo': devNo,
  4297. 'type': u'脉冲',
  4298. 'typeCode': u'201',
  4299. 'groupName': u'测试',
  4300. 'groupNumber': 666
  4301. }
  4302. defaultWashconfig = {'1': {'coins': 1}, '2': {'coins': 2}, '3': {'coins': 3}, '4': {'coins': 4},
  4303. '5': {'coins': 5}}
  4304. ruleList = [
  4305. {
  4306. 'id': packageId,
  4307. 'name': u'测试',
  4308. 'coins': rule['coins'],
  4309. 'price': rule.get('price', rule['coins'])
  4310. } for packageId, rule in defaultWashconfig.items()
  4311. ]
  4312. return JsonResponse({"result": 1, "description": None, 'payload': {'devData': devData, 'ruleList': ruleList}})
  4313. group = Group.get_group(dev['groupId'])
  4314. if group is None:
  4315. return JsonErrorResponse(description=u'找不到设备')
  4316. if group['ownerId'] != str(request.user.bossId):
  4317. return JsonErrorResponse(description=u'找不到设备')
  4318. devData = {
  4319. 'id': devNo,
  4320. 'maxCoins': maxCoins,
  4321. 'isManager': True,
  4322. 'groupName': group['groupName'],
  4323. 'groupNumber': dev['groupNumber'],
  4324. 'devNo': devNo,
  4325. 'type': dev['devType']['name'],
  4326. 'typeCode': dev['devType']['code']
  4327. }
  4328. if "displaySwitchs" in dev["otherConf"]:
  4329. displaySwitchs = dev["otherConf"].get('displaySwitchs')
  4330. else:
  4331. displaySwitchs = {'displayCoinsSwitch': True,
  4332. 'displayTimeSwitch': True,
  4333. 'displayPriceSwitch': True,
  4334. "setPulseAble": False,
  4335. "setBasePriceAble": False}
  4336. if dev.channelType != DeviceChannelType.Channel_BT:
  4337. smartBox = ActionDeviceBuilder.create_action_device(dev)
  4338. try:
  4339. portDict = smartBox.dealer_get_port_status()
  4340. if portDict:
  4341. chargeIndex = {}
  4342. for index, info in portDict.items():
  4343. if "status" not in info:
  4344. continue
  4345. if info['status'] == Const.DEV_WORK_STATUS_IDLE:
  4346. chargeIndex[index] = 'idle'
  4347. elif info['status'] == Const.DEV_WORK_STATUS_WORKING:
  4348. chargeIndex[index] = 'busy'
  4349. elif info['status'] == Const.DEV_WORK_STATUS_FAULT:
  4350. chargeIndex[index] = 'fault'
  4351. elif info['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
  4352. chargeIndex[index] = 'ban'
  4353. elif info['status'] == Const.DEV_WORK_STATUS_CONNECTED:
  4354. chargeIndex[index] = 'connected'
  4355. elif info['status'] == Const.DEV_WORK_STATUS_FINISHED:
  4356. chargeIndex[index] = 'finished'
  4357. devData.update({'chargeIndex': chargeIndex})
  4358. except ServiceException, e:
  4359. return JsonErrorResponse(description=e.result.get('description'))
  4360. except Exception as e:
  4361. logger.exception(e)
  4362. return JsonErrorResponse(description=u'未知错误')
  4363. if dev["devType"]["code"] == Const.DEVICE_TYPE_CODE_HP_GATE:
  4364. if request.GET.get("isRemoteUpper", None):
  4365. ruleList = []
  4366. else:
  4367. tempList = sorted(dev["washConfig"].get("1", {}).items(), key=lambda x: x[0])
  4368. ruleList = [v for _, v in tempList]
  4369. chargeIndex = {}
  4370. if dev["otherConf"].get("controlEnter") in ("1", "2"):
  4371. chargeIndex["enter"] = "idle"
  4372. if dev["otherConf"].get("controlExit") in ("1", "2"):
  4373. chargeIndex["exit"] = "idle"
  4374. devData.update({'chargeIndex': chargeIndex})
  4375. if request.GET.get("isRemoteUpper", None):
  4376. ruleList = []
  4377. elif dev["devType"]["code"] in support_policy_weifule:
  4378. if dev.deviceAdapter.support_device_package:
  4379. payload = dev.deviceAdapter.dealer_show_package()
  4380. payload.update({"devData": devData})
  4381. return JsonOkResponse(payload=payload)
  4382. elif dev["devType"]["code"] in support_policy_device:
  4383. if dev.deviceAdapter.support_device_package:
  4384. payload = dev.deviceAdapter.dealer_show_package()
  4385. payload.update({"devData": devData})
  4386. return JsonOkResponse(payload=payload)
  4387. elif dev["devType"]["code"] in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG, Const.DEVICE_TYPE_CODE_CHARGE_XIAOKEDOU]:
  4388. if dev.deviceAdapter.support_device_package:
  4389. payload = dev.deviceAdapter.dealer_show_package()
  4390. payload.update({"devData": devData})
  4391. return JsonOkResponse(payload=payload)
  4392. else:
  4393. snRuleList = []
  4394. ruleList = []
  4395. for packageId, rule in dev['washConfig'].items():
  4396. item = {
  4397. 'id': packageId,
  4398. 'name': rule['name'],
  4399. 'coins': rule['coins'],
  4400. 'price': rule.get('price', rule['coins']),
  4401. 'time': rule.get('time', 20),
  4402. 'description': rule.get('description', ''),
  4403. 'imgList': rule.get('imgList', []),
  4404. 'unit': rule.get('unit', u'分钟'),
  4405. 'switch': rule.get('switch', True),
  4406. }
  4407. if rule.get('pulse'):
  4408. item.update({
  4409. 'pulse': rule.get('pulse'),
  4410. })
  4411. if rule.get('basePrice'):
  4412. item.update({
  4413. 'basePrice': rule.get('basePrice'),
  4414. })
  4415. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  4416. item.update({
  4417. 'billingMethod': rule['billingMethod'],
  4418. })
  4419. if 'sn' in rule:
  4420. item['sn'] = rule['sn']
  4421. ruleList.append(item)
  4422. ruleList = sorted(ruleList, key=lambda x: (x.get('sn'), x.get('id')))
  4423. payload = {"devData": devData, "ruleList": ruleList, 'displaySwitchs': displaySwitchs}
  4424. unit_price = dev.otherConf.get('unit_price', {})
  4425. if dev.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_WEIFULE2]:
  4426. try:
  4427. if not unit_price:
  4428. dev.deviceAdapter.set_dev_setting(dev.deviceAdapter.get_dev_setting())
  4429. unit_price = Device.get_dev_by_l(lc).otherConf.get('unit_price', {})
  4430. except:
  4431. pass
  4432. if unit_price:
  4433. payload.update({'unit_price': unit_price})
  4434. return JsonOkResponse(payload=payload)
  4435. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存套餐失败'))
  4436. @permission_required(ROLE.dealer, ROLE.subaccount)
  4437. def savePackages(request):
  4438. """
  4439. 保存套餐
  4440. :param request:
  4441. :return:
  4442. """
  4443. # 检测套餐单位一致性校验
  4444. def check_package_unit(typeCode, package):
  4445. # 电川汽车装有按金额启动,电量启动和充满自停的需求
  4446. if typeCode == Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING:
  4447. return True
  4448. if typeCode in skip_package_unit_verify_list:
  4449. return True
  4450. dic = map(lambda x: {'unit': x.get('unit') }, package)
  4451. res = reduce(lambda x, y: x if x == y else None, dic)
  4452. if res is None:
  4453. return False
  4454. else:
  4455. return True
  4456. # 检查套餐单位单位小数点后两位校验
  4457. def check_params_range(typeCode, package):
  4458. if typeCode in skip_package_range_verify_list:
  4459. return None
  4460. dic = map(lambda x: [x.get('time')], package)
  4461. res = reduce(lambda x, y: x + y, dic)
  4462. result = None
  4463. for item in res:
  4464. l = str(item).split(".")
  4465. if len(l) > 1 and len(l[1]) > 2:
  4466. result = (res.index(item) // 3) + 1
  4467. break
  4468. return result
  4469. # 套餐参数完整性校验
  4470. def check_params(typeCode, package):
  4471. if typeCode in skip_package_params_verify_list:
  4472. return True
  4473. lis = map(lambda x: [x.get('time'), x.get('price'), x.get('coins')], package)
  4474. res = reduce(lambda x, y: x + y, lis)
  4475. for i in res:
  4476. if i is None or float(i) < 0:
  4477. return False
  4478. return True
  4479. # 套餐和金币是否需要强制1:1
  4480. def check_price_equal_coin(_devDict, _package):
  4481. for _dev in _devDict.values():
  4482. # 非出租设备 不影响
  4483. if not _dev.isRent:
  4484. continue
  4485. for _rule in _package:
  4486. if RMB(_rule["price"]) != RMB(_rule["coins"]):
  4487. return False
  4488. return True
  4489. curr_user = request.user # type: Union[Dealer, SubAccount]
  4490. if not curr_user.normal:
  4491. return JsonErrorResponse(description=u'账号异常,不能进行该操作')
  4492. status, msg = ensure_all_fields_are_not_empty(
  4493. {k: v for k, v in request.POST.items() if k not in ('ruleId',)})
  4494. if not status:
  4495. return JsonErrorResponse(description=msg)
  4496. paras = json.loads(request.body) if request.body else {}
  4497. if not paras:
  4498. return JsonErrorResponse(description=u'提交数据为空')
  4499. if paras['logicalCode'].__class__.__name__ == 'list':
  4500. devNoList = [Device.get_devNo_by_logicalCode(lc) for lc in paras['logicalCode']]
  4501. else:
  4502. devNoList = [Device.get_devNo_by_logicalCode(paras['logicalCode'])]
  4503. devDict = Device.get_dev_by_nos(devNoList)
  4504. if not devDict:
  4505. return JsonErrorResponse(description=u'找不到设备')
  4506. typeCode = devDict.values()[0]['devType']['code']
  4507. if typeCode in support_policy_weifule:
  4508. dev = devDict.values()[0]
  4509. if dev.deviceAdapter.support_device_package:
  4510. try:
  4511. dev.deviceAdapter.format_device_package(**paras)
  4512. except ServiceException as e:
  4513. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  4514. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4515. elif typeCode in support_policy_device:
  4516. dev = devDict.values()[0]
  4517. if dev.deviceAdapter.support_device_package:
  4518. try:
  4519. dev.deviceAdapter.format_device_package(**paras)
  4520. except ServiceException as e:
  4521. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  4522. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4523. # 解析washConfig,如果需要下发设备,解析出来setConfig
  4524. serviceList = paras['serviceData']
  4525. displaySwitchs = paras.get('displaySwitchs', {'displayCoinsSwitch': True,
  4526. 'displayTimeSwitch': True,
  4527. 'displayPriceSwitch': True,
  4528. 'setPulseAble': False,
  4529. 'setBasePriceAble': False})
  4530. # 调整sn顺序
  4531. for item in serviceList:
  4532. item["sn"] = serviceList.index(item)
  4533. if not check_params(typeCode, serviceList):
  4534. return JsonErrorResponse(description=u'请完整的填写套餐中的所有参数')
  4535. if not check_package_unit(typeCode, serviceList):
  4536. return JsonErrorResponse(description=u'套餐用户获得参数单位配置需要一致')
  4537. f = check_params_range(typeCode, serviceList)
  4538. if f:
  4539. return JsonErrorResponse(description=u'第%s个套餐 用户获得参数应为小数点后两位' % f)
  4540. if not check_price_equal_coin(devDict, serviceList):
  4541. return JsonErrorResponse(description=u"套餐金币与价格必须相等!")
  4542. washConfig, setConfig = {}, {}
  4543. agent = Agent.objects.get(id=request.user.agentId)
  4544. existIds = []
  4545. for rule in serviceList:
  4546. if 'id' in rule:
  4547. existIds.append(rule['id'])
  4548. # 霍珀道闸 后付费模式 使用阶梯计费
  4549. if typeCode == Const.DEVICE_TYPE_CODE_HP_GATE:
  4550. rule = {str(index + 1): v for index, v in enumerate(serviceList)}
  4551. washConfig = {"1": rule}
  4552. elif typeCode in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE,Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG, Const.DEVICE_TYPE_CODE_CHARGE_XIAOKEDOU]:
  4553. dev = devDict.values()[0]
  4554. if dev.deviceAdapter.support_device_package:
  4555. try:
  4556. washConfig, displaySwitchs = dev.deviceAdapter.format_device_package(**paras)
  4557. except ServiceException as e:
  4558. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  4559. else:
  4560. for rule in serviceList:
  4561. if rule.has_key('coins') and rule.has_key('price'):
  4562. if not (is_number(rule['coins']) and is_number(rule['price']) and is_number(
  4563. rule.get('time', 0))):
  4564. return JsonErrorResponse(description=u'金币数目或者时间或者价格必须是数字')
  4565. else:
  4566. rule['coins'], rule['price'] = 0, 0 # 对于那种先不需要付费的,这个就直接是0
  4567. if RMB(rule['price']) >= request.user.maxPackagePrice:
  4568. return JsonErrorResponse(description=u'套餐金额超限')
  4569. if len(rule['name']) > 20:
  4570. return JsonErrorResponse(description=u'套餐名字只能取1-20位')
  4571. if typeCode == Const.DEVICE_TYPE_CODE_WASHER:
  4572. name = rule['name']
  4573. if name not in [Const.WASHER_BOX_SET_DTS, Const.WASHER_BOX_SET_KSX, Const.WASHER_BOX_SET_BZX,
  4574. Const.WASHER_BOX_SET_DWX, Const.WASHER_BOX_SET_JRKS, Const.WASHER_BOX_SET_JRBZ,
  4575. Const.WASHER_BOX_JRDW, Const.WASHER_BOX_SET_TQJ]:
  4576. return JsonErrorResponse(description=u'套餐名称只能是:桶清洁、单脱水、快速洗、标准洗、大物洗、加热快速洗、加热标准洗、加热大物洗。')
  4577. coins = rule['coins']
  4578. useTime = rule['time']
  4579. if name == Const.WASHER_BOX_SET_DTS:
  4580. setConfig[Const.WASHER_BOX_DTS] = {'price': int(coins), 'time': int(useTime)}
  4581. elif name == Const.WASHER_BOX_SET_KSX:
  4582. setConfig[Const.WASHER_BOX_KS] = {'price': int(coins), 'time': int(useTime)}
  4583. elif name == Const.WASHER_BOX_SET_BZX:
  4584. setConfig[Const.WASHER_BOX_BZ] = {'price': int(coins), 'time': int(useTime)}
  4585. elif name == Const.WASHER_BOX_SET_DWX:
  4586. setConfig[Const.WASHER_BOX_DW] = {'price': int(coins), 'time': int(useTime)}
  4587. elif name == Const.WASHER_BOX_SET_JRKS:
  4588. setConfig[Const.WASHER_BOX_JRKS] = {'price': int(coins), 'time': int(useTime)}
  4589. elif name == Const.WASHER_BOX_SET_JRBZ:
  4590. setConfig[Const.WASHER_BOX_JRBZ] = {'price': int(coins), 'time': int(useTime)}
  4591. elif name == Const.WASHER_BOX_SET_JRDW:
  4592. setConfig[Const.WASHER_BOX_JRDW] = {'price': int(coins), 'time': int(useTime)}
  4593. elif (typeCode == Const.DEVICE_TYPE_CODE_WASHER_CW) and \
  4594. (rule['name'] not in [u'标准洗', u'快速洗', u'强力洗', u'单脱水', u'轻柔洗', u'漂洗并脱水', u'自洁', u'能效-全载', u'能效-半载',
  4595. u'整机自检', u'电脑版自检']):
  4596. return JsonErrorResponse(description=u'套餐名称只能是:标准洗,快速洗,强力洗,单脱水,轻柔洗,漂洗并脱水,自洁,能效-全载,能效-半载,整机自检,电脑版自检')
  4597. elif typeCode == Const.DEVICE_TYPE_CODE_WASHER_SIMAIER:
  4598. if rule['name'] not in [u'加强洗', u'标准洗', u'快速洗', u'单脱水']:
  4599. return JsonErrorResponse(description=u'套餐名称只能是:加强洗,标准洗,快速洗,单脱水')
  4600. elif typeCode == Const.DEVICE_TYPE_CODE_HUITENG:
  4601. if rule['name'] not in [u'单脱水', u'快速洗', u'标准洗', u'大物洗']:
  4602. return JsonErrorResponse(description=u'套餐名称只能是:单脱水,快速洗,标准洗,大物洗')
  4603. elif typeCode == Const.DEVICE_TYPE_CODE_CAR_CHARGING_CY:
  4604. price = rule.get("price")
  4605. coins = rule.get("coins")
  4606. unit = rule.get("unit")
  4607. time = rule.get("time")
  4608. if price != coins:
  4609. return JsonErrorResponse(description=u'请将金币和套餐值设置相同')
  4610. if unit != u"次":
  4611. return JsonErrorResponse(description=u'计费单位只能是:次')
  4612. if int(time) != 1:
  4613. return JsonErrorResponse(description=u"计费次数只能是:1")
  4614. elif typeCode in [Const.DEVICE_TYPE_CODE_WASHER_CY_HS,Const.DEVICE_TYPE_CODE_WASHER_CY_HS_YUCHUAN]:
  4615. if rule['name'] not in [u'大物洗', u'标准洗', u'快速洗', u'单脱水']:
  4616. return JsonErrorResponse(description=u'套餐名称只能是:大物洗,标准洗,快速洗,单脱水')
  4617. if rule['unit'] != "分钟":
  4618. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4619. if rule["name"] == u"单脱水" and (int(rule["time"]) > 9 or int(rule["time"]) < 5):
  4620. return JsonErrorResponse(description=u"单脱水时间范围为5-9分钟")
  4621. if rule["name"] == u"快速洗" and (int(rule["time"]) > 32 or int(rule["time"]) < 20):
  4622. return JsonErrorResponse(description=u"快速洗时间范围为20-32分钟")
  4623. if rule["name"] == u"标准洗" and (int(rule["time"]) > 43 or int(rule["time"]) < 35):
  4624. return JsonErrorResponse(description=u"标准洗时间范围为35-43分钟")
  4625. if rule["name"] == u"大物洗" and (int(rule["time"]) > 53 or int(rule["time"]) < 45):
  4626. return JsonErrorResponse(description=u"大物洗时间范围为45-53分钟")
  4627. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4628. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4629. elif typeCode in [Const.DEVICE_TYPE_CODE_WASHER_CY_HJ]:
  4630. if rule['name'] not in [u'大物洗', u'标准洗', u'快速洗', u'单脱水']:
  4631. return JsonErrorResponse(description=u'套餐名称只能是:大物洗,标准洗,快速洗,单脱水')
  4632. if rule['unit'] != "分钟":
  4633. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4634. if rule["name"] == u"单脱水" and (int(rule["time"]) > 15 or int(rule["time"]) < 5):
  4635. return JsonErrorResponse(description=u"单脱水时间范围为5-15分钟")
  4636. if rule["name"] == u"快速洗" and (int(rule["time"]) > 35 or int(rule["time"]) < 20):
  4637. return JsonErrorResponse(description=u"快速洗时间范围为20-35分钟")
  4638. if rule["name"] == u"标准洗" and (int(rule["time"]) > 50 or int(rule["time"]) < 35):
  4639. return JsonErrorResponse(description=u"标准洗时间范围为35-50分钟")
  4640. if rule["name"] == u"大物洗" and (int(rule["time"]) > 65 or int(rule["time"]) < 50):
  4641. return JsonErrorResponse(description=u"大物洗时间范围为50-65分钟")
  4642. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4643. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4644. elif typeCode in [Const.DEVICE_TYPE_CODE_WASHER_CY_HJ_1]:
  4645. if rule['name'] not in [u'大物洗', u'标准洗', u'快速洗', u'单脱水']:
  4646. return JsonErrorResponse(description=u'套餐名称只能是:大物洗,标准洗,快速洗,单脱水')
  4647. if rule['unit'] != "分钟":
  4648. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4649. if rule["name"] == u"单脱水" and (int(rule["time"]) > 15 or int(rule["time"]) < 5):
  4650. return JsonErrorResponse(description=u"单脱水时间范围为5-15分钟")
  4651. if rule["name"] == u"快速洗" and (int(rule["time"]) > 35 or int(rule["time"]) < 18):
  4652. return JsonErrorResponse(description=u"快速洗时间范围为18-35分钟")
  4653. if rule["name"] == u"标准洗" and (int(rule["time"]) > 45 or int(rule["time"]) < 30):
  4654. return JsonErrorResponse(description=u"标准洗时间范围为30-45分钟")
  4655. if rule["name"] == u"大物洗" and (int(rule["time"]) > 55 or int(rule["time"]) < 40):
  4656. return JsonErrorResponse(description=u"大物洗时间范围为40-55分钟")
  4657. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4658. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4659. elif typeCode == "1003053":
  4660. if rule['name'] not in [u'加时烘干', u'快速烘干', u'标准烘干', u'特别烘干']:
  4661. return JsonErrorResponse(description=u'套餐名称只能是:加时烘干,快速烘干,标准烘干,特别烘干')
  4662. if rule['unit'] != "分钟":
  4663. return JsonErrorResponse(description=u"请将套餐的价格设置为分钟")
  4664. if rule["name"] == u"加时烘干" and (int(rule["time"]) > 20 or int(rule["time"]) < 5):
  4665. return JsonErrorResponse(description=u"加时烘干时间范围为5-20分钟")
  4666. if rule["name"] == u"快速烘干" and (int(rule["time"]) > 40 or int(rule["time"]) < 20):
  4667. return JsonErrorResponse(description=u"快速洗时间范围为20-40分钟")
  4668. if rule["name"] == u"标准烘干" and (int(rule["time"]) > 50 or int(rule["time"]) < 30):
  4669. return JsonErrorResponse(description=u"标准洗时间范围为30-50分钟")
  4670. if rule["name"] == u"特别烘干" and (int(rule["time"]) > 70 or int(rule["time"]) < 50):
  4671. return JsonErrorResponse(description=u"大物洗时间范围为50-70分钟")
  4672. if int(float(rule["coins"])) > 15 or int(float(rule["price"])) > 15:
  4673. return JsonErrorResponse(description=u"套餐价格不得大于15")
  4674. if 'id' in rule:
  4675. ruleId = rule['id']
  4676. else:
  4677. ruleId = list(set(range(1, 71)) - set([int(ruleId) for ruleId in washConfig.keys()]) - set(existIds))[0]
  4678. # TODO 需要统一类型.这里为云南霍博单独做
  4679. dealer = request.user # type: Dealer
  4680. if ('coins_be_float' not in agent.features) and (not dealer.supports('coins_be_float')):
  4681. if int(float(rule['coins'])) != float(rule['coins']):
  4682. return JsonErrorResponse(description=u'金币只能是整数')
  4683. washConfig[str(ruleId)] = {
  4684. 'name': rule['name'],
  4685. 'coins': int(float(rule['coins'])),
  4686. 'price': float(rule['price']),
  4687. 'time': float(rule.get('time', 0)),
  4688. 'description': rule.get('description', ''),
  4689. 'imgList': rule.get('imgList', []),
  4690. 'unit': rule.get('unit', u'分钟'),
  4691. 'switch': rule.get('switch', True),
  4692. 'sn': rule.get('sn'),
  4693. }
  4694. else:
  4695. washConfig[str(ruleId)] = {
  4696. 'name': rule['name'],
  4697. 'coins': float(rule['coins']),
  4698. 'price': float(rule['price']),
  4699. 'time': float(rule.get('time', 0)),
  4700. 'description': rule.get('description', ''),
  4701. 'imgList': rule.get('imgList', []),
  4702. 'unit': rule.get('unit', u'分钟'),
  4703. 'switch': rule.get('switch', True),
  4704. 'sn': rule.get('sn'),
  4705. }
  4706. if rule.get('pulse'):
  4707. washConfig[str(ruleId)].update({
  4708. 'pulse': rule.get('pulse'),
  4709. })
  4710. if rule.get('basePrice'):
  4711. washConfig[str(ruleId)].update({
  4712. 'basePrice': rule.get('basePrice'),
  4713. })
  4714. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  4715. washConfig[str(ruleId)].update({
  4716. 'billingMethod': rule['billingMethod'],
  4717. })
  4718. if rule.get('autoStop') != None:
  4719. washConfig[str(ruleId)].update({
  4720. 'basePrice': rule.get('basePrice'),
  4721. })
  4722. if rule.get('autoRefund') != None:
  4723. washConfig[str(ruleId)].update({
  4724. 'basePrice': rule.get('basePrice'),
  4725. })
  4726. if typeCode in [Const.DEVICE_TYPE_CODE_WASHER_CY_HS, Const.DEVICE_TYPE_CODE_WASHER_CY_HS_YUCHUAN, Const.DEVICE_TYPE_CODE_WASHER_CY_HS_HONGGAN]:
  4727. if len(serviceList) != 4:
  4728. return JsonErrorResponse(description=u'请勿增加或删除套餐')
  4729. # 如果设备直接可以下发套餐信息到设备,直接到设备上修改。比如串口洗衣机、串口的充电设备等
  4730. for devNo, dev in devDict.items():
  4731. if dev['devType']['code'] == Const.DEVICE_TYPE_CODE_WASHER:
  4732. smartBox = dev.deviceAdapter # type: WasherBox
  4733. try:
  4734. curConfig = smartBox.get_wash_config()
  4735. except ServiceException, e:
  4736. logger.exception('get washconfig to device=%s error=%s' % (devNo, e))
  4737. return JsonErrorResponse(description=u'读取设备套餐信息遇到错误:%s,请稍候再试试哦' % (e.result.get('description')))
  4738. try:
  4739. curConfig.update(setConfig)
  4740. smartBox.set_wash_config(curConfig)
  4741. except ServiceException, e:
  4742. logger.exception('set washconfig to device=%s error=%s' % (devNo, e))
  4743. return JsonErrorResponse(description=u'保存套餐到设备遇到错误:%s,请稍候再试试哦' % (e.result.get('description')))
  4744. if dev['devType']['code'] == Const.DEVICE_TYPE_CODE_HUITENG:
  4745. smartBox = dev.deviceAdapter # type: washerHTBox
  4746. cmdFlagDict = {u'单脱水': {'coins': '01', 'time': '09', 'baseTime': 5},
  4747. u'快速洗': {'coins': '02', 'time': '08', 'baseTime': 20},
  4748. u'标准洗': {'coins': '03', 'time': '07', 'baseTime': 35},
  4749. u'大物洗': {'coins': '04', 'time': '06', 'baseTime': 45}}
  4750. oldConfig = dev['washConfig']
  4751. for ruleId, rule in oldConfig.items():
  4752. try:
  4753. newRule = washConfig.get(ruleId)
  4754. if newRule['coins'] != rule['coins']:
  4755. smartBox.set_normal_value(cmdFlagDict[newRule['name']]['coins'], newRule['coins'])
  4756. if newRule['time'] != rule['time']:
  4757. baseTime = cmdFlagDict[newRule['name']]['baseTime']
  4758. if newRule['time'] < baseTime:
  4759. return JsonErrorResponse(description=u'您设置的套餐%s时间%s分钟,不能低于基础时间%s分钟' % (
  4760. newRule['name'], newRule['time'], baseTime))
  4761. addTime = newRule['time'] - baseTime
  4762. smartBox.set_normal_value(cmdFlagDict[newRule['name']]['time'], addTime)
  4763. except ServiceException, e:
  4764. return JsonErrorResponse(description=u'保存套餐到设备遇到错误:%s,请重试哦' % (e.result.get('description')))
  4765. if dev['devType']['code'] in [Const.DEVICE_TYPE_CODE_WASHER_CY_HS, Const.DEVICE_TYPE_CODE_WASHER_CY_HS_YUCHUAN]:
  4766. box = dev.deviceAdapter
  4767. washPriceMap = {
  4768. u"单脱水": "priceDt",
  4769. u"快速洗": "priceKs",
  4770. u"标准洗": "priceBz",
  4771. u"大物洗": "priceDw"
  4772. }
  4773. washTimeMap = {
  4774. u"单脱水": "timeDt",
  4775. u"快速洗": "timeKs",
  4776. u"标准洗": "timeBz",
  4777. u"大物洗": "timeDw"
  4778. }
  4779. priceData = {}
  4780. timeData = {}
  4781. for _, c in washConfig.items():
  4782. try:
  4783. priceData[washPriceMap.get(c.get("name"))] = c.get("coins")
  4784. timeData[washTimeMap.get(c.get("name"))] = c.get("time")
  4785. except Exception as e:
  4786. break
  4787. else:
  4788. try:
  4789. box.set_config_82(priceData)
  4790. box.set_config_83(timeData)
  4791. except ServiceException, e:
  4792. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  4793. # 烘干机
  4794. if dev['devType']['code'] == Const.DEVICE_TYPE_CODE_WASHER_CY_HS_HONGGAN:
  4795. box = dev.deviceAdapter
  4796. hongganPriceMap = {
  4797. u"加时烘干": "priceDt",
  4798. u"快速烘干": "priceKs",
  4799. u"标准烘干": "priceBz",
  4800. u"特别烘干": "priceDw"
  4801. }
  4802. hongganTimeMap = {
  4803. u"加时烘干": "timeDt",
  4804. u"快速烘干": "timeKs",
  4805. u"标准烘干": "timeBz",
  4806. u"特别烘干": "timeDw"
  4807. }
  4808. priceData = {}
  4809. timeData = {}
  4810. for _, c in washConfig.items():
  4811. try:
  4812. priceData[hongganPriceMap.get(c.get("name"))] = c.get("coins")
  4813. timeData[hongganTimeMap.get(c.get("name"))] = c.get("time")
  4814. except Exception as e:
  4815. break
  4816. else:
  4817. try:
  4818. box.set_config_82(priceData)
  4819. box.set_config_83(timeData)
  4820. except ServiceException, e:
  4821. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  4822. try:
  4823. dev['washConfig'] = washConfig
  4824. otherConf = dev.get('otherConf', {})
  4825. otherConf['displaySwitchs'] = displaySwitchs
  4826. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'washConfig': dev['washConfig'], 'otherConf':otherConf}})
  4827. request.user.defaultWashConfig[dev['devType']['id']] = dev['washConfig'].values()
  4828. request.user.save()
  4829. Device.invalid_device_cache(devNo)
  4830. except ServiceException, e:
  4831. logger.exception('update device washconfig error=%s,devNo=%s,washConfig=%s'
  4832. % (e, devNo, dev['washConfig']))
  4833. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  4834. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  4835. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'设置默认组失败'))
  4836. @permission_required(ROLE.dealer, ROLE.subaccount)
  4837. def setDefaultGroup(request):
  4838. ownerId = str(request.user.bossId)
  4839. groupId = request.POST.get('groupId', None)
  4840. if groupId is None:
  4841. return JsonErrorResponse(description=u"缺少参数")
  4842. try:
  4843. success, description, group = Group.update_group(group_id=groupId, isDefault=True)
  4844. return JsonOkResponse() if success else JsonErrorResponse(description=description)
  4845. except Exception, e:
  4846. logger.exception('update error=%s' % e)
  4847. return JsonResponse({'result': 0, 'description': u"系统繁忙,请稍后再试", 'payload': {}})
  4848. @permission_required(ROLE.dealer, ROLE.subaccount)
  4849. def logout(request):
  4850. agentId = request.user.agentId
  4851. auth.logout(request)
  4852. response = JsonResponse({'result': 1, 'payload': agentId})
  4853. # 删除不在使用的COOKIE
  4854. response.delete_cookie(key='hasagent')
  4855. return response
  4856. @permission_required(ROLE.dealer, ROLE.subaccount)
  4857. def wxconfig(request):
  4858. url = request.GET.get('href')
  4859. if not url:
  4860. return JsonResponse({'result': 0, 'description': u'参数错误', 'payload': {}})
  4861. value = get_wx_config(request.user, url)
  4862. logger.exception('wx config url = %s' % url)
  4863. return JsonResponse({'result': 1, 'description': None, 'payload': {'wxconfig': value}})
  4864. @require_GET
  4865. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取库存详情失败'))
  4866. @permission_required(ROLE.dealer, ROLE.subaccount)
  4867. def stockDetails(request):
  4868. logicalCode = request.GET.get('logicalCode')
  4869. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  4870. dev = Device.get_dev(devNo)
  4871. if not dev:
  4872. return JsonErrorResponse(description=u'找不到设备')
  4873. return JsonResponse({'result': 1, "description": None, "payload": {"quantity": dev['quantity']}})
  4874. @require_POST
  4875. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'更新库存失败,请重试'))
  4876. @permission_required(ROLE.dealer, ROLE.subaccount)
  4877. def updateStockQuantity(request):
  4878. payload = json.loads(request.body)
  4879. lc = payload.get('logicalCode')
  4880. quantity = int(payload.get('quantity', 0))
  4881. devNo = Device.get_devNo_by_logicalCode(lc)
  4882. dev = Device.get_dev(devNo)
  4883. if dev['quantity'] > quantity:
  4884. stockType = 'remove'
  4885. stockNum = dev['quantity'] - quantity
  4886. else:
  4887. stockType = 'add'
  4888. stockNum = quantity - dev['quantity']
  4889. result = Device.update_field(dev_no=devNo, update=True, quantity=quantity, consumptionQuantity=0)
  4890. if not result:
  4891. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  4892. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  4893. StockRecord.get_collection().insert(
  4894. {'logicCode': lc, 'imei': dev['devNo'], 'stockType': stockType, 'stockTime': stockTime, 'number': stockNum})
  4895. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  4896. @permission_required(ROLE.dealer, ROLE.subaccount)
  4897. def getStockRecord(request):
  4898. lc = request.GET.get('logicalCode')
  4899. if not lc:
  4900. return JsonResponse({'result': 0, 'description': u'未接收到设备编码,请刷新重试', 'payload': {}})
  4901. pageIndex = int(request.GET.get('pageIndex', 1))
  4902. pageSize = int(request.GET.get('pageSize', 10))
  4903. startTime = defaultTodayDate(request.GET.get('startTime', None)) + ' ' + '00:00:00'
  4904. endTime = defaultTodayDate(request.GET.get('endTime', None)) + ' ' + '23:59:59'
  4905. rcds = StockRecord.get_collection().find({'logicCode': lc, 'stockTime': {'$gte': startTime, '$lte': endTime}}).sort(
  4906. 'stockTime', -1)
  4907. add, cost = 0, 0
  4908. sIndex = (pageIndex - 1) * pageSize
  4909. eIndex = pageIndex * pageSize
  4910. ii = 0
  4911. dataList = []
  4912. for rcd in rcds:
  4913. name = ''
  4914. if rcd['stockType'] == 'add':
  4915. add += rcd['number']
  4916. name = u'增加库存 ' + rcd.get('more', '')
  4917. elif rcd['stockType'] == 'remove':
  4918. cost += rcd['number']
  4919. name = u'减少库存 ' + rcd.get('more', '')
  4920. elif rcd['stockType'] == 'consume':
  4921. cost += rcd['number']
  4922. name = u'用户购买 ' + rcd.get('more', '')
  4923. elif rcd['stockType'] == 'adFree':
  4924. cost += rcd['number']
  4925. name = u'吸粉发放 ' + rcd.get('more', '')
  4926. if sIndex <= ii < eIndex:
  4927. dataList.append({'name': name, 'time': rcd['stockTime'], 'number': rcd['number']})
  4928. ii += 1
  4929. devNo = Device.get_devNo_by_logicalCode(lc)
  4930. dev = Device.get_dev(devNo)
  4931. para = {'total': ii, 'add': add, 'cost': cost, 'quantity': dev['quantity'], 'dataList': dataList}
  4932. return JsonResponse({'result': 1, 'description': None, 'payload': para})
  4933. @permission_required(ROLE.dealer, ROLE.subaccount)
  4934. def toggleSwitches(request):
  4935. paraDict = json.loads(request.body) if request.body else {}
  4936. if not paraDict:
  4937. return JsonErrorResponse(description=u'接收数据为空,请重试')
  4938. ownerId = request.user.bossId # type: ObjectId
  4939. if paraDict.get("hasTempPackage", None) == True:
  4940. paraDict["displayTempPackage"] = True
  4941. success = Dealer.update_dealer(ownerId, **paraDict)
  4942. if not success:
  4943. return JsonErrorResponse(description=u'更新失败,请重试')
  4944. else:
  4945. return JsonOkResponse()
  4946. @permission_required(ROLE.dealer, ROLE.subaccount)
  4947. def clearDeviceStatistics(request):
  4948. lc = request.POST.get('logicalCode')
  4949. devNo = Device.get_devNo_by_logicalCode(lc)
  4950. dev = Device.get_dev(devNo)
  4951. if not dev:
  4952. return JsonErrorResponse(description=u'找不到设备')
  4953. if dev['ownerId'] != str(request.user.bossId):
  4954. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  4955. if dev.get('devType', {}).get('code', '') not in [Const.DEVICE_TYPE_CODE_WASHCAR_LSHB]:
  4956. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  4957. try:
  4958. smartBox = ActionDeviceBuilder.create_action_device(dev)
  4959. smartBox.clear_dev_feecount()
  4960. except ServiceException, e:
  4961. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  4962. return JsonResponse({'result': 1, 'description': u'', 'payload': {}})
  4963. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  4964. @permission_required(ROLE.dealer, ROLE.subaccount)
  4965. def getDeviceFunction(request):
  4966. payload = json.loads(request.body)
  4967. lc = payload.get("logicalCode")
  4968. if isinstance(lc, list) and len(lc):
  4969. lc = lc[0]
  4970. else:
  4971. raise JsonErrorResponse(description=u"无效的设备编号")
  4972. devNo = Device.get_devNo_by_logicalCode(lc)
  4973. dev = Device.get_dev(devNo)
  4974. if not dev:
  4975. return JsonResponse({'result': 0, 'description': u'未找到该设备', 'payload': {}})
  4976. try:
  4977. smartBox = ActionDeviceBuilder.create_action_device(dev)
  4978. setConf = smartBox.get_dev_setting()
  4979. if setConf is None:
  4980. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  4981. if len(payload.get("logicalCode")) > 1:
  4982. serviceCache.set('lastsettingConf_owner%s' % (str(request.user.id)), setConf, 600)
  4983. else:
  4984. caches['devmgr'].set('settingConf_%s' % (devNo,), setConf, 600)
  4985. return JsonResponse({'result': 1, 'description': u'', 'payload': setConf})
  4986. except ServiceException, e:
  4987. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  4988. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  4989. @permission_required(ROLE.dealer, ROLE.subaccount)
  4990. def getDeviceFunctionForIC(request):
  4991. payload = json.loads(request.body)
  4992. lc = payload.get("logicalCode")
  4993. if isinstance(lc, list) and len(lc):
  4994. lc = lc[0]
  4995. else:
  4996. raise JsonErrorResponse(description=u"无效的设备编号")
  4997. devNo = Device.get_devNo_by_logicalCode(lc)
  4998. dev = Device.get_dev(devNo)
  4999. if not dev:
  5000. return JsonResponse({'result': 0, 'description': u'未找到该设备', 'payload': {}})
  5001. try:
  5002. smartBox = ActionDeviceBuilder.create_action_device(dev)
  5003. setConf = smartBox.get_IC_card_password()
  5004. if setConf is None:
  5005. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  5006. caches['devmgr'].set('settingConf_%s' % (devNo,), setConf, 600)
  5007. return JsonResponse({'result': 1, 'description': u'', 'payload': setConf})
  5008. except ServiceException, e:
  5009. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  5010. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  5011. @permission_required(ROLE.dealer, ROLE.subaccount)
  5012. def setDeviceFunction(request):
  5013. # type: (WSGIRequest)->JsonResponse
  5014. payload = json.loads(request.body)
  5015. lc = payload.get("logicalCode")
  5016. if isinstance(lc, list) and len(lc):
  5017. lc = lc[0]
  5018. else:
  5019. raise JsonErrorResponse(description=u"无效的设备编号")
  5020. requestBody = RequestBodyDict({"POST": payload})
  5021. devNo = Device.get_devNo_by_logicalCode(lc)
  5022. dev = Device.get_dev(devNo)
  5023. if not dev:
  5024. return JsonErrorResponse(description=u'找不到设备')
  5025. if dev['ownerId'] != str(request.user.bossId):
  5026. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  5027. lastSetConf = caches['devmgr'].get('settingConf_%s' % (devNo,))
  5028. box = ActionDeviceBuilder.create_action_device(dev)
  5029. try:
  5030. box.set_device_function(requestBody, lastSetConf)
  5031. except ServiceException, e:
  5032. logger.exception('set info to device=%s error=%s' % (devNo, e))
  5033. return JsonResponse(
  5034. {'result': 0, 'description': u'设置参数遇到错误:%s' % (e.result.get('description', '')), 'payload': {}})
  5035. if lastSetConf is not None:
  5036. caches['devmgr'].set('settingConf_%s' % devNo, lastSetConf)
  5037. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  5038. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  5039. @permission_required(ROLE.dealer, ROLE.subaccount)
  5040. def setDeviceFunctionParam(request):
  5041. # type: (WSGIRequest)->JsonResponse
  5042. updateConf = json.loads(request.body)
  5043. logicalCodes = updateConf.pop('logicalCode')
  5044. # 替代品 先将 request 和 adapter的功能函数解耦 后续逐步修改
  5045. requestBody = RequestBodyDict({"POST": updateConf})
  5046. if len(logicalCodes) > 1:
  5047. setMode = updateConf.pop('modifyMode', None)
  5048. dev = Device.get_dev_by_l(logicalCodes[0])
  5049. dev_owner = dev.ownerId
  5050. dev_type_code = dev.devType.get('code')
  5051. for logicalCode in logicalCodes[1:]:
  5052. dev = Device.get_dev_by_l(logicalCode)
  5053. if dev_owner != dev.ownerId or dev_type_code != dev.devType.get('code'):
  5054. return JsonErrorResponse(description=u"设备经销商不同或者不同类型设备")
  5055. beforeConf = serviceCache.get('lastsettingConf_owner%s' % (str(request.user.id))) # type: Dict
  5056. if not beforeConf:
  5057. return JsonErrorResponse(description=u"查询当前配置信息失败")
  5058. if setMode == 'diff':
  5059. # 找出发生改变的参数项
  5060. for key, oldValue in beforeConf.iteritems():
  5061. if key in updateConf and str(updateConf[key]) == str(oldValue):
  5062. updateConf.pop(key)
  5063. if not updateConf:
  5064. return JsonErrorResponse(description=u"您没有修改任何参数")
  5065. payload = {'updateConf': updateConf, 'lastSetConf': None, 'logicalCodes': logicalCodes}
  5066. else:
  5067. payload = {'updateConf': updateConf, 'lastSetConf': beforeConf, 'logicalCodes': logicalCodes}
  5068. payload.update({
  5069. 'operationId': '{}_{}'.format(str(request.user.id), int(time.time()))
  5070. })
  5071. from taskmanager.mediator import task_caller
  5072. task_caller('batch_set_device_params', **payload)
  5073. serviceCache.set(payload['operationId'], payload, 600)
  5074. return JsonResponse({'result': 1, 'description': None, 'payload': {'operationId': payload['operationId']}})
  5075. else:
  5076. logicalCode = logicalCodes[0]
  5077. dealer = Dealer.objects(id=str(request.user.id)).first()
  5078. if dealer is None:
  5079. return JsonErrorResponse(description=u"设备的经销商不存在")
  5080. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  5081. dev = Device.get_dev(devNo)
  5082. if dev is None:
  5083. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  5084. if dev['ownerId'] != str(request.user.bossId):
  5085. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  5086. beforeConf = caches['devmgr'].get('settingConf_%s' % (devNo,))
  5087. if not beforeConf:
  5088. try:
  5089. beforeConf = dev.deviceAdapter.get_dev_setting()
  5090. if not beforeConf:
  5091. return JsonResponse({'result': 0, 'description': u'当前设备不支持该操作', 'payload': {}})
  5092. except Exception as e:
  5093. logger.exception(e)
  5094. return JsonResponse({'result': 0, 'description': u'查询设备当前配置信息失败', 'payload': {}})
  5095. operation = OperatorLog.record_dev_setting_changes_log(
  5096. dealer, 'record_someone_set_devSettings', dev['logicalCode'], dev['devType']['code'],
  5097. {
  5098. 'beforeCacheStr': json.dumps(beforeConf), 'afterCacheStr': json.dumps(updateConf)
  5099. }) # type: OperatorLog
  5100. try:
  5101. dev.deviceAdapter.set_device_function_param(requestBody, beforeConf)
  5102. operation.update(content__status='success')
  5103. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  5104. except ServiceException, e:
  5105. logger.info('error happened, error=%s' % (e,))
  5106. operation.update(content__status='fail', content_desc=e.result.get('description'))
  5107. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  5108. except InvalidParameter as e:
  5109. logger.exception(e)
  5110. operation.update(content__status='fail', content_desc=e.message)
  5111. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5112. except Exception, e:
  5113. operation.update(content__status='fail', content_desc=u'系统异常')
  5114. logger.exception('error happened, error=%s' % (e,))
  5115. return JsonResponse({'result': 0, 'description': u'系统异常,请检查输入参数,或者稍后重试', 'payload': {}})
  5116. @permission_required(ROLE.dealer, ROLE.subaccount)
  5117. def deviceParamsResult(request):
  5118. user = request.user
  5119. operationId = request.GET.get('operationId', None)
  5120. if not operationId:
  5121. return JsonResponse({'result': 1, 'description': None, 'payload': {}})
  5122. payload = serviceCache.get(operationId, {})
  5123. if not payload:
  5124. operations = OperatorLog.objects.filter(operatorId=str(user.id),
  5125. role=user.role,
  5126. content__operationId=operationId)
  5127. dataList = list(map(lambda operation: {'id': str(operation.id), 'logicalCode': operation.content['logicalCode'],
  5128. 'status': operation.content.get('status')}, operations))
  5129. else:
  5130. logicalCodes = payload.get('logicalCodes', [])
  5131. operations = OperatorLog.objects.filter(operatorId=str(user.id),
  5132. role=user.role,
  5133. content__logicalCode__in=logicalCodes,
  5134. content__operationId=operationId)
  5135. dataList = list(map(lambda operation: {'id': str(operation.id), 'logicalCode': operation.content['logicalCode'],
  5136. 'status': operation.content.get('status')}, operations))
  5137. if len(operations) != len(logicalCodes):
  5138. leftLogicalCodes = set(logicalCodes) - set(operations.values_list('logicalCode'))
  5139. for logicalCode in leftLogicalCodes:
  5140. dataList.append({'id': None, 'logicalCode': logicalCode, 'status': 'waiting'})
  5141. return JsonResponse({'result': 1, 'description': None, 'payload': {'dataList':dataList}})
  5142. @permission_required(ROLE.dealer, ROLE.subaccount)
  5143. def retryingSettingsDeviceParams(request):
  5144. dev_oper_id = request.GET.get('id')
  5145. operation = OperatorLog.objects.filter(id=dev_oper_id).first() # type: OperatorLog
  5146. logicalCode = operation.content['logicalCode']
  5147. dev = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  5148. if not dev:
  5149. return JsonResponse({'result': 0, 'description': u'该设备不存在', 'payload': {}})
  5150. if dev.ownerId != request.user.bossId:
  5151. return JsonResponse({'result': 0, 'description': u'您无权操作该设备', 'payload': {}})
  5152. try:
  5153. if operation.operatorName == 'record_someone_set_devSettings':
  5154. updateConf = json.loads(operation.content.get('updateConfStr'))
  5155. beforeCacheStr = json.loads(operation.content.get('beforeCacheStr'))
  5156. requestBody = RequestBodyDict({"POST": updateConf})
  5157. dev.deviceAdapter.set_device_function(requestBody, beforeCacheStr)
  5158. dev.deviceAdapter.set_device_function_param(requestBody, beforeCacheStr)
  5159. elif operation.operatorName == 'setServerSetting':
  5160. payload = json.loads(operation.content.get('after'))
  5161. dev.deviceAdapter.set_server_setting(payload)
  5162. except ServiceException, e:
  5163. logger.info('error happened, error=%s' % (e,))
  5164. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  5165. except InvalidParameter as e:
  5166. logger.exception(e)
  5167. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5168. else:
  5169. operation.update(content__status='success')
  5170. return JsonResponse({'result': 1, 'description': '重试成功', 'payload': {'status': 'success'}})
  5171. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取卡列表失败'))
  5172. @permission_required(ROLE.dealer, ROLE.subaccount)
  5173. def getUserCardList(request):
  5174. pageIndex = int(request.GET.get('pageIndex', 1))
  5175. pageSize = int(request.GET.get('pageSize', 10))
  5176. searchKey = str(request.GET.get('searchKey', ''))
  5177. userId = str(request.GET.get('userId', ''))
  5178. equipmentGroupId = str(request.GET.get('equipmentGroupId'))
  5179. frozen = request.GET.get("frozen", None)
  5180. dealerId = str(request.user.bossId)
  5181. queryDict = {
  5182. "dealerId": dealerId,
  5183. 'openId': userId or {'$exists': True}
  5184. }
  5185. if frozen:
  5186. queryDict.update({"frozen": bool(int(frozen))})
  5187. if searchKey:
  5188. queryDict.update(search_query(['cardName', 'phone', "cardNo"], searchKey).to_query(Card))
  5189. if equipmentGroupId:
  5190. queryDict.update({'groupId': equipmentGroupId})
  5191. cards = Card.objects.filter(__raw__=queryDict).skip((pageIndex - 1) * pageSize).limit(pageSize)
  5192. dataList = list()
  5193. for card in cards: # type: Card
  5194. dataList.append({
  5195. "cardName": card.cardName,
  5196. "phone": card.phone,
  5197. "groupId": card.groupId,
  5198. "groupName": card.group.groupName if card.group else "",
  5199. "cardId": str(card.id),
  5200. "bindStatus": card.isBinded,
  5201. "dealerId": card.dealerId,
  5202. "remarks": card.remarks,
  5203. "balance": card.balance,
  5204. "cardNo": card.cardNo,
  5205. "frozen": int(card.frozen)
  5206. })
  5207. payload = {
  5208. "total": get_paginate(dataList, pageSize=pageSize, pageIndex=pageIndex),
  5209. "dataList": dataList,
  5210. "agentId": request.user.agentId
  5211. }
  5212. return JsonResponse({"result": 1, "description": "", "payload": payload})
  5213. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取详情失败'))
  5214. @permission_required(ROLE.dealer, ROLE.subaccount)
  5215. def getUserCard(request):
  5216. cardId = request.GET.get("cardId", "")
  5217. try:
  5218. card = Card.objects.get(id=cardId)
  5219. except DoesNotExist:
  5220. return JsonErrorResponse(description=u"无效的卡")
  5221. except Exception as e:
  5222. logger.exception(e)
  5223. return JsonErrorResponse(description=u"获取卡详情失败,请刷新页面试试")
  5224. if card.dealerId != str(request.user.bossId):
  5225. return JsonErrorResponse(u"获取详情失败")
  5226. group = card.group
  5227. data = {
  5228. "cardId": cardId,
  5229. "cardNo": card.cardNo,
  5230. "cardName": card.cardName,
  5231. "groupId": card.groupId,
  5232. "dealerId": card.dealerId,
  5233. "groupName": group.groupName if group is not None else '',
  5234. "frozen": card.frozen,
  5235. "phone": card.phone,
  5236. "status": card.status,
  5237. "bindStatus": card.isBinded,
  5238. "balance": "{:.2f}".format(float(card.balance)),
  5239. "chargeBalance": "{:.2f}".format(float(card.chargeBalance)),
  5240. "bestowBalance": "{:.2f}".format(float(card.bestowBalance)),
  5241. "cardType": card.cardType
  5242. }
  5243. return JsonOkResponse(payload=data)
  5244. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"编辑卡失败"))
  5245. @permission_required(ROLE.dealer, ROLE.subaccount)
  5246. def editCard(request):
  5247. """
  5248. 经销商端 编辑卡片信息 可编辑内容 为 绑定设备组 卡名称 联系方式
  5249. :param request:
  5250. :return:
  5251. """
  5252. payload = json.loads(request.body)
  5253. cardId = payload.get("cardId")
  5254. cardName = payload.get("cardName")
  5255. phone = payload.get("phone")
  5256. groupId = payload.get("groupId")
  5257. try:
  5258. card = Card.objects.get(id=cardId)
  5259. except DoesNotExist:
  5260. return JsonErrorResponse(description=u"修改卡失败")
  5261. if phone and not PHONE_NUMBER_RE.match(phone):
  5262. return JsonErrorResponse(description=u"手机号码输入错误")
  5263. if cardName and not NAME_RE.match(cardName):
  5264. return JsonErrorResponse(description=u"请输入正确格式的名称(2-20位)")
  5265. if card.dealerId != str(request.user.bossId):
  5266. return JsonErrorResponse(description=u"不是您的卡片,无权修改")
  5267. group = Group.get_group(groupId)
  5268. if not group:
  5269. return JsonErrorResponse(description=u"请选择正确的设备组")
  5270. if group.get("ownerId") != str(request.user.bossId):
  5271. return JsonErrorResponse(description=u"请选择正确的设备组")
  5272. card.cardName = cardName
  5273. card.phone = phone
  5274. card.groupId = groupId
  5275. card.save()
  5276. return JsonOkResponse()
  5277. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"录卡失败"))
  5278. @permission_required(ROLE.dealer, ROLE.subaccount)
  5279. def saveEntityCard(request):
  5280. # type: (WSGIRequest)->JsonResponse
  5281. payload = json.loads(request.body)
  5282. cardNo = payload.get('cardNo', '')
  5283. phone = payload.get('phone', '')
  5284. cardName = payload.get('cardName', '')
  5285. groupId = payload.get("groupId", "")
  5286. dealerId = str(request.user.bossId)
  5287. # 卡号前置去0
  5288. if cardNo.isdigit():
  5289. cardNo = str(int(cardNo))
  5290. if not cardNo or not Card.check_card_no(cardNo):
  5291. return JsonErrorResponse(description=u"卡号不符合规则,请输入正确的卡号")
  5292. groupIds = Group.get_group_ids_of_dealer(dealerId)
  5293. if not groupId or groupId not in groupIds:
  5294. return JsonErrorResponse(description=u"请选择正确的设备组")
  5295. if phone and not PHONE_NUMBER_RE.match(phone):
  5296. return JsonErrorResponse(description=u"手机号码输入错误")
  5297. if cardName and not NAME_RE.match(cardName):
  5298. return JsonResponse({"result": 0, "description": u"请输入正确格式的名称(2-20位)"})
  5299. agentId = request.user.agentId
  5300. # 基于卡号找 代理商下的卡 或者平台下的卡
  5301. card = Card.objects.filter(Q(agentId=agentId) | Q(agentId=''), cardNo=cardNo).first()
  5302. if not card:
  5303. card = Card(
  5304. cardNo=cardNo,
  5305. dealerId=dealerId,
  5306. agentId=agentId,
  5307. cardName=cardName,
  5308. groupId=groupId,
  5309. phone=phone,
  5310. openId=Const.DEFAULT_CARD_OPENID
  5311. ).save()
  5312. return JsonResponse({"result": 1, "description": u"录入成功", "payload": {'cardId':str(card.id)}})
  5313. else:
  5314. if card.dealerId: # 有经销商注册
  5315. if card.dealerId == dealerId:
  5316. return JsonErrorResponse(description=u"{} 卡已经被您收录,请不要重复收录".format(cardNo))
  5317. else:
  5318. return JsonErrorResponse(description="{} 卡已被其他经销商录入,请确认卡号不要重复".format(cardNo))
  5319. else: # 此代理商平台下没有经销商注册该卡片
  5320. card.dealerId = dealerId
  5321. card.agentId = agentId
  5322. card.cardName = cardName
  5323. card.groupId = groupId
  5324. card.phone = phone
  5325. card.openId = Const.DEFAULT_CARD_OPENID
  5326. card.save()
  5327. return JsonResponse({"result": 1, "description": u"录入成功", "payload": {'cardId': str(card.id)}})
  5328. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"补卡失败"))
  5329. @permission_required(ROLE.dealer, ROLE.subaccount)
  5330. def swapCardNo(request):
  5331. """
  5332. 补卡 需要生成补卡记录,不重新创建新卡 如果新卡的卡号已经存在但是没有绑定用户并且内部没余额
  5333. :param request:
  5334. :return:
  5335. """
  5336. payload = json.loads(request.body)
  5337. cardNo = payload.get("cardNo", "")
  5338. cardId = payload.get("cardId")
  5339. dealerId = str(request.user.bossId)
  5340. # 卡号前置去0
  5341. if cardNo.isdigit():
  5342. cardNo = str(int(cardNo))
  5343. if not Card.check_card_no(cardNo):
  5344. return JsonErrorResponse(description=u"无效的卡号,卡号长度不能超过10位")
  5345. try:
  5346. oldCard = Card.objects.get(id=cardId)
  5347. except DoesNotExist:
  5348. return JsonErrorResponse(description=u"查询旧卡失败")
  5349. if oldCard.cardNo == cardNo:
  5350. return JsonErrorResponse(description=u"卡号一致无需修改")
  5351. if oldCard.dealerId != dealerId:
  5352. return JsonErrorResponse(description=u"无权编辑此卡")
  5353. checkStatus, checkMsg = Card.check_swap_card_no(cardNo, dealerId, oldCard.agentId)
  5354. if not checkStatus:
  5355. return JsonErrorResponse(description=checkMsg)
  5356. # 直接将卡号更新掉,然后新建一条换卡记录
  5357. oldCard.update(cardNo=cardNo)
  5358. SwapCardRecord.add_record(oldCard.cardNo, cardNo, oldCard.agentId, str(request.user.id))
  5359. return JsonOkResponse()
  5360. @record_operation_behavior()
  5361. @permission_required(ROLE.dealer, ROLE.subaccount)
  5362. def deleteInitCard(request):
  5363. cardId = json.loads(request.body).get("cardId")
  5364. card = Card.objects.filter(id=cardId, dealerId=str(request.user.bossId)).first()
  5365. if not card:
  5366. return JsonResponse({"result": 0, "description": u"未找到该实体卡", "payload": {}})
  5367. updated = card.clear_card()
  5368. if not updated:
  5369. return JsonErrorResponse(description=u'操作失败')
  5370. return JsonResponse({"result": 1, "description": u"删除成功", "payload": {}})
  5371. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取卡记录失败'))
  5372. @permission_required(ROLE.dealer, ROLE.subaccount)
  5373. def getUserCardRecord(request):
  5374. # type: (WSGIRequest)->JsonResponse
  5375. pageIndex = int(request.GET.get('pageIndex', 1))
  5376. pageSize = int(request.GET.get('pageSize', 10))
  5377. startTime = request.GET.get('startTime', 10)
  5378. endTime = request.GET.get('endTime', 10)
  5379. cardId = request.GET.get('cardId', None)
  5380. type = request.GET.get('type', None)
  5381. card = Card.objects.get(id=cardId)
  5382. if type == "chargeCard":
  5383. dataList = []
  5384. # TODO zjl 订单统一 不要这样搞得很别扭
  5385. viaMap = {
  5386. u"退币": "refund",
  5387. u"充值": "chargeCard"
  5388. }
  5389. for item in CardRechargeRecord.get_collection().find({
  5390. 'cardId': cardId,
  5391. 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5392. '$lte': to_datetime(endTime + " 23:59:59")}}).sort("dateTimeAdded", -1):
  5393. data = {
  5394. "cardId": str(item['_id']),
  5395. "cardNo": card.cardNo,
  5396. "via": viaMap.get(item.get("remarks"), "chargeCard"),
  5397. "amount": item['money'],
  5398. "coins": item.get('coins', item['money']),
  5399. "address": item['address'],
  5400. "groupName": item['groupName'],
  5401. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'),
  5402. "rechargeType": item.get("rechargeType")
  5403. }
  5404. if item.has_key('preBalance'):
  5405. data.update({'preBalance': item['preBalance']})
  5406. if item.has_key('balance'):
  5407. data.update({'balance': item['balance']})
  5408. if item.get("remarks", None):
  5409. data.update({'remarks': item['remarks']})
  5410. if item.get("logicalCode"):
  5411. data.update({"devType": Device.get_dev_by_logicalCode(item['logicalCode']).get("devType", dict()).get("name", "")})
  5412. data.update({"logicalCode": item['logicalCode']})
  5413. dataList.append(data)
  5414. elif type == "consume":
  5415. dataList = []
  5416. rcds = CardConsumeRecord.get_collection().find(
  5417. {'cardId': cardId, 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5418. '$lte': to_datetime(endTime + " 23:59:59")}}).sort(
  5419. "dateTimeAdded", -1)
  5420. for item in rcds:
  5421. newData = {
  5422. "cardId": str(item['_id']),
  5423. "cardNo": card.cardNo,
  5424. "via": "consume",
  5425. "devType": item['devType'],
  5426. "amount": item['money'],
  5427. "logicalCode": item['logicalCode'],
  5428. "address": item['address'],
  5429. "groupName": item['groupName'],
  5430. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S')
  5431. }
  5432. if item.has_key('balance'):
  5433. newData.update({'balance': item['balance']})
  5434. newData.update(item.get('servicedInfo', {}))
  5435. dataList.append(newData)
  5436. elif type == 'order':
  5437. dataList = []
  5438. for item in CardRechargeOrder.get_collection().find({
  5439. 'cardId': cardId,
  5440. 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5441. '$lte': to_datetime(endTime + " 23:59:59")}}).sort("dateTimeAdded", -1):
  5442. data = {
  5443. "via": "order",
  5444. "amount": item['money'],
  5445. "coins": item.get('coins', item['money']),
  5446. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'),
  5447. "status": u'等待用户刷卡充值' if item['status'] == 'finishedPay' else u'充值完成',
  5448. "desc": item['remarks'],
  5449. "rechargeType": item.get("rechargeType")
  5450. }
  5451. if item.has_key('preBalance'):
  5452. data.update({'preBalance': item['preBalance']})
  5453. if item.has_key('balance'):
  5454. data.update({'balance': item['balance']})
  5455. dataList.append(data)
  5456. elif type == 'cardConsume':
  5457. card = Card.objects.filter(id=cardId).first()
  5458. dataList = []
  5459. orders = ConsumeRecord.get_collection().find({
  5460. 'openId': str(card.openId),
  5461. 'dateTimeAdded': {'$gte': to_datetime(startTime + " 00:00:00"),
  5462. '$lte': to_datetime(endTime + " 23:59:59")}}).sort("dateTimeAdded", -1)
  5463. for item in orders:
  5464. data = {
  5465. "via": "consume",
  5466. "amount":item.get('coin', item['money']),
  5467. "createdTime": item['dateTimeAdded'].strftime('%Y-%m-%d %H:%M:%S'),
  5468. "orderNo":item.get('orderNo'),
  5469. "status": u'完成',
  5470. "desc": item['remarks']
  5471. }
  5472. dataList.append(data)
  5473. else:
  5474. return JsonResponse({"result": 0, "description": u"查询类型错误", "payload": {}})
  5475. return JsonResponse(
  5476. {
  5477. "result": 1,
  5478. "description": "",
  5479. "payload": {
  5480. "total": len(dataList),
  5481. "dataList": dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  5482. }
  5483. })
  5484. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  5485. @permission_required(ROLE.dealer, ROLE.subaccount)
  5486. def getDeviceFunctionByKey(request):
  5487. # type: (WSGIRequest)->JsonResponse
  5488. try:
  5489. payload = json.loads(request.body)
  5490. key = payload.get('key', None)
  5491. # 兼容真谷多
  5492. port = payload.get("portIndex", None)
  5493. if port is not None:
  5494. key = port
  5495. logicalCode = payload.get('logicalCode', None)
  5496. if isinstance(logicalCode, list) and len(logicalCode):
  5497. logicalCode = logicalCode[0]
  5498. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  5499. dev = Device.get_dev(devNo)
  5500. lastSetConf = caches['devmgr'].get('settingConf_%s' % (devNo,))
  5501. if not lastSetConf:
  5502. lastSetConf = {}
  5503. box = ActionDeviceBuilder.create_action_device(dev)
  5504. payload = box.get_device_function_by_key(key)
  5505. if payload is not None:
  5506. if lastSetConf is None:
  5507. lastSetConf = payload
  5508. else:
  5509. lastSetConf.update(payload)
  5510. caches['devmgr'].set('settingConf_%s' % (devNo,), lastSetConf, 600)
  5511. return JsonResponse({"result": 1, "description": "", "payload": payload})
  5512. except ServiceException, e:
  5513. return JsonResponse({"result": 0, "description": e.result.get('description', ''), "payload": {}})
  5514. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'设置错误'))
  5515. @permission_required(ROLE.dealer, ROLE.subaccount)
  5516. def setDeviceFunctionByKey(request):
  5517. # type: (WSGIRequest)->JsonResponse
  5518. payload = json.loads(request.body)
  5519. logicalCode = payload.get('logicalCode', None)
  5520. if isinstance(logicalCode, list) and len(logicalCode):
  5521. logicalCode = logicalCode[0]
  5522. else:
  5523. return JsonErrorResponse(description=u"错误的二维码编号")
  5524. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  5525. dev = Device.get_dev(devNo)
  5526. keyName = payload.get('key', None)
  5527. if keyName is None:
  5528. return JsonResponse({"result": 0, "description": u'没有按下任何控制键', "payload": {}})
  5529. try:
  5530. box = ActionDeviceBuilder.create_action_device(dev)
  5531. box.press_down_key(keyName)
  5532. return JsonResponse({"result": 1, "description": '', "payload": {}})
  5533. except ServiceException, e:
  5534. logger.exception('cannot setDeviceFunctionByKey, error=%s' % (e.result.get('description', '').encode('utf-8'),))
  5535. return JsonResponse({"result": 0, "description": e.result.get('description', ''), "payload": {}})
  5536. @error_tolerate(nil=DefaultJsonErrorResponse)
  5537. @permission_required(ROLE.dealer, ROLE.subaccount)
  5538. def wechatEntry(request):
  5539. # type: (WSGIRequest)->JsonResponse
  5540. """
  5541. 必须每次都进行鉴权
  5542. :param request:
  5543. :return:
  5544. """
  5545. current_user = request.user # type: Dealer
  5546. if not check_role(current_user, ROLE.dealer):
  5547. return ErrorResponseRedirect(error = u'权限错误')
  5548. entryType = request.GET.get('type')
  5549. if entryType not in ['simCard', 'apiQuota', 'disableAdQuota']:
  5550. return ErrorResponseRedirect(error = u'参数错误(10001)')
  5551. if entryType == 'simCard': # 流量卡充值
  5552. my_agent = Agent.get_inhouse_prime_agent()
  5553. app = get_app(my_agent, APP_TYPE.WECHAT_ENV_PAY, role = ROLE.dealer)
  5554. elif entryType == 'apiQuota': # api设备配额数量充值
  5555. my_agent = Agent.get_inhouse_prime_agent()
  5556. app = get_app(my_agent, APP_TYPE.WECHAT_ENV_PAY, role=ROLE.dealer)
  5557. elif entryType == 'disableAdQuota': # api设备配额数量充值
  5558. my_agent = Agent.get_inhouse_prime_agent()
  5559. app = get_app(my_agent, APP_TYPE.WECHAT_ENV_PAY, role=ROLE.dealer)
  5560. else:
  5561. return ErrorResponseRedirect(error=u'参数错误(10002)')
  5562. if isinstance(app, WechatPayApp):
  5563. auth_bridge = WechatAuthBridge(app) # type: WechatAuthBridge
  5564. else:
  5565. return ErrorResponseRedirect(error=u'参数错误(10003)')
  5566. auth_code = request.GET.get(auth_bridge.auth_code_key, None)
  5567. if auth_code:
  5568. openId = auth_bridge.authorize(auth_code)
  5569. if openId is not None:
  5570. redirect = base64.b64decode(request.GET.get('payload'))
  5571. redirect = add_query(redirect, {
  5572. 'openId': openId
  5573. })
  5574. return FrontEndResponseRedirect(redirect)
  5575. else:
  5576. return ErrorResponseRedirect(error=u'系统繁忙,请重试')
  5577. else:
  5578. redirect_url = concat_server_end_url(uri='/dealer/wechat/entry?type={}'.format(entryType))
  5579. return ExternalResponseRedirect(
  5580. auth_bridge.generate_auth_url_base_scope(
  5581. redirect_uri=redirect_url,
  5582. payload=base64.b64encode(request.GET.get('redirect'))))
  5583. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'冻结卡失败'))
  5584. @permission_required(ROLE.dealer, ROLE.subaccount)
  5585. def freezeCard(request):
  5586. # type: (WSGIRequest)->JsonResponse
  5587. payload = json.loads(request.body)
  5588. frozen = payload.get('frozen')
  5589. cardId = payload.get('id', '')
  5590. try:
  5591. card = Card.objects.get(id=cardId)
  5592. card.frozen = frozen
  5593. card.status = 'active'
  5594. card.save()
  5595. except Exception, e:
  5596. logger.exception(e.message)
  5597. return JsonResponse({"result": 0, "description": u'系统错误', "payload": {}})
  5598. return JsonResponse({"result": 1, "description": '', "payload": {}})
  5599. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误'))
  5600. @permission_required(ROLE.dealer, ROLE.subaccount)
  5601. def getWalletWithdrawInfo(request):
  5602. dealer = request.user # type: Dealer
  5603. if not is_dealer(dealer):
  5604. return ErrorResponseRedirect(error = u'子账号无提现权限')
  5605. source_key = request.GET.get('sourceId')
  5606. income_type = request.GET.get('sourceType')
  5607. phone = str(dealer.monitorPhone) if dealer.monitorPhone else str(dealer.username)
  5608. result = {
  5609. "result": 1,
  5610. "description": None,
  5611. 'payload': {
  5612. 'payOpenId': 'placeholder',
  5613. 'phone': phone,
  5614. 'balance': dealer.sub_balance(income_type, source_key),
  5615. 'withdrawFeeRatio': dealer.withdrawFeeRatio,
  5616. 'support': dealer.withdraw_support(source_key)
  5617. }
  5618. }
  5619. return JsonResponse(result)
  5620. @require_POST
  5621. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5622. @permission_required(ROLE.dealer, ROLE.subaccount)
  5623. def getFeatureList(request):
  5624. # type: (WSGIRequest)->JsonResponse
  5625. """
  5626. :param request:
  5627. :return:
  5628. """
  5629. currentUser = request.user # type: Dealer
  5630. payload = json.loads(request.body)
  5631. queryList = payload.get('list', [])
  5632. resultFeatures = currentUser.query_feature_by_list(queryList)
  5633. if 'blackListManage' in currentUser.features:
  5634. resultFeatures.update({'blackListManage': True})
  5635. return JsonOkResponse(payload=resultFeatures)
  5636. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5637. @permission_required(ROLE.dealer, ROLE.subaccount)
  5638. def getOnsaleTypeList(request):
  5639. # type: (WSGIRequest)->JsonResponse
  5640. dataList = []
  5641. for typeName, info in OnSale.onsaleTypeDict.items():
  5642. dataList.append(
  5643. {
  5644. 'typeName': typeName,
  5645. 'desc': info['desc'],
  5646. 'img': info['img']
  5647. }
  5648. )
  5649. return JsonResponse({'result': 1, 'description': '', 'payload': {'total': len(dataList), 'dataList': dataList}})
  5650. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5651. @permission_required(ROLE.dealer, ROLE.subaccount)
  5652. def getOnsaleList(request):
  5653. # type: (WSGIRequest)->JsonResponse
  5654. """
  5655. 列出所有 经销商的活动尚未删除的
  5656. :param request:
  5657. :return:
  5658. """
  5659. pageIndex = int(request.GET.get('pageIndex', 1))
  5660. pageSize = int(request.GET.get('pageSize', 10))
  5661. searchKey = request.GET.get('searchKey', None)
  5662. dealerId = str(request.user.bossId)
  5663. onsales = OnSale.objects.filter(dealerId=dealerId, name__startswith=searchKey).order_by("-id")
  5664. dataList = [_obj.to_dict() for _obj in onsales[(pageIndex - 1) * pageSize: pageIndex * pageSize]]
  5665. return JsonOkResponse(payload={"total": len(dataList), "dataList": dataList})
  5666. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5667. @permission_required(ROLE.dealer, ROLE.subaccount)
  5668. def createOnsale(request):
  5669. # type: (WSGIRequest)->JsonResponse
  5670. dealerId = str(request.user.bossId)
  5671. payload = json.loads(request.body) if request.body else {}
  5672. if not payload:
  5673. return JsonErrorResponse(description=u'传入数据为空')
  5674. payload['startTime'] = to_datetime(payload['startTime'] + ' 00:00:00')
  5675. payload['endTime'] = to_datetime(payload['endTime'] + ' 23:59:59')
  5676. onsale = OnSale(**payload)
  5677. name = onsale.name
  5678. # 检查活动的名称
  5679. count = OnSale.objects.filter(dealerId=dealerId, name=name).count()
  5680. if count > 0:
  5681. return JsonResponse({'result': 0, 'description': u'活动名称重复,优惠活动的名称必须唯一', 'payload': {}})
  5682. # 检查下该经销商是否符合资格配置该活动
  5683. if onsale.onsaleType == u"京东新人1分购":
  5684. dealer = Dealer.objects.get(id=dealerId)
  5685. if not dealer.isJosEnable():
  5686. return JsonResponse({"result": 0, "description": u"抱歉,您暂时无法配置此项活动,详情请咨询平台方"})
  5687. # 检查活动的设备类型是否匹配
  5688. onsaleType = onsale.onsaleType
  5689. expression = OnSale.onsaleTypeDict[onsaleType]['expression']
  5690. onsale.onClickUrl = OnSale.onsaleTypeDict[onsaleType]['onClickUrl']
  5691. onsale.showType = OnSale.onsaleTypeDict[onsaleType]['showType']
  5692. if expression:
  5693. for lc in onsale.logicalCodeList:
  5694. dev = Device.get_dev_by_logicalCode(lc)
  5695. if dev is None:
  5696. continue
  5697. if not eval(expression):
  5698. return JsonResponse({'result': 0, 'description': u'编码为:%s的设备类型不符合本次活动的要求,请去掉该设备哦' % lc, 'payload': {}})
  5699. onsale.dealerId = str(request.user.bossId)
  5700. onsale.save()
  5701. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  5702. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5703. @permission_required(ROLE.dealer, ROLE.subaccount)
  5704. def deleteOnsale(request):
  5705. # type: (WSGIRequest)->JsonResponse
  5706. payload = json.loads(request.body)
  5707. onsaleId = payload.get('id')
  5708. if not onsaleId:
  5709. return JsonErrorResponse(description=u'数据不完整,请刷新')
  5710. obj = OnSale.objects.get(id=onsaleId)
  5711. obj.delete()
  5712. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  5713. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,删除失败,请您重试'))
  5714. @permission_required(ROLE.dealer, ROLE.subaccount)
  5715. def editOnsale(request):
  5716. # type: (WSGIRequest)->JsonResponse
  5717. payload = json.loads(request.body) if request.body else {}
  5718. if not payload:
  5719. return JsonErrorResponse(description=u'发送的编辑数据为空')
  5720. payload['startTime'] = to_datetime(payload['startTime'] + ' 00:00:00')
  5721. payload['endTime'] = to_datetime(payload['endTime'] + ' 23:59:59')
  5722. obj = OnSale.objects.get(id=payload['id'])
  5723. obj.update(**payload)
  5724. return JsonResponse({'result': 1, 'description': '', 'payload': {}})
  5725. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请刷新'))
  5726. @permission_required(ROLE.dealer, ROLE.subaccount)
  5727. def getOnsaleRecord(request):
  5728. # type: (WSGIRequest)->JsonResponse
  5729. pageIndex = int(request.GET.get('pageIndex', 1))
  5730. pageSize = int(request.GET.get('pageSize', 10))
  5731. startTimeStr = request.GET.get('startTime', None)
  5732. if not startTimeStr:
  5733. return JsonErrorResponse(description=u'数据为空,请重试')
  5734. startTime = to_datetime(startTimeStr + ' 00:00:00')
  5735. endTimeStr = request.GET.get('endTime', 10)
  5736. endTime = to_datetime(endTimeStr + ' 23:59:59')
  5737. onsaleId = request.GET.get('onsaleId', None)
  5738. rcds = OnSaleRecord.objects.filter(onsaleId=onsaleId, addedTime__gte=startTime, addedTime__lte=endTime)
  5739. dataList = []
  5740. countDict = {}
  5741. for rcd in rcds:
  5742. data = {'clickTime': rcd.addedTime.strftime(Const.DATETIME_FMT)}
  5743. desc = u'用户:%s,' % rcd.nickName
  5744. if rcd.onsaleDetail.has_key('coins'):
  5745. desc += u' 领取%s个金币' % rcd.onsaleDetail['coins']
  5746. if rcd.onsaleDetail.has_key('duration'):
  5747. desc += u' 启动免费体验%s分钟' % rcd.onsaleDetail['duration']
  5748. if rcd.onsaleDetail.has_key('phoneNumber'):
  5749. desc += u' 手机号码:%s' % rcd.onsaleDetail['phoneNumber']
  5750. data['description'] = desc
  5751. data.update(rcd.onsaleDetail)
  5752. for k, v in rcd.onsaleDetail.items():
  5753. countKey = '%sTotal' % k
  5754. if countDict.has_key(countKey):
  5755. countDict[countKey] += v
  5756. else:
  5757. countDict[countKey] = v
  5758. dataList.append(data)
  5759. return JsonResponse(
  5760. {
  5761. 'result': 1,
  5762. 'description': '',
  5763. 'payload':
  5764. {
  5765. 'total': len(dataList),
  5766. 'dataList': dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize],
  5767. 'countDict': countDict
  5768. }
  5769. })
  5770. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'创意文件存储失败,请重新试试'))
  5771. @permission_required(ROLE.dealer, ROLE.subaccount)
  5772. def uploadCreative(request):
  5773. # type: (WSGIRequest)->JsonResponse
  5774. files = request.FILES.getlist('file')
  5775. if not len(files):
  5776. return JsonResponse({'result': 0, 'description': u'未找到上传的创意文件,请重新试试', 'payload': {}})
  5777. uploader = AliOssFileUploader(inputFile=request.FILES.getlist('file')[0], uploadType='creative')
  5778. logger.info('[uploadItemPic] %s is being used' % (repr(uploader),))
  5779. try:
  5780. outputUrl = uploader.upload()
  5781. return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl})
  5782. except InvalidFileSize, e:
  5783. logger.info(
  5784. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  5785. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5786. except InvalidFileName, e:
  5787. logger.info(
  5788. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  5789. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  5790. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'状态更新错误,请刷新页面重新试试'))
  5791. @permission_required(ROLE.dealer, ROLE.subaccount)
  5792. def toggleOnsale(request):
  5793. # type: (WSGIRequest)->JsonResponse
  5794. payload = json.loads(request.body)
  5795. status = payload.get('status')
  5796. onsaleId = payload.get('id')
  5797. onsale = OnSale.objects.get(id=onsaleId)
  5798. onsale.status = status
  5799. onsale.save()
  5800. return JsonResponse({'result': 1, 'description': '', 'payload': ''})
  5801. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取价格失败,请刷新页面重新试试'))
  5802. @permission_required(ROLE.dealer, ROLE.subaccount)
  5803. def getPricePerHour(request):
  5804. # type: (WSGIRequest)->JsonResponse
  5805. lc = request.GET.get('logicalCode')
  5806. dev = Device.objects.get(logicalCode=lc)
  5807. return JsonResponse({'result': 1, 'description': '', 'payload': dev.otherConf.get('pricePerHour', 2.0)})
  5808. @permission_required(ROLE.dealer, ROLE.subaccount)
  5809. def setBatchDevsSwitch(request):
  5810. # type: (WSGIRequest)->JsonResponse
  5811. data = json.loads(request.body) if request.body else {}
  5812. if not data:
  5813. return JsonErrorResponse(u'数据为空,请重试')
  5814. lcs = data['logicalCodes']
  5815. isFault = data['isFault']
  5816. objs = Device.objects.filter(devNo__in=lcs)
  5817. for obj in objs:
  5818. dev = Device.get_dev(obj.devNo)
  5819. obj.isFault = isFault
  5820. try:
  5821. box = ActionDeviceBuilder.create_action_device(dev)
  5822. box.set_dev_fault(isFault)
  5823. obj.save()
  5824. Device.invalid_device_cache(obj.devNo)
  5825. except Exception as e:
  5826. logger.exception(e)
  5827. continue
  5828. return JsonResponse({"result": 1, "description": "", "payload": {}})
  5829. # 批量设置退费保护时间
  5830. @permission_required(ROLE.dealer, ROLE.subaccount)
  5831. def setBatchRefundProtectionTime(request):
  5832. # type: (WSGIRequest)->JsonResponse
  5833. data = json.loads(request.body) if request.body else {}
  5834. if not data:
  5835. return JsonErrorResponse(u'数据为空,请重试')
  5836. lcs = data['logicalCodes']
  5837. refundProtectionTime = data['refundProtectionTime']
  5838. try:
  5839. Device.objects.filter(devNo__in=lcs).update(refundProtectionTime=refundProtectionTime).select_for_update()
  5840. except Exception as e:
  5841. logger.exception(e)
  5842. @permission_required(ROLE.dealer, ROLE.subaccount)
  5843. def getCardTicketTypeList(request):
  5844. # type: (WSGIRequest)->JsonResponse
  5845. objs = VirtualCard.objects.filter(ownerId=str(request.user.bossId))
  5846. dataList = []
  5847. for obj in objs:
  5848. # if '*' in obj.groupIDs:
  5849. # groupIds = Group.get_group_ids_of_dealer(str(request.user.id))
  5850. # else:
  5851. # groupIds = obj.groupIds
  5852. data = {
  5853. 'cardName': obj.cardName,
  5854. 'price': obj.price,
  5855. 'groupIds': obj.groupIds,
  5856. 'periodDays': obj.periodDays,
  5857. 'expiredTime': obj.expiredTime.strftime('%Y-%m-%d'),
  5858. 'dayQuota': obj.dayQuota,
  5859. 'quota': obj.quota,
  5860. 'userLimit': obj.userLimit,
  5861. 'userDesc': obj.userDesc,
  5862. 'dealerDesc': obj.dealerDesc
  5863. }
  5864. dataList.append(data)
  5865. return JsonResponse({"result": 1, "description": '', "payload": {'datalist': dataList}})
  5866. @error_tolerate(nil=JsonErrorResponse(u"获取虚拟卡列表失败"))
  5867. @permission_required(ROLE.dealer, ROLE.subaccount)
  5868. def getCardTicketList(request):
  5869. """
  5870. 经销商 优惠卡卷列表
  5871. 可通过卡名称搜索
  5872. 可通过 售卡状态 卡使用地址进行筛选
  5873. :param request:
  5874. :return:
  5875. """
  5876. pageIndex = int(request.GET.get('pageIndex', 1))
  5877. pageSize = int(request.GET.get('pageSize', 10))
  5878. status = request.GET.get("status") # 卡状态
  5879. groupId = request.GET.get("groupId") # 地址ID
  5880. searchKey = request.GET.get("searchKey") # 卡名称
  5881. # 没有传递状态 则是全部的可用状态
  5882. statusList = [int(status)] if status else [0, 1]
  5883. filters = {"ownerId": str(request.user.bossId), "status__in": statusList}
  5884. # 传递了地址的情况 则全选地址的 和单独选择的都要算上
  5885. if groupId:
  5886. filters.update({"groupIds__in": ["*", groupId]})
  5887. objs = VirtualCard.objects.filter(**filters)
  5888. if searchKey:
  5889. objs = objs.search(searchKey, ["cardName"])
  5890. total = objs.count()
  5891. dataList = []
  5892. for obj in objs.skip((pageIndex - 1) * pageSize).limit(pageSize):
  5893. dataList.append(obj.to_dict())
  5894. return JsonResponse({"result": 1, "description": '', "payload": {'total': total, 'pageSize': pageSize, 'dataList': dataList}})
  5895. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'添加失败,请重新试试'))
  5896. @permission_required(ROLE.dealer, ROLE.subaccount)
  5897. def addTicketCard(request):
  5898. def sort_quota(qArray): # type:(list) -> list
  5899. # 首先检查单位是否重复 对于重复的单位叠加处理
  5900. qDict = defaultdict(int)
  5901. for _item in qArray:
  5902. _count, _unit = _item["count"], _item["unit"]
  5903. qDict[_unit] += int(_count)
  5904. if len(qDict) != len(qArray):
  5905. raise ServiceException({"result": 2, "description": u"额度设置错误,额度单位重复"})
  5906. return sorted(qArray, key=lambda x: x["unit"])
  5907. if not request.body:
  5908. return JsonErrorResponse(description=u'传入数据为空')
  5909. payload = json.loads(request.body)
  5910. cardId = payload.get("cardId")
  5911. cardName = payload["cardName"]
  5912. userDesc = payload["userDesc"]
  5913. userLimit = int(payload["userLimit"])
  5914. periodDays = float(payload["periodDays"])
  5915. try:
  5916. expiredTime = to_datetime(payload['expiredTime'] + ' 23:59:59')
  5917. except Exception as e:
  5918. expiredTime = to_datetime(payload['expiredTime'])
  5919. devTypeList = payload["devTypeList"]
  5920. groups = ['*'] if payload['groups'] == '*' else [grp['groupId'] for grp in payload['groups']]
  5921. price = RMB(payload["price"])
  5922. power = int(payload["power"])
  5923. try:
  5924. dayQuota = sort_quota(payload["dayQuota"])
  5925. quota = sort_quota(payload["quota"])
  5926. except ServiceException as e:
  5927. return JsonErrorResponse(description=e.result["description"])
  5928. if cardId:
  5929. try:
  5930. card = VirtualCard.objects.get(id=cardId)
  5931. except DoesNotExist:
  5932. return JsonErrorResponse(description=u"编辑虚拟卡卷失败")
  5933. if card.ownerId != str(request.user.bossId):
  5934. return JsonErrorResponse(description=u"保存失败,请重新尝试")
  5935. else:
  5936. card = VirtualCard()
  5937. card.update(
  5938. cardName=cardName, userDesc=userDesc, userLimit=userLimit, periodDays=periodDays,
  5939. expiredTime=expiredTime, devTypeList=devTypeList, groupIds=groups, price=price,
  5940. power=power, dayQuota=dayQuota, quota=quota, ownerId=str(request.user.bossId),
  5941. upsert=True
  5942. )
  5943. return JsonOkResponse()
  5944. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除失败,请重新试试'))
  5945. @permission_required(ROLE.dealer, ROLE.subaccount)
  5946. def deleteCardTicket(request):
  5947. # type: (WSGIRequest)->JsonResponse
  5948. if not request.body: return JsonErrorResponse(description=u'传入数据为空')
  5949. payload = json.loads(request.body)
  5950. cardId = payload['id']
  5951. try:
  5952. VirtualCard.get_collection().update({'_id': ObjectId(cardId)}, {'$set': {'status':-1}})
  5953. return JsonResponse({"result": 1, "description": "", "payload": {}})
  5954. except Exception as e:
  5955. logger.exception('update error=%s' % e)
  5956. return JsonResponse({"result": 0, "description": u"删除失败,请您稍后重试", "payload": {}})
  5957. @permission_required(ROLE.dealer, ROLE.subaccount)
  5958. def switchCardTicket(request):
  5959. # type: (WSGIRequest)->JsonResponse
  5960. if not request.body: return JsonErrorResponse(description=u'传入数据为空')
  5961. payload = json.loads(request.body)
  5962. cardId = payload['id']
  5963. try:
  5964. vCard = VirtualCard.objects.get(id=cardId)
  5965. vCard.status = 1 if vCard.status == 0 else 0
  5966. vCard.save()
  5967. return JsonResponse({"result": 1, "description": "", "payload": {}})
  5968. except Exception as e:
  5969. logger.exception('switchCardTicket error=%s' % e)
  5970. return JsonResponse({"result": 0, "description": u"切换虚拟卡的状态失败,请您刷新页面后重试", "payload": {}})
  5971. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除失败,请重新试试'))
  5972. @permission_required(ROLE.dealer, ROLE.subaccount)
  5973. def delUserVirtualCard(request):
  5974. payload = json.loads(request.body)
  5975. cardId = payload.get("cardId")
  5976. if not cardId:
  5977. return JsonErrorResponse(description=u"该虚拟卡不存在")
  5978. try:
  5979. vCard = UserVirtualCard.objects.get(id=cardId)
  5980. except DoesNotExist:
  5981. return JsonErrorResponse(description=u"该虚拟卡不存在")
  5982. if vCard.dealerId != str(request.user.id):
  5983. return JsonErrorResponse(u"不是您的虚拟卡,无权删除")
  5984. record = AdjustUserVirtualCardRecord(
  5985. cardId=cardId,
  5986. cardNo=vCard.cardNo,
  5987. beforeAdjust=vCard.expiredTime,
  5988. operator=str(request.user.id),
  5989. dealerId=str(request.user.bossId),
  5990. adjustType=TYPE_ADJUST_USER_VIRTUAL_CARD.DELETE,
  5991. oldQuota=vCard.quota,
  5992. adjustQuota=[{"count": 0, "unit": vCard.quota[0].get("unit")}]
  5993. )
  5994. vCard.delete()
  5995. record.save()
  5996. return JsonOkResponse(description=u"删除成功")
  5997. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'调整失败,请重新试试'))
  5998. @permission_required(ROLE.dealer, ROLE.subaccount)
  5999. def adjustUserVirtualCardTime(request):
  6000. payload = json.loads(request.body)
  6001. cardId = payload.get("cardId", "")
  6002. days = int(payload.get("days", 0))
  6003. if not days:
  6004. return JsonErrorResponse(description=u"您调整的时间没有变化")
  6005. if not cardId:
  6006. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6007. try:
  6008. vCard = UserVirtualCard.objects.get(id=cardId)
  6009. except DoesNotExist:
  6010. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6011. if vCard.dealerId != str(request.user.id):
  6012. return JsonErrorResponse(u"不是您的虚拟卡,无权修改")
  6013. record = AdjustUserVirtualCardRecord(
  6014. cardId=cardId,
  6015. cardNo=vCard.cardNo,
  6016. beforeAdjust=vCard.expiredTime,
  6017. operator=str(request.user.id),
  6018. dealerId=str(request.user.bossId),
  6019. adjustType=TYPE_ADJUST_USER_VIRTUAL_CARD.ADJUST_DAYS,
  6020. adjustDays=days,
  6021. oldQuota=vCard.quota,
  6022. adjustQuota=[{"count": 0, "unit": vCard.quota[0].get("unit")}]
  6023. )
  6024. vCard.expiredTime = vCard.expiredTime + datetime.timedelta(days=days)
  6025. vCard.save()
  6026. record.save()
  6027. return JsonOkResponse(description=u"操作成功,虚拟卡{}过期调整过期时间{}天".format(str(vCard.id), days))
  6028. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'调整失败,请重新试试'))
  6029. @permission_required(ROLE.dealer, ROLE.subaccount)
  6030. def adjustUserVirtualCardQuota(request):
  6031. """
  6032. 调整虚拟卡额度
  6033. :param request:
  6034. :return:
  6035. """
  6036. payload = json.loads(request.body)
  6037. cardId = payload.get("cardId", "")
  6038. quota = payload.get("quota")
  6039. dayQuota = payload.get("dayQuota")
  6040. if not cardId:
  6041. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6042. if not all([quota, dayQuota]):
  6043. return JsonErrorResponse(description="参数不全")
  6044. try:
  6045. vCard = UserVirtualCard.objects.get(id=cardId)
  6046. except DoesNotExist:
  6047. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6048. vCard.quota = quota
  6049. vCard.dayQuota = dayQuota
  6050. for _item in vCard.quota:
  6051. _item["count"] = float(_item["count"])
  6052. for _item in vCard.dayQuota:
  6053. _item["count"] = float(_item["count"])
  6054. vCard.save()
  6055. return JsonOkResponse(description=u"操作成功,虚拟卡{}调整额度成功")
  6056. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"调整失败,请重新试试"))
  6057. @permission_required(ROLE.dealer, ROLE.subaccount)
  6058. def adjustUserVirtualState(request):
  6059. """
  6060. 修改虚拟卡 的状态 主要是冻结/非冻结 霍珀需求
  6061. 这个操作状态就不放入调整记录了
  6062. :param request:
  6063. :return:
  6064. """
  6065. payload = json.loads(request.body)
  6066. cardId = payload.get("id", "")
  6067. if not cardId:
  6068. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6069. try:
  6070. vCard = UserVirtualCard.objects.get(id=cardId)
  6071. except DoesNotExist:
  6072. return JsonErrorResponse(description=u"该虚拟卡不存在")
  6073. if vCard.status in ["normal", "warning"]:
  6074. vCard.status = "frozen"
  6075. else:
  6076. vCard.status = "normal"
  6077. vCard.save()
  6078. return JsonOkResponse(description=u"操作成功")
  6079. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'读取失败,请重新试试'))
  6080. @permission_required(ROLE.dealer, ROLE.subaccount)
  6081. def userVirtualCardAdjustRecord(request):
  6082. pageIndex = int(request.GET.get("pageIndex", 1))
  6083. pageSize = int(request.GET.get("pageSize", 10))
  6084. searchKey = request.GET.get("searchKey")
  6085. _type = request.GET.get("type")
  6086. startTime = request.GET.get("startTime")
  6087. endTime = request.GET.get("endTime")
  6088. matchFilters = {"dealerId": str(request.user.bossId)}
  6089. if _type:
  6090. if _type not in Const.TYPE_ADJUST_USER_VIRTUAL_CARD.choices():
  6091. return JsonErrorResponse(description=u"筛选种类错误,无此相关记录")
  6092. else:
  6093. matchFilters.update({"adjustType": _type})
  6094. if startTime:
  6095. startDataTime = to_datetime(startTime + ' 00:00:00', "%Y-%m-%d %H:%M:%S")
  6096. now = datetime.datetime.now()
  6097. if not endTime:
  6098. endDateTime = now + datetime.timedelta(days=1)
  6099. else:
  6100. endDateTime = to_datetime(endTime, "%Y-%m-%d")
  6101. if endDateTime > now:
  6102. endDateTime = now
  6103. endDateTime = endDateTime + datetime.timedelta(days=1)
  6104. if startDataTime >= endDateTime:
  6105. endDateTime = startDataTime + datetime.timedelta(days=1)
  6106. matchFilters.update(
  6107. {
  6108. "dateTimeAdded": {
  6109. "$gte": startDataTime,
  6110. "$lte": endDateTime
  6111. }
  6112. }
  6113. )
  6114. if searchKey:
  6115. matchFilters.update({
  6116. "cardNo": searchKey
  6117. })
  6118. records = AdjustUserVirtualCardRecord.get_collection().find(
  6119. matchFilters
  6120. ).sort(
  6121. [("dateTimeAdded", -1)]
  6122. ).skip(
  6123. pageSize * (pageIndex - 1)
  6124. ).limit(
  6125. pageSize
  6126. )
  6127. data = []
  6128. for record in records:
  6129. oldQuota = record.get("oldQuota")[0]
  6130. adjustQuota = record.get("adjustQuota")[0]
  6131. newQuota = {
  6132. "count" :oldQuota.get("count") + adjustQuota.get("count"),
  6133. "unit": oldQuota.get("unit")
  6134. }
  6135. dealerId = record.get("operator")
  6136. dealer = Dealer.get_dealer(dealerId)
  6137. operator = dealer.get("nickname") or dealer.get("username")
  6138. data.append(
  6139. {
  6140. "cardId": record.get("cardId"),
  6141. "cardNo": record.get("cardNo"),
  6142. "beforeAdjustExpired": record.get("beforeAdjust").strftime("%Y-%m-%d %H:%M:%S"),
  6143. "afterAdjustExpired": (record.get("beforeAdjust") + datetime.timedelta(days=record.get("adjustDays"))).strftime("%Y-%m-%d %H:%M:%S"),
  6144. "beforeAdjustQuota": "{} {}".format(oldQuota.get("count"), oldQuota.get("unit")),
  6145. "afterAdjustQuota": "{} {}".format(newQuota.get("count"), oldQuota.get("unit")),
  6146. "operator": operator,
  6147. "adjustType": record.get("adjustType"),
  6148. "adjustDate": record.get("dateTimeAdded")
  6149. }
  6150. )
  6151. return JsonOkResponse(payload={"total": 10000, "dataList": data})
  6152. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'读取失败,请重新试试'))
  6153. @permission_required(ROLE.dealer, ROLE.subaccount)
  6154. def getUserCardTicketList(request):
  6155. """
  6156. 经销商获取 已经发售的虚拟卡
  6157. 可以通过卡号搜索
  6158. 可以通过根据发卡地址来筛选 groupId
  6159. 可以通过卡类型筛选 dealerCardTypeId
  6160. 可以通过卡的状态来筛选 status 0(没过期 ) 1(过期)
  6161. :param request:
  6162. :return:
  6163. """
  6164. pageIndex = int(request.GET.get('pageIndex', 1))
  6165. pageSize = int(request.GET.get('pageSize', 10))
  6166. searchKey = request.GET.get('searchKey', '')
  6167. dealerCardTypeId = request.GET.get("dealerCardTypeId")
  6168. status = request.GET.get("status")
  6169. groupId = request.GET.get("groupId")
  6170. userId = str(request.GET.get('userId', ''))
  6171. isEmptyCard = int(request.GET.get('isEmptyCard', 0))
  6172. if isEmptyCard:
  6173. objs = VirtualCardBuilder.find_dealer_virtual_card(str(request.user.id)).order_by('-id')
  6174. else:
  6175. filters = {
  6176. "dealerId": str(request.user.bossId)
  6177. }
  6178. # 添加筛选条件
  6179. if userId:
  6180. filters.update({"openIds__contains": userId})
  6181. if groupId:
  6182. filters.update({"groupIds__in": ["*", groupId]})
  6183. if dealerCardTypeId:
  6184. filters.update({"cardTypeId": dealerCardTypeId})
  6185. if status:
  6186. nowTime = datetime.datetime.now()
  6187. status = int(status)
  6188. filters.update({"expiredTime__gt": nowTime}) if status else filters.update({"expiredTime__lt": nowTime})
  6189. objs = UserVirtualCard.objects.filter(**filters).order_by('-startTime')
  6190. if searchKey:
  6191. objs = objs.search(searchKey)
  6192. total = objs.count()
  6193. dataList = []
  6194. for obj in objs.skip((pageIndex - 1) * pageSize).limit(pageSize):
  6195. data = obj.to_dict()
  6196. data.update(obj.quotaInfo)
  6197. dataList.append(data)
  6198. return JsonResponse({"result": 1, "description": '', "payload": {'total': total, 'dataList': dataList}})
  6199. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"读取失败,请重新试试"))
  6200. @permission_required(ROLE.dealer, ROLE.subaccount)
  6201. def getUserCardTicketDetail(request):
  6202. """
  6203. 获取用户的
  6204. :param request:
  6205. :return:
  6206. """
  6207. cardId = request.GET.get("cardId", "")
  6208. try:
  6209. vCard = UserVirtualCard.objects.get(id=cardId)
  6210. except DoesNotExist:
  6211. return JsonErrorResponse(description=u"查询错误,请刷新页面重试")
  6212. data = vCard.to_detail()
  6213. data.update({"frozenState": not vCard.status in ["normal", "warning"]})
  6214. return JsonOkResponse(payload=data)
  6215. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"备注失败,请重新试试"))
  6216. @permission_required(ROLE.dealer, ROLE.subaccount)
  6217. def remarkUserVirtual(request):
  6218. """
  6219. 霍珀需求 经销商为已发卡卷添加备注
  6220. :param request:
  6221. :return:
  6222. """
  6223. payload = json.loads(request.body)
  6224. cardId = payload.get("cardId")
  6225. remark = payload.get("remark")
  6226. dealerId = str(request.user.bossId)
  6227. try:
  6228. vCard = UserVirtualCard.objects.get(id=cardId)
  6229. except DoesNotExist:
  6230. return JsonErrorResponse(description=u"虚拟卡备注失败,请刷新页面试试")
  6231. if vCard.dealerId != dealerId:
  6232. return JsonErrorResponse(description=u"不是您的虚拟卡您无权修改")
  6233. vCard.update(remark=remark)
  6234. return JsonOkResponse()
  6235. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'读取失败,请重新试试'))
  6236. @permission_required(ROLE.dealer, ROLE.subaccount)
  6237. def getElcPriceModList(request):
  6238. dealerId = str(request.user.bossId)
  6239. objs = ElecPriceTemplate.objects.filter(ownerId=dealerId)
  6240. resultList = [{'id': str(obj.id), 'name': obj.name, 'price': obj.priceList} for obj in objs]
  6241. return JsonResponse({"result": 1, "description": '', "payload": resultList})
  6242. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存失败,请重新试试'))
  6243. @permission_required(ROLE.dealer, ROLE.subaccount)
  6244. def saveElcPriceMod(request):
  6245. dealerId = str(request.user.bossId)
  6246. payload = json.loads(request.body)
  6247. priceList = payload['price']
  6248. logicalCode = payload['logicalCode']
  6249. newName = payload.get('name', None)
  6250. dev = Device.get_dev_by_logicalCode(logicalCode)
  6251. group = Group.get_group(dev['groupId'])
  6252. if newName is None:
  6253. newName = group['groupName'] + datetime.datetime.now().strftime('%Y%m%d%H%M%S')
  6254. newObj = ElecPriceTemplate(ownerId=dealerId,
  6255. name=newName,
  6256. priceList=priceList)
  6257. newObj.save()
  6258. return JsonResponse({"result": 1, "description": '', "payload": None})
  6259. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存失败,请重新试试'))
  6260. @permission_required(ROLE.dealer, ROLE.subaccount)
  6261. def saveDeviceElcPrice(request):
  6262. """
  6263. 这个是 用心汽车桩专用的 保存汽车的电价设置
  6264. """
  6265. payload = json.loads(request.body)
  6266. priceList = payload['price']
  6267. logicalCode = payload['logicalCode']
  6268. from apps.web.core.device_define.yongxin import DefaultParams
  6269. if len(priceList) != DefaultParams.DEFAULT_ELEC_PRICE_INTERVAL_NUM:
  6270. return JsonErrorResponse(description=u"电价参数设置错误,请重新试试")
  6271. if filter(lambda x: int(x * 100) > DefaultParams.DEFAULT_MAX_ELEC_PRICE, priceList):
  6272. return JsonErrorResponse(description=u"电价最大为2.55元")
  6273. device = Device.objects.get(logicalCode=logicalCode)
  6274. device.otherConf['priceList'] = priceList
  6275. device.save()
  6276. Device.invalid_device_cache(device.devNo)
  6277. return JsonOkResponse()
  6278. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除电价失败,请重新试试'))
  6279. @permission_required(ROLE.dealer, ROLE.subaccount)
  6280. def deleteElcPriceMod(request):
  6281. payload = json.loads(request.body)
  6282. ids = [ObjectId(_) for _ in payload['id']]
  6283. ElecPriceTemplate.get_collection().remove({'_id': {'$in': ids}})
  6284. return JsonResponse({"result": 1, "description": '', "payload": None})
  6285. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'上传的商品图片存储失败,请重新试试'))
  6286. @permission_required(ROLE.dealer, ROLE.subaccount)
  6287. def uploadItemPic(request):
  6288. # type: (WSGIRequest)->JsonResponse
  6289. files = request.FILES.getlist('file')
  6290. if not len(files):
  6291. return JsonResponse({'result': 0, 'description': u'未找到上传的商品图片,请重新试试', 'payload': {}})
  6292. uploader = AliOssFileUploader(inputFile=request.FILES.getlist('file')[0], uploadType='item')
  6293. logger.info('[uploadItemPic] %s is being used' % (repr(uploader),))
  6294. try:
  6295. outputUrl = uploader.upload()
  6296. return JsonResponse({'result': 1, 'description': '', 'payload': outputUrl})
  6297. except InvalidFileSize, e:
  6298. logger.info(
  6299. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  6300. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  6301. except InvalidFileName, e:
  6302. logger.info(
  6303. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  6304. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  6305. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'编辑商品类型失败,请重新试试'))
  6306. @permission_required(ROLE.dealer, ROLE.subaccount)
  6307. def addEditItemType(request):
  6308. payload = json.loads(request.body)
  6309. ownerId = str(request.user.bossId)
  6310. itemId = payload.get('id', None)
  6311. title = payload.get('name', None)
  6312. desc = payload.get('description', None)
  6313. picUrl = payload.get('img', "")
  6314. price = 100 * payload.get('price')
  6315. try:
  6316. if itemId is not None:
  6317. obj = ItemType.objects.get(id=itemId)
  6318. obj.title, obj.desc, obj.picUrl, obj.price = title, desc, picUrl, price
  6319. obj.save()
  6320. else:
  6321. newObj = ItemType(ownerId=ownerId, title=title, desc=desc, picUrl=picUrl, price=price)
  6322. newObj.save()
  6323. itemId = str(newObj.id)
  6324. except DoesNotExist:
  6325. newObj = ItemType(ownerId=ownerId, title=title, desc=desc, picUrl=picUrl, price=price)
  6326. newObj.save()
  6327. itemId = str(newObj.id)
  6328. except Exception as e:
  6329. logger.exception(e)
  6330. return JsonErrorResponse(description=u'未知错误')
  6331. return JsonResponse({"result": 1, "description": '', "payload": {"id": itemId}})
  6332. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'删除商品类型失败,请重新试试'))
  6333. @permission_required(ROLE.dealer, ROLE.subaccount)
  6334. def deleteItemType(request):
  6335. payload = json.loads(request.body)
  6336. ids = payload.get('ids', [])
  6337. itemIds = [ObjectId(obj) for obj in ids]
  6338. try:
  6339. ItemType.get_collection().remove({'_id': {'$in': itemIds}})
  6340. except Exception as e:
  6341. logger.exception(e)
  6342. return JsonErrorResponse(description=u'未知错误')
  6343. return JsonResponse({"result": 1, "description": '', "payload": None})
  6344. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取商品类型失败,请重新试试'))
  6345. @permission_required(ROLE.dealer, ROLE.subaccount)
  6346. def getItemTypes(request):
  6347. ownerId = str(request.user.bossId)
  6348. itemTypeId = request.GET.get('itemTypeId', '')
  6349. if itemTypeId:
  6350. objs = ItemType.objects.filter(ownerId=ownerId, id=itemTypeId)
  6351. else:
  6352. objs = ItemType.objects.filter(ownerId=ownerId)
  6353. dataList = [{'id': str(obj.id),
  6354. 'name': obj.title,
  6355. 'description': obj.desc,
  6356. 'img': obj.picUrl,
  6357. 'price': float(obj.price) / 100.0} for obj in objs
  6358. ]
  6359. return JsonResponse({"result": 1, "description": '', "payload": {'dataList': dataList}})
  6360. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'编辑格子失败'))
  6361. @permission_required(ROLE.dealer, ROLE.subaccount)
  6362. def addEditCell(request):
  6363. payload = json.loads(request.body)
  6364. logicalCode = payload.get('logicalCode')
  6365. cellId = payload.get('id', None)
  6366. cellNo = payload.get('cellNo')
  6367. boardNo = int(payload.get('boardNo'))
  6368. lockNo = int(payload.get('lockNo'))
  6369. itemTitle = payload.get('itemTitle', '')
  6370. itemDesc = payload.get('itemDesc', '')
  6371. itemPicUrl = payload.get('itemPicUrl', '')
  6372. itemPrice = payload.get('itemPrice') * 100
  6373. try:
  6374. if cellId is not None:
  6375. obj = Cell.objects.get(id=cellId)
  6376. obj.cellNo, obj.boardNo, obj.lockNo, obj.itemTitle, obj.itemDesc, obj.itemPicUrl, obj.itemPrice = cellNo, boardNo, lockNo, itemTitle, itemDesc, itemPicUrl, itemPrice
  6377. obj.save()
  6378. else:
  6379. newObj = Cell(logicalCode=logicalCode, cellNo=cellNo, boardNo=boardNo, lockNo=lockNo, itemTitle=itemTitle,
  6380. itemDesc=itemDesc, itemPicUrl=itemPicUrl, itemPrice=itemPrice)
  6381. newObj.save()
  6382. cellId = str(newObj.id)
  6383. except DoesNotExist, e:
  6384. newObj = Cell(logicalCode=logicalCode, cellNo=cellNo, boardNo=boardNo, lockNo=lockNo, itemTitle=itemTitle,
  6385. itemDesc=itemDesc, itemPicUrl=itemPicUrl, itemPrice=itemPrice)
  6386. newObj.save()
  6387. cellId = str(newObj.id)
  6388. except Exception, e:
  6389. return JsonErrorResponse(description=u'未知错误')
  6390. # 重新挂上washConfig套餐信息
  6391. cells = Cell.objects.filter(logicalCode=logicalCode)
  6392. washConfig = {}
  6393. for cell in cells:
  6394. washConfig[str(cell.id)] = {
  6395. 'name': cell.cellNo,
  6396. 'coins': float(cell.itemPrice / 100.0),
  6397. 'price': float(cell.itemPrice / 100.0),
  6398. 'time': 1,
  6399. 'description': cell.itemTitle,
  6400. 'imgList': [cell.itemPicUrl],
  6401. 'unit': u'次'
  6402. }
  6403. dev = Device.get_dev_by_logicalCode(logicalCode)
  6404. dev['washConfig'] = washConfig
  6405. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'washConfig': dev['washConfig']}})
  6406. Device.invalid_device_cache(dev['devNo'])
  6407. return JsonResponse({"result": 1, "description": '', "payload": {"id": cellId}})
  6408. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6409. @permission_required(ROLE.dealer, ROLE.subaccount)
  6410. def deleteCell(request):
  6411. payload = json.loads(request.body)
  6412. logicalCode = payload.get('logicalCode')
  6413. cellIds = payload.get('ids')
  6414. Cell.objects(id__in=cellIds).delete()
  6415. # 重新挂上washConfig套餐信息
  6416. cells = Cell.objects.filter(logicalCode=logicalCode)
  6417. washConfig = {}
  6418. for cell in cells:
  6419. washConfig[str(cell.id)] = {
  6420. 'name': cell.cellNo,
  6421. 'coins': float(cell.itemPrice / 100.0),
  6422. 'price': float(cell.itemPrice / 100.0),
  6423. 'time': 1,
  6424. 'description': cell.itemTitle,
  6425. 'imgList': [],
  6426. 'unit': u'次'
  6427. }
  6428. dev = Device.get_dev_by_logicalCode(logicalCode)
  6429. dev['washConfig'] = washConfig
  6430. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'washConfig': dev['washConfig']}})
  6431. Device.invalid_device_cache(dev['devNo'])
  6432. return JsonResponse({"result": 1, "description": '', "payload": None})
  6433. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'查询格子失败'))
  6434. @permission_required(ROLE.dealer, ROLE.subaccount)
  6435. def getDeviceCells(request):
  6436. logicalCode = request.GET.get('logicalCode')
  6437. pageIndex = int(request.GET.get('pageIndex', 1))
  6438. pageSize = int(request.GET.get('pageSize', 30))
  6439. objs = Cell.objects.filter(logicalCode=logicalCode)
  6440. dev = Device.get_dev_by_logicalCode(logicalCode)
  6441. box = ActionDeviceBuilder.create_action_device(dev)
  6442. lockStatusDict = box.get_all_lock_status()
  6443. dataList = []
  6444. quantity, consumptionQuantity = 0, 0
  6445. for obj in objs:
  6446. dataList.append(
  6447. {
  6448. 'id': str(obj.id), 'cellNo': obj.cellNo, 'boardNo': obj.boardNo,
  6449. 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle,
  6450. 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl,
  6451. 'itemPrice': round(obj.itemPrice / 100.0, 2),
  6452. 'lockStatus': lockStatusDict.get(obj.cellNo, 'close'),
  6453. 'quantity': 1 if obj.itemStatus == 'full' else 0
  6454. }
  6455. )
  6456. if obj.itemStatus == 'full':
  6457. quantity += 1
  6458. else:
  6459. consumptionQuantity += 1
  6460. dev['quantity'] = quantity
  6461. dev['consumptionQuantity'] = consumptionQuantity
  6462. Device.update_field(
  6463. dev_no=dev['devNo'],
  6464. update=True,
  6465. quantity=quantity,
  6466. consumptionQuantity=consumptionQuantity)
  6467. return JsonResponse({'result': 1, 'description': '',
  6468. 'payload': {'dataList': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]}})
  6469. def openManyCells(dev, strIds):
  6470. ids = [ObjectId(id) for id in strIds]
  6471. cellDict = {}
  6472. cells = Cell.objects.filter(id__in=ids)
  6473. for cell in cells:
  6474. if cellDict.has_key(str(cell.boardNo)):
  6475. cellDict[str(cell.boardNo)].append(cell.lockNo)
  6476. else:
  6477. cellDict[str(cell.boardNo)] = [cell.lockNo]
  6478. box = ActionDeviceBuilder.create_action_device(dev)
  6479. for boardNo, lockNos in cellDict.items():
  6480. try:
  6481. box.open_many_locks(boardNo, lockNos)
  6482. except Exception as e:
  6483. logger.exception(e)
  6484. return JsonResponse({"result": 0, "description": u'打开格子失败', "payload": None})
  6485. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6486. @permission_required(ROLE.dealer, ROLE.subaccount)
  6487. def addGoodsToDeviceCell(request):
  6488. payload = json.loads(request.body)
  6489. logicalCode = payload['logicalCode']
  6490. dev = Device.get_dev_by_logicalCode(logicalCode)
  6491. openManyCells(dev, payload['ids'])
  6492. ids = [ObjectId(strId) for strId in payload['ids']]
  6493. cells = Cell.objects.filter(id__in=ids)
  6494. for cell in cells:
  6495. cell.itemStatus = 'full'
  6496. try:
  6497. cell.save()
  6498. # 增加一条补货记录
  6499. newStock = StockRecord(
  6500. logicCode=dev['logicalCode'],
  6501. imei=dev['devNo'],
  6502. stockType='add',
  6503. stockTime=datetime.datetime.now().strftime(Const.DATETIME_FMT),
  6504. number=1,
  6505. more="%s:%s" % (cell.cellNo, cell.itemTitle)
  6506. )
  6507. newStock.save()
  6508. except Exception, e:
  6509. continue
  6510. Cell.update_dev_quantity_from_cell(dev)
  6511. return JsonResponse({"result": 1, "description": '', "payload": None})
  6512. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6513. @permission_required(ROLE.dealer, ROLE.subaccount)
  6514. def unlockCell(request):
  6515. payload = json.loads(request.body)
  6516. logicalCode = payload.get('logicalCode')
  6517. ids = payload.get('id')
  6518. dev = Device.get_dev_by_logicalCode(logicalCode)
  6519. openManyCells(dev, ids)
  6520. return JsonResponse({"result": 1, "description": '', "payload": None})
  6521. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6522. @permission_required(ROLE.dealer, ROLE.subaccount)
  6523. def getDeviceCellsFromDB(request):
  6524. logicalCode = request.GET.get('logicalCode')
  6525. pageIndex = int(request.GET.get('pageIndex', 1))
  6526. pageSize = int(request.GET.get('pageSize', 30))
  6527. objs = Cell.objects.filter(logicalCode=logicalCode)
  6528. dataList = []
  6529. quantity, consumptionQuantity = 0, 0
  6530. for obj in objs:
  6531. dataList.append(
  6532. {'id': str(obj.id), 'cellNo': obj.cellNo, 'boardNo': obj.boardNo,
  6533. 'lockNo': obj.lockNo, 'itemTitle': obj.itemTitle,
  6534. 'itemDesc': obj.itemDesc, 'itemPicUrl': obj.itemPicUrl,
  6535. 'itemPrice': round(obj.itemPrice / 100.0, 2),
  6536. # 'lockStatus':lockStatusDict.get(obj.cellNo,'close'),
  6537. 'quantity': 1 if obj.itemStatus == 'full' else 0}
  6538. )
  6539. if obj.itemStatus == 'full':
  6540. quantity += 1
  6541. else:
  6542. consumptionQuantity += 1
  6543. # TODO 为啥这两个参数只打内存,不更新到数据库
  6544. Device.get_and_update_device_cache(
  6545. dev_no=Device.get_dev_by_logicalCode(logicalCode)['devNo'],
  6546. quantity=quantity,
  6547. consumptionQuantity=consumptionQuantity)
  6548. return JsonResponse({'result': 1, 'description': '',
  6549. 'payload': {'dataList': dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]}})
  6550. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'获取列表失败'))
  6551. @permission_required(ROLE.dealer, ROLE.subaccount)
  6552. def getOfflineTaskList(request):
  6553. # type: (WSGIRequest)->JsonResponse
  6554. current_user = request.user # type: Dealer
  6555. page_index = int(request.GET.get('pageIndex', 1))
  6556. page_size = int(request.GET.get('pageSize', 10))
  6557. search_key = request.GET.get('searchKey', None)
  6558. tasks = OfflineTask.objects(ownerId=current_user.id,
  6559. role=current_user.role).search(search_key).order_by('-dateTimeAdded')
  6560. total = tasks.count()
  6561. return JsonOkResponse(
  6562. payload={
  6563. 'dataList': [t.to_dict() for t in tasks.paginate(pageSize=page_size, pageIndex=page_index)],
  6564. 'total': total
  6565. })
  6566. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6567. @permission_required(ROLE.dealer, ROLE.subaccount)
  6568. def exportBusinessStats(request):
  6569. """
  6570. 经销商的手机 导出报表
  6571. :param request:
  6572. :return:
  6573. """
  6574. dealer = request.user # type: Dealer
  6575. request_get = request.GET.copy()
  6576. if 'kind' not in request_get:
  6577. request_get['kind'] = 'income'
  6578. if 'time' in request_get and (('startTime' not in request_get) or ('endTime' not in request_get)):
  6579. # 将月份转换成开始时间为1号,结束时间为当月最后一天,因为需要一个前闭后闭区间,所以最后一天日期减一天
  6580. request_get['startTime'] = datetime.datetime.strptime(request_get.pop('time')[0], "%Y-%m")
  6581. request_get['endTime'] = request_get['startTime'] + relativedelta(months=1) - datetime.timedelta(days=1)
  6582. request_get['startTime'] = request_get['startTime'].strftime(Const.DATE_FMT)
  6583. request_get['endTime'] = request_get['endTime'].strftime(Const.DATE_FMT)
  6584. query = prepare_query(request_get) # type: Query
  6585. def get_offline_task_name(task_type, user, **kwargs):
  6586. # type: (basestring, Dealer, Dict)->basestring
  6587. type_desc_map = {
  6588. 'income': u'收益',
  6589. 'consume': u'消费',
  6590. 'monthly_bill': u'月度'
  6591. }
  6592. tmp_list = [task_type, type_desc_map.get(kwargs['kind']), user.username]
  6593. if 'logicalCode' in kwargs:
  6594. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  6595. if 'groupId' in kwargs:
  6596. address = Group.get_group(kwargs['groupId']).get('address', '')
  6597. tmp_list.append(u'地址_%s' % (address,))
  6598. if 'source' in kwargs:
  6599. kind = kwargs.get('kind')
  6600. if kind == 'income':
  6601. source_translation = DEALER_INCOME_SOURCE_TRANSLATION.get(kwargs['source'])
  6602. elif kind == 'consume':
  6603. source_translation = DEALER_CONSUMPTION_AGG_KIND_TRANSLATION.get(kwargs['source'])
  6604. else:
  6605. source_translation = None
  6606. if source_translation:
  6607. tmp_list.append(source_translation)
  6608. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  6609. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  6610. return '-'.join(tmp_list).replace("/", "_")
  6611. # 此处生成的是 报表文件的名称
  6612. offline_task_name = get_offline_task_name(
  6613. task_type=OfflineTaskType.BUSINESS_REPORT,
  6614. user=dealer,
  6615. **query.raw)
  6616. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  6617. process_func_name='generate_business_stats_report_by_dealer',
  6618. task_type=OfflineTaskType.BUSINESS_REPORT,
  6619. userid=str(dealer.id),
  6620. role=ROLE.dealer)
  6621. queryAttrs = query.attrs
  6622. queryAttrs['dateTimeAdded__lte'] = dt_to_timestamp(queryAttrs['dateTimeAdded__lte'])
  6623. queryAttrs['dateTimeAdded__gte'] = dt_to_timestamp(queryAttrs['dateTimeAdded__gte'])
  6624. queryAttrs['dealerId'] = str(dealer.id)
  6625. task_caller(func_name=offline_task.process_func_name,
  6626. offline_task_id=str(offline_task.id),
  6627. filePath=file_path,
  6628. queryAttrs=queryAttrs)
  6629. return JsonOkResponse(payload=str(offline_task.id))
  6630. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6631. @permission_required(ROLE.dealer, ROLE.subaccount)
  6632. def exportAllTicketList(request):
  6633. """
  6634. 经销商的下的所以虚拟卡
  6635. :param request:
  6636. :return:
  6637. """
  6638. dealer = request.user # type: Dealer
  6639. timeStr = arrow.now().format('YYYY-MM-DD_HH:mm:ss')
  6640. offline_task_name = '已发虚拟卡_{}_{}_{}'.format(dealer.username, timeStr, random.randint(100000, 999999))
  6641. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  6642. process_func_name='export_vcard_info_excel_from_db',
  6643. task_type=OfflineTaskType.BUSINESS_REPORT,
  6644. userid=str(dealer.id),
  6645. role=ROLE.dealer)
  6646. queryDict = {}
  6647. queryDict['dealerId'] = str(dealer.id)
  6648. task_caller(func_name=offline_task.process_func_name,
  6649. offline_task_id=str(offline_task.id),
  6650. filepath=file_path,
  6651. queryDict=queryDict)
  6652. return JsonOkResponse(payload=str(offline_task.id))
  6653. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取收益列表失败"))
  6654. @permission_required(ROLE.dealer)
  6655. def getGroupUserAccountInfo(request):
  6656. """
  6657. 经销商下所有地址的用户充值,消费,余额情况
  6658. """
  6659. dealer = request.user # type: Dealer
  6660. def get_offline_task_name(task_type, user, **kwargs):
  6661. # type: (basestring, Dealer, Dict)->basestring
  6662. tmp_list = [task_type, user.username]
  6663. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  6664. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  6665. if 'groupId' in kwargs and kwargs['groupId']:
  6666. address = Group.get_group(kwargs['groupId']).get('address', '')
  6667. tmp_list.append(u'地址_%s' % (address,))
  6668. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  6669. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  6670. return '-'.join(tmp_list).replace("/", "_")
  6671. query_dict = {
  6672. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  6673. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  6674. 'ownerId': str(dealer.id)
  6675. }
  6676. offline_task_name = get_offline_task_name(
  6677. task_type=u'地址用户充值消费情况统计报表',
  6678. user=dealer,
  6679. **query_dict)
  6680. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  6681. process_func_name='export_group_user_account_excel_form_db',
  6682. task_type=OfflineTaskType.BUSINESS_REPORT,
  6683. userid=str(dealer.id),
  6684. role=ROLE.dealer)
  6685. task_caller(func_name=offline_task.process_func_name,
  6686. offline_task_id=str(offline_task.id),
  6687. filepath=file_path,
  6688. queryDict=query_dict)
  6689. return JsonResponse({
  6690. 'result': 1,
  6691. 'description': u"请前往离线任务查看任务处理情况",
  6692. 'payload': str(offline_task.id)})
  6693. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6694. @permission_required(ROLE.dealer, ROLE.subaccount)
  6695. def getOfflineTaskStatus(request):
  6696. # type: (WSGIRequest)->JsonResponse
  6697. """
  6698. :param request:
  6699. :return:
  6700. """
  6701. task_id = request.GET.get('id')
  6702. if not task_id:
  6703. return JsonErrorResponse(description=u'查询ID为空')
  6704. task = OfflineTask.objects(id=str(task_id)).get() # type: OfflineTask
  6705. return JsonOkResponse(payload=task.status)
  6706. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6707. @permission_required(ROLE.dealer, ROLE.subaccount)
  6708. def getSubAccountList(request):
  6709. pageIndex = int(request.GET.get('pageIndex', 1))
  6710. pageSize = int(request.GET.get('pageSize', 10))
  6711. subaccounts = SubAccount.objects.filter(bossId=str(request.user.bossId))
  6712. total = subaccounts.count()
  6713. dataList = []
  6714. for obj in subaccounts.skip((pageIndex - 1) * pageSize).limit(pageSize):
  6715. if obj.bossId == str(obj.id):
  6716. continue
  6717. dataList.append({
  6718. 'username': obj.username,
  6719. 'permissionList': obj.permissionList,
  6720. 'nickname': obj.nickname,
  6721. 'id': str(obj.id)
  6722. })
  6723. return JsonOkResponse(payload={'agentId': request.user.agentId, 'dataList': dataList, 'total': total})
  6724. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6725. @permission_required(ROLE.dealer, ROLE.subaccount)
  6726. def addEditSubAccount(request):
  6727. bossId = request.user.bossId
  6728. payload = json.loads(request.body)
  6729. strId = payload.get('id', None)
  6730. if strId is None:
  6731. username = payload['username']
  6732. code = payload['code']
  6733. status, desc = dealerRegisterSMSProvider.verify(username, code)
  6734. if not status:
  6735. return JsonErrorResponse(desc)
  6736. count = SubAccount.objects.filter(username=username, bossId=str(bossId)).count()
  6737. if count > 0:
  6738. return JsonResponse({"result": 0, "description": u'该手机号已经是子账号了,不允许重复配置该手机号为子账号', "payload": None})
  6739. password = payload['password']
  6740. if (not password) or len(password) < 6:
  6741. return JsonResponse({"result": 0, "description": u'必须输入密码,密码长度不能小于6', "payload": None})
  6742. nickname = payload['nickname']
  6743. if not nickname:
  6744. return JsonResponse({"result": 0, "description": u'必须配置昵称', "payload": None})
  6745. newObj = SubAccount(
  6746. username=username,
  6747. nickname=nickname,
  6748. password=make_password(password),
  6749. permissionList=payload.get('permissionList', []),
  6750. agentId=request.user.agentId,
  6751. bossId=bossId
  6752. )
  6753. newObj.save()
  6754. return JsonOkResponse(payload={'id': str(newObj.id)})
  6755. else:
  6756. username = payload['username']
  6757. try:
  6758. obj = SubAccount.objects.get(id=strId)
  6759. except DoesNotExist:
  6760. return JsonResponse({"result": 0, "description": u'并未找到该子账号,可能已经被删除了', "payload": None})
  6761. password = payload['password']
  6762. if (not password) or len(password) < 6:
  6763. return JsonResponse({"result": 0, "description": u'必须输入密码,密码长度不能小于6', "payload": None})
  6764. nickname = payload['nickname']
  6765. if not nickname:
  6766. return JsonResponse({"result": 0, "description": u'必须配置昵称', "payload": None})
  6767. obj.username = username
  6768. obj.nickname = nickname
  6769. obj.permissionList = payload.get('permissionList', [])
  6770. obj.save()
  6771. obj.set_password(password)
  6772. return JsonOkResponse(payload={'id': str(obj.id)})
  6773. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6774. @permission_required(ROLE.dealer, ROLE.subaccount)
  6775. def deleteSubAccount(request):
  6776. payload = json.loads(request.body)
  6777. idsTemp = payload.get('ids', [])
  6778. ids = [ObjectId(_) for _ in idsTemp]
  6779. SubAccount.objects.filter(id__in=ids).delete()
  6780. return JsonResponse({"result": 1, "description": '', "payload": None})
  6781. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6782. @permission_required(ROLE.dealer, ROLE.subaccount)
  6783. def getAccountPermission(request):
  6784. # 授权经销商用户
  6785. if check_role(request.user, ROLE.dealer):
  6786. permissions = hasattr(request, 'permissions') and getattr(request, 'permissions') # type: dict
  6787. if permissions:
  6788. permissions.update({'role': 'dealerWorker'})
  6789. return JsonOkResponse(payload=permissions)
  6790. # 获取经销商或者子账号所属经销商权限
  6791. mainMenu, homepageData = request.user.myBoss.query_home_page_layout()
  6792. # 调整子账号权限
  6793. if check_role(request.user, ROLE.subaccount):
  6794. for pm in request.user.permissionList:
  6795. if pm in ['today_income', 'today_pay_income', 'today_ad_income', 'offline_coins']:
  6796. homepageData[pm] = True
  6797. else:
  6798. mainMenu[pm] = True
  6799. leftHomepage = list(set(Const.HOME_PAGE_DATA_LIST.keys()) - set(request.user.permissionList))
  6800. for pm in leftHomepage:
  6801. homepageData[pm] = False
  6802. leftMainmenu = list(set(Const.MAIN_MENU_LIST.keys()) - set(request.user.permissionList))
  6803. for pm in leftMainmenu:
  6804. mainMenu[pm] = False
  6805. return JsonOkResponse(payload={'role': request.user.role, 'homepageData': homepageData, 'mainMenu': mainMenu})
  6806. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'操作失败'))
  6807. @permission_required(ROLE.dealer)
  6808. def getAccountPermissionById(request):
  6809. strId = request.GET.get('id', None)
  6810. subList = SubAccount.objects.get(id=strId).permissionList
  6811. mainMenu, homepageData = request.user.query_home_page_layout()
  6812. for menu, value in mainMenu.iteritems():
  6813. if not value:
  6814. continue
  6815. if menu in subList:
  6816. mainMenu[menu] = True
  6817. else:
  6818. mainMenu[menu] = False
  6819. mainMenu['sim_card'] = False # sim卡充值不允许给子账号操作
  6820. for menu, value in homepageData.iteritems():
  6821. if not value:
  6822. continue
  6823. if menu in subList:
  6824. homepageData[menu] = True
  6825. else:
  6826. homepageData[menu] = False
  6827. return JsonOkResponse(payload={'homepageData': homepageData, 'mainMenu': mainMenu})
  6828. @permission_required(ROLE.dealer)
  6829. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6830. def subAccountRegisterCode(request):
  6831. # type: (WSGIRequest)->JsonResponse
  6832. payload = json.loads(request.body)
  6833. phoneNumber = payload.get('username', None)
  6834. agent = Agent.get_agent(request.user.agentId)
  6835. productName = agent['productName']
  6836. if not phoneNumber:
  6837. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  6838. if len(SubAccount.objects.filter(username=phoneNumber, bossId=str(request.user.id))):
  6839. return JsonResponse({'result': 0, 'description': u'该手机号已经是您的子账号了'})
  6840. status, msg = dealerRegisterSMSProvider.get(phoneNumber=phoneNumber,
  6841. productName=productName,
  6842. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  6843. if not status:
  6844. return JsonResponse({'result': 0, 'description': msg})
  6845. else:
  6846. return JsonResponse({'result': 1, 'description': ''})
  6847. @permission_required(ROLE.dealer)
  6848. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6849. def saveAccountPermission(request):
  6850. payload = json.loads(request.body)
  6851. subId = payload.get('id')
  6852. homepageData = payload.get('homepageData', [])
  6853. mainMenu = payload.get('mainMenu', [])
  6854. obj = SubAccount.objects.get(id=subId)
  6855. perList = []
  6856. for k, v in homepageData.items():
  6857. if v:
  6858. perList.append(k)
  6859. for k, v in mainMenu.items():
  6860. if v:
  6861. perList.append(k)
  6862. obj.permissionList = perList
  6863. obj.save()
  6864. return JsonResponse({'result': 1, 'description': ''})
  6865. @permission_required(ROLE.dealer)
  6866. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6867. def getAlarmList(request):
  6868. # type: (WSGIRequest)->JsonResponse
  6869. pageIndex = int(request.GET.get('pageIndex', 1))
  6870. pageSize = int(request.GET.get('pageSize', 10))
  6871. queryset = FaultRecord.objects(dealerId=str(request.user.id), status=FAULT_RECORD_STATUS.INIT).order_by('-createdTime')
  6872. records = queryset.paginate(pageIndex=pageIndex, pageSize=pageSize) # type: Iterable[FaultRecord]
  6873. total = queryset.count()
  6874. return JsonOkResponse(payload={'dataList': [ _.to_dict() for _ in records ], 'total': total})
  6875. @permission_required(ROLE.dealer)
  6876. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6877. def handleAlarm(request):
  6878. # type: (WSGIRequest)->JsonResponse
  6879. payload = json.loads(request.body)
  6880. id_ = payload.get('id')
  6881. if id_ is None:
  6882. return JsonErrorResponse(description=u'id未传入')
  6883. status = payload.get('status')
  6884. if status is None:
  6885. return JsonErrorResponse(description=u'处理状态未传入')
  6886. dealedDetail = payload.get("dealedDetail", "")
  6887. if type(id_) == list:
  6888. id_list = id_
  6889. else:
  6890. id_list = [id_]
  6891. for item_id in id_list:
  6892. alarm = FaultRecord.objects(id=item_id).get() # type: FaultRecord
  6893. alarm.set_status(status=status, dealedDetail=dealedDetail)
  6894. if status == "handled":
  6895. task_caller(
  6896. "send_to_xf_fault_handle",
  6897. devNo=alarm.imei,
  6898. faultId=str(alarm.id)
  6899. )
  6900. handler_event_to_zhejiang(id_list[0])
  6901. dev = Device.get_dev(alarm.imei)
  6902. box = ActionDeviceBuilder.create_action_device(dev)
  6903. if box.isHaveFaultHandle:
  6904. try:
  6905. box.faultHandle(alarm=alarm)
  6906. except:
  6907. pass
  6908. return JsonOkResponse()
  6909. @permission_required(ROLE.dealer)
  6910. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  6911. def checkAlarm(request):
  6912. # type: (WSGIRequest)->JsonResponse
  6913. id_ = request.GET.get('id')
  6914. if id_ is None:
  6915. return JsonErrorResponse(description=u'id未传入')
  6916. alarm = FaultRecord.objects(id=id_).get() # type: FaultRecord
  6917. dev = Device.get_dev(alarm.imei)
  6918. box = ActionDeviceBuilder.create_action_device(dev)
  6919. try:
  6920. desc = box.check_alarm(alarm)
  6921. except ServiceException , e:
  6922. return JsonResponse({"result": 0, "description": e.result.get('description'), 'payload': {}})
  6923. except Exception, e:
  6924. return JsonResponse({"result": 0, "description": u'系统异常,检查告警失败', 'payload': {}})
  6925. return JsonResponse({"result": 1, "description": desc, 'payload': {}})
  6926. @permission_required(ROLE.dealer)
  6927. @error_tolerate(logger = logger, nil = JsonErrorResponse(u'系统错误,请稍后再试'))
  6928. def withdrawEntry(request):
  6929. # type: (WSGIRequest)->JsonResponse
  6930. user = request.user # type: Dealer
  6931. if not check_role(user, ROLE.dealer):
  6932. return ErrorResponseRedirect(error = u'权限错误')
  6933. # 检查是否有非法订单,如果有,不允许提现直接返回错误
  6934. if RechargeRecord.have_illegal_order(str(user.id), user.maxPackagePrice):
  6935. return ErrorResponseRedirect(error = u'系统检测到部分存疑订单,暂时不能提现。请联系平台客服确认')
  6936. source_key = request.GET.get('sourceId')
  6937. if not WithdrawGateway.is_ledger(source_key):
  6938. return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10003)')
  6939. source_type = request.GET.get('sourceType')
  6940. assert source_type in DEALER_INCOME_TYPE.choices(), 'invalid dealer income type'
  6941. if source_key not in user.balance_dict(source_type):
  6942. return ErrorResponseRedirect(error = u'提现参数错误,请刷新后重试')
  6943. is_ledger, agent, withdraw_gateway_list = Agent.withdraw_gateway_list(source_key)
  6944. if not is_ledger:
  6945. return ErrorResponseRedirect(error = u'系统配置错误,请联系平台客服(10005)')
  6946. wechat_withdraw_gateway = withdraw_gateway_list['wechat'] # type: WithdrawGateway
  6947. if wechat_withdraw_gateway.support_withdraw and not wechat_withdraw_gateway.manual_withdraw:
  6948. code = request.GET.get('code', None)
  6949. if not code:
  6950. redirect = request.GET.get('redirect')
  6951. return ExternalResponseRedirect(
  6952. WechatAuthBridge(wechat_withdraw_gateway.app).generate_auth_url_base_scope(
  6953. concat_server_end_url(
  6954. uri = '/dealer/withdraw/entry?sourceType={source_type}&sourceId={source_key}'.format(
  6955. source_type = source_type,
  6956. source_key = source_key
  6957. )), payload = base64.b64encode(redirect)))
  6958. else:
  6959. auth_bridge = WechatAuthBridge(wechat_withdraw_gateway.app)
  6960. openId = auth_bridge.authorize(code)
  6961. if openId is not None:
  6962. redirect = base64.b64decode(request.GET.get('payload'))
  6963. redirect = add_query(redirect, {
  6964. 'sourceType': source_type,
  6965. 'sourceId': source_key,
  6966. 'openId': openId
  6967. })
  6968. return FrontEndResponseRedirect(redirect)
  6969. else:
  6970. return ErrorResponseRedirect(error = u'微信授权失败,请刷新后重试')
  6971. else:
  6972. redirect = request.GET.get('redirect')
  6973. redirect = add_query(redirect, {
  6974. 'sourceType': source_type,
  6975. 'sourceId': source_key,
  6976. 'openId': ''
  6977. })
  6978. return FrontEndResponseRedirect(redirect)
  6979. @permission_required(ROLE.dealer)
  6980. def ActivateUser(request):
  6981. """
  6982. 安骑的 用户缴纳金额后 经销商激活
  6983. 需要查询对应的 推荐人,如果存在推荐人,将其金币数量增加固定数量
  6984. """
  6985. user = request.user
  6986. payload = json.loads(request.body)
  6987. _id = payload.get("id", "") # 存有用户激活信息的ID
  6988. status = payload.get("status", "")
  6989. remarks = payload.get("remarks", "")
  6990. groupIds = Group.get_group_ids_of_dealer(str(user.id)) # 获取该经销商下的所有的groupId
  6991. customer = MyUser.objects.get(id=_id)
  6992. if int(status) == 2: # 2表示用户信息激活状态为成功
  6993. MyUser.set_active_info(
  6994. {"isMember": True,
  6995. "status": status,
  6996. "remarks": remarks},
  6997. openId=customer.openId,
  6998. agentId=customer.agentId,
  6999. groupId__in=groupIds
  7000. )
  7001. # TODO zjl 这一部分任务查询时间任过长,没有索引, 是否考虑设置异步任务触发
  7002. recommender = MyUser.get_active_info(openId=customer.openId, agentId=customer.agentId, groupId__in=groupIds).get("recommender") # 推荐人
  7003. if recommender:
  7004. groupList = Group.get_groups_of_dealer(user.id)
  7005. recommender = MyUser.objects.get(phoneNumber=recommender)
  7006. if recommender.groupId not in groupList: # 添加对于当前的recommender的验证 要是同一个经销商下的
  7007. logger.info("uninvalid recommender dealer=%s, recommender=%s" % (user.nickname, recommender.nickname))
  7008. else:
  7009. coins = 10 # TODO zjl 添加推荐人金币 金币设置值
  7010. update = recommender.incr_balance(VirtualCoin(coins))
  7011. if not update:
  7012. logger.info("recommender %s get coins faild." % recommender.nickname)
  7013. else:
  7014. # 添加一条充值记录
  7015. orderNo = str(uuid.uuid1())
  7016. try:
  7017. newRcd = RechargeRecord(orderNo=orderNo,
  7018. coins=coins,
  7019. money=0.00,
  7020. openId=recommender.openId,
  7021. wxOrderNo=u'活动赠币',
  7022. nickname=recommender.nickname,
  7023. result='success',
  7024. via='sendcoin',
  7025. operator=str(user.id))
  7026. newRcd.save()
  7027. except Exception as e:
  7028. logger.exception('update record for feedback coins error=%s,orderNo=%s' % (e, orderNo))
  7029. return JsonOkResponse(u"会员录入成功,可以正常使用换电柜")
  7030. elif int(status) == 3: # 3表示用户信息激活状态为失败
  7031. MyUser.set_active_info(
  7032. {"isMember": False,
  7033. "status": status,
  7034. "remarks": remarks,
  7035. "auditTime": datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d %H:%M:%S")},
  7036. openId=customer.openId,
  7037. agentId=customer.agentId,
  7038. groupId__in=groupIds
  7039. )
  7040. return JsonOkResponse(u"已拒绝该用户")
  7041. else:
  7042. logger.error("uninvalid status : %s" % status)
  7043. return JsonErrorResponse(u"无效的审核状态")
  7044. @permission_required(ROLE.dealer)
  7045. def delUserActiveInfo(request):
  7046. user = request.user
  7047. payload = json.loads(request.body)
  7048. ids = payload.get("ids", "")
  7049. # 删除该经销商下的该用户的激活信息
  7050. customers = MyUser.objects.filter(id__in=ids)
  7051. groupIds = Group.get_group_ids_of_dealer(str(user.id))
  7052. for customer in customers:
  7053. MyUser.del_active_info(
  7054. openId=customer.openId,
  7055. agentId=customer.agentId,
  7056. groupId__in=groupIds
  7057. )
  7058. return JsonOkResponse()
  7059. @permission_required(ROLE.dealer)
  7060. def getUserIdentifyList(request):
  7061. """
  7062. 获取临时用户 待激活用户
  7063. """
  7064. pageIndex = int(request.GET.get("pageIndex", 1))
  7065. pageSize = int(request.GET.get("pageSize", 10))
  7066. searchKey = request.GET.get("searchKey")
  7067. status = request.GET.get("status")
  7068. if status in ("", "null"):
  7069. statusList = [0, 1, 2, 3]
  7070. else:
  7071. statusList = [int(status)]
  7072. groupList = Group.get_group_ids_of_dealer(request.user.id)
  7073. query = {
  7074. "groupId": {"$in": groupList},
  7075. "extra.active.status": {"$in": statusList}
  7076. }
  7077. if searchKey:
  7078. query.update(search_query(['nickname', 'phoneNumber'], searchKey).to_query(MyUser))
  7079. results = MyUser.get_collection().find(
  7080. query,
  7081. {
  7082. "nickname": 1,
  7083. "openId": 1,
  7084. "phoneNumber": 1,
  7085. "avatar": 1,
  7086. "extra.active": 1
  7087. }
  7088. ).skip(
  7089. (pageIndex - 1) * pageSize
  7090. ).limit(
  7091. pageSize
  7092. )
  7093. tempUsers = []
  7094. for user in results:
  7095. userDict = dict()
  7096. userDict["id"] = str(user["_id"])
  7097. # userDict["phoneNumber"] = user["phoneNumber"]
  7098. userDict["userNickname"] = user.get("nickname", "")
  7099. userDict["avatarUrl"] = user.get("avatar", "")
  7100. userDict.update(
  7101. user["extra"]["active"]
  7102. )
  7103. tempUsers.append(userDict)
  7104. data = {
  7105. "page": pageIndex,
  7106. # "total": 2 * pageSize if len(tempUsers) >= pageSize else pageSize,
  7107. "total": 10000,
  7108. "pageSize": pageSize,
  7109. "offset": 0,
  7110. "dataList": tempUsers
  7111. }
  7112. return JsonResponse({'result': 1, 'description': "", 'payload': data})
  7113. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'鉴权失败,请重新登录'))
  7114. @permission_required(ROLE.dealer, ROLE.subaccount)
  7115. def info(request):
  7116. user = request.user
  7117. payload = {
  7118. 'roles':['admin'],
  7119. 'introduction':user.description,
  7120. 'avatar':user.wechatAuthUserInfo.get('avatar'),
  7121. 'name':user.phone
  7122. }
  7123. return JsonResponse({'result': 1, 'description': '', 'payload':payload})
  7124. def getDashboard(request):
  7125. dealerId = str(request.user.id)
  7126. groupIds = Group.get_group_ids_of_dealer(dealerId)
  7127. devList = Device.get_devices_by_group(groupIds).values()
  7128. devCount = len(devList)
  7129. todayTime = datetime.datetime.now()
  7130. yesterdayTime = todayTime - datetime.timedelta(days=1)
  7131. today = todayTime.strftime(Const.DATE_FMT)
  7132. yesterDay = yesterdayTime.strftime(Const.DATE_FMT)
  7133. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':today}, {'daily':1, 'activedDevRatio':1})
  7134. if rcds.count() == 0:
  7135. todayIncome = 0
  7136. todayRechargeIncome = 0
  7137. todayChargeCardIncome = 0
  7138. todayOrder = 0
  7139. else:
  7140. info = rcds[0]
  7141. todayIncome = info.get('daily', {}).get('totalIncome', 0)
  7142. income = info.get('daily', {}).get('income', {})
  7143. todayRechargeIncome = income.get('recharge', 0)
  7144. todayChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('chargeVirtualCard', 0))
  7145. todayOrder = info.get('daily', {}).get('totalIncomeCount', 0)
  7146. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':yesterDay}, {'daily':1, 'activedDevRatio':1})
  7147. if rcds.count() == 0:
  7148. yesterdayIncome = 0
  7149. yesterdayOrder = 0
  7150. yesterdayActiveDevicePercent = 0
  7151. yesterdayActiveDevice = 0
  7152. yesterdayRechargeIncome = 0
  7153. yesterdayChargeCardIncome = 0
  7154. else:
  7155. info = rcds[0]
  7156. yesterdayIncome = info.get('daily', {}).get('totalIncome', 0)
  7157. income = info.get('daily', {}).get('income', {})
  7158. yesterdayRechargeIncome = income.get('recharge', 0)
  7159. yesterdayChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('chargeVirtualCard', 0))
  7160. yesterdayOrder = info.get('daily', {}).get('totalIncomeCount', 0)
  7161. yesterdayActiveDevicePercent = info.get('activedDevRatio', 0)
  7162. yesterdayActiveDevice = int(round(yesterdayActiveDevicePercent / 100.0 * devCount, 2))
  7163. date = MONTH_DATE_KEY.format(year=todayTime.year, month=todayTime.month)
  7164. rcds = DealerMonthlyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':date}, {'monthly':1, 'activedDevRatio':1, 'addedUserCount':1})
  7165. if rcds.count() == 0:
  7166. monthIncome = 0
  7167. monthRechargeIncome = 0
  7168. monthChargeCardIncome = 0
  7169. thisMonthOrder = 0
  7170. userCountAddedThisMonth = 0
  7171. else:
  7172. info = rcds[0]
  7173. monthIncome = info.get('monthly', {}).get('totalIncome', 0)
  7174. income = info.get('monthly', {}).get('income', {})
  7175. monthRechargeIncome = income.get('recharge', 0)
  7176. monthChargeCardIncome = RMB(income.get('chargeCard', 0)) + RMB(income.get('chargeVirtualCard', 0))
  7177. thisMonthOrder = info.get('monthly', {}).get('totalIncomeCount', 0)
  7178. userCountAddedThisMonth = info.get('addedUserCount', 0)
  7179. userCount = request.user.userCount
  7180. return JsonOkResponse(
  7181. payload={
  7182. "todayIncome":todayIncome,
  7183. 'todayRechargeIncome':todayRechargeIncome,
  7184. 'todayChargeCardIncome':todayChargeCardIncome,
  7185. "yesterdayIncome":yesterdayIncome,
  7186. 'yesterdayRechargeIncome':yesterdayRechargeIncome,
  7187. 'yesterdayChargeCardIncome':yesterdayChargeCardIncome,
  7188. "thisMonthIncome": monthIncome,
  7189. 'thisMonthRechargeIncome':monthRechargeIncome,
  7190. 'thisMonthChargeCardIncome':monthChargeCardIncome,
  7191. "todayOrder": todayOrder,
  7192. "yesterdayOrder":yesterdayOrder,
  7193. "thisMonthOrder":thisMonthOrder,
  7194. "deviceTotal":len(devList),
  7195. "yesterdayActiveDevice":yesterdayActiveDevice,
  7196. "yesterdayActiveDevicePercent":yesterdayActiveDevicePercent,
  7197. 'userCount':userCount,
  7198. 'userCountAddedThisMonth':userCountAddedThisMonth
  7199. }
  7200. )
  7201. def deviceOfflineTrend(request):
  7202. dealerId = str(request.user.id)
  7203. todayTime = datetime.datetime.now()
  7204. startTime = todayTime - datetime.timedelta(days=7)
  7205. startDay = startTime.strftime(Const.DATE_FMT)
  7206. endDay = todayTime.strftime(Const.DATE_FMT)
  7207. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':{'$gte':startDay, '$lte':endDay}}, {'other':1, 'date':1})
  7208. dataList = []
  7209. for rcd in rcds:
  7210. other = rcd.get('other', {'totalOfflineTime':0, 'totalOfflineBusyTime':0, 'totalOnlineTime':0})
  7211. totalTime = other['totalOfflineTime'] + other['totalOfflineBusyTime'] + other['totalOnlineTime']
  7212. dataList.append({
  7213. 'dateStr':rcd['date'],
  7214. 'offlineTimePercent':round(100 * other['totalOfflineTime'] / totalTime, 2) if totalTime else 0
  7215. })
  7216. return JsonOkResponse(payload={'dataList': dataList})
  7217. @error_tolerate(nil=DefaultJsonErrorResponse)
  7218. @permission_required(ROLE.dealer)
  7219. def deviceActiveTrend(request):
  7220. dealerId = str(request.user.id)
  7221. todayTime = datetime.datetime.now()
  7222. startTime = todayTime - datetime.timedelta(days=7)
  7223. startDay = startTime.strftime(Const.DATE_FMT)
  7224. endDay = todayTime.strftime(Const.DATE_FMT)
  7225. rcds = DealerDailyStat.get_collection().find({'dealerId':ObjectId(dealerId), 'date':{'$gte':startDay, '$lte':endDay}}, {'activedDevRatio':1, 'date':1})
  7226. dataList = []
  7227. for rcd in rcds:
  7228. ratio = rcd.get('activedDevRatio', 0)
  7229. dataList.append({
  7230. 'dateStr':rcd['date'],
  7231. 'activeDevicePercent':ratio
  7232. })
  7233. return JsonOkResponse(payload={'dataList': dataList})
  7234. @error_tolerate(nil=DefaultJsonErrorResponse)
  7235. @permission_required(ROLE.dealer)
  7236. def getGroupStatistics(request):
  7237. def calc_group_stats(groupId, startDate, endDate):
  7238. groupResult = GroupReport.get_rpt([groupId], startDate, endDate)
  7239. offlineCoin = groupResult[groupId].get('lineCoins', 0)
  7240. rcds = GroupDailyStatsModelProxy.get_data_list(startTime=startDate,
  7241. endTime=endDate,
  7242. groupId=ObjectId(groupId),
  7243. only={
  7244. 'other': 1, 'incomeTotal': 1, 'daily': 1,
  7245. 'activedDevRatio': 1
  7246. })
  7247. orderTotal, payIncome, offlineTime, totalTime, totalActivedRate, peakValue = 0, RMB(0.0), 0, 0, 0, 0
  7248. count = 0
  7249. for rcd in rcds:
  7250. count += 1
  7251. daily = rcd.get('daily') or {}
  7252. other = rcd.get('other') or {}
  7253. orderTotal += daily.get('totalIncomeCount', 0)
  7254. payIncome += daily.get('totalIncome', 0)
  7255. offlineTime += other.get('totalOfflineTime', 0)
  7256. totalTime = totalTime + other.get('totalOfflineTime', 0) + other.get('totalOnlineTime', 0) + other.get(
  7257. 'totalOfflineBusyTime', 0)
  7258. totalActivedRate += rcd.get('activedDevRatio', 0)
  7259. dayPeakValue = rcd.get('peakUsage', 0)
  7260. if peakValue <= dayPeakValue:
  7261. peakValue = dayPeakValue
  7262. return {
  7263. 'orderTotal': orderTotal,
  7264. 'payIncome': payIncome,
  7265. 'offlineCoin': offlineCoin,
  7266. 'deviceOfflineCount': int(round(offlineTime / totalTime * 100.0, 2)) if totalTime > 0 else 0,
  7267. # 前台修改后,用设备离线时间占比offlineTime/totalTime * 100
  7268. 'dailyActivityRate': int(round(totalActivedRate / count, 2)) if count > 0 else 0,
  7269. 'peakValue': peakValue
  7270. }
  7271. ownerId = str(request.user.id)
  7272. startDate = str(request.GET.get('startTime'))
  7273. endDate = str(request.GET.get('endTime'))
  7274. pageIndex = int(request.GET.get('pageIndex'))
  7275. pageSize = int(request.GET.get('pageSize'))
  7276. groupIds = Group.get_group_ids_of_dealer(ownerId)
  7277. total = len(groupIds)
  7278. pageGroupIds = groupIds[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  7279. dataList = []
  7280. count = 0
  7281. for groupId in pageGroupIds:
  7282. count += 1
  7283. group = Group.get_group(groupId)
  7284. devList = Device.get_devices_by_group([groupId]).values()
  7285. devCount = len(devList)
  7286. valueDict = calc_group_stats(groupId, startDate, endDate)
  7287. dataList.append({
  7288. 'id':str(groupId),
  7289. 'groupName':group['groupName'],
  7290. 'address':group['address'],
  7291. 'deviceTotal':devCount,
  7292. 'orderTotal':valueDict.get('orderTotal', 0),
  7293. 'payIncome':valueDict.get('payIncome', RMB(0.0)),
  7294. 'offlineCoin':valueDict.get('offlineCoin', 0),
  7295. 'deviceOfflineCount':valueDict.get('deviceOfflineCount', 0),
  7296. 'dailyActivityRate':valueDict.get('dailyActivityRate', 0),
  7297. 'peakValue':valueDict.get('peakValue', 0)
  7298. })
  7299. return JsonOkResponse(payload={'total':total, 'dataList': dataList})
  7300. @error_tolerate(nil=DefaultJsonErrorResponse)
  7301. @permission_required(ROLE.dealer)
  7302. def getOrderTrendByGroup(request):
  7303. groupId = request.GET.get('id')
  7304. todayTime = datetime.datetime.now()
  7305. startDate = request.GET.get('startTime', '')
  7306. if not startDate:
  7307. startTime = todayTime - datetime.timedelta(days=7)
  7308. startDate = startTime.strftime(Const.DATE_FMT)
  7309. endDate = request.GET.get('endTime', '')
  7310. if not endDate:
  7311. endDate = (todayTime + datetime.timedelta(days=1)).strftime(Const.DATE_FMT)
  7312. group_report_dict = GroupReport.get_rpt([groupId], startDate, endDate)
  7313. rcds = GroupDailyStatsModelProxy.get_data_list(startTime=startDate,
  7314. endTime=endDate,
  7315. groupId=ObjectId(groupId),
  7316. only={
  7317. 'daily': 1, 'date': 1
  7318. })
  7319. dataList = []
  7320. for rcd in rcds: # type: GroupDailyStat
  7321. daily = rcd.daily
  7322. dataList.append({
  7323. 'dateStr': rcd.date,
  7324. 'payIncome': daily.get('totalIncome', 0),
  7325. 'orderTotal': daily.get('totalIncomeCount', 0),
  7326. 'offlineCoin': group_report_dict.get(rcd.date, {'lineCoins': 0, 'count': 0}.get('lineCoins', 0))
  7327. })
  7328. return JsonOkResponse(payload={'dataList': dataList})
  7329. @error_tolerate(nil=DefaultJsonErrorResponse)
  7330. @permission_required(ROLE.dealer)
  7331. def getOfflineTrendByGroup(request):
  7332. groupId = request.GET.get('id')
  7333. startDate = request.GET.get('startTime', '')
  7334. endDate = request.GET.get('endTime', '')
  7335. if not startDate:
  7336. todayTime = datetime.datetime.now()
  7337. startTime = todayTime - datetime.timedelta(days=7)
  7338. startDate = startTime.strftime(Const.DATE_FMT)
  7339. endDate = todayTime.strftime(Const.DATE_FMT)
  7340. rcds = GroupDailyStat.get_collection().find({'groupId':ObjectId(groupId), 'date':{'$gte':startDate, '$lte':endDate}}, {'other':1, 'date':1})
  7341. dataList = []
  7342. for rcd in rcds:
  7343. other = rcd.get('other', {})
  7344. offlineTime = other.get('totalOfflineTime', 0)
  7345. totalTime = other.get('totalOfflineTime', 0) + other.get('totalOnlineTime', 0) + other.get('totalOfflineBusyTime', 0)
  7346. dataList.append({
  7347. 'dateStr':rcd['date'],
  7348. 'offlineCount':int(round(offlineTime / totalTime * 100.0, 2)) if totalTime else 0
  7349. })
  7350. return JsonOkResponse(payload={'dataList':dataList})
  7351. @error_tolerate(nil=DefaultJsonErrorResponse)
  7352. @permission_required(ROLE.dealer)
  7353. def dailyActivityTrendByGroup(request):
  7354. groupId = request.GET.get('id')
  7355. startDate = request.GET.get('startTime', '')
  7356. endDate = request.GET.get('endTime', '')
  7357. if not startDate:
  7358. todayTime = datetime.datetime.now()
  7359. startTime = todayTime - datetime.timedelta(days=7)
  7360. startDate = startTime.strftime(Const.DATE_FMT)
  7361. endDate = todayTime.strftime(Const.DATE_FMT)
  7362. rcds = GroupDailyStat.get_collection().find({'groupId':ObjectId(groupId), 'date':{'$gte':startDate, '$lte':endDate}}, {'activedDevRatio':1, 'devCount':1, 'date':1})
  7363. dataList = []
  7364. for rcd in rcds:
  7365. deviceTotal = rcd.get('devCount', 0)
  7366. dataList.append({
  7367. 'dateStr':rcd['date'],
  7368. 'dailyActivity':int(float(rcd.get('activedDevRatio', 0)) / 100.0 * deviceTotal),
  7369. 'deviceTotal':deviceTotal
  7370. })
  7371. return JsonOkResponse(payload={'dataList':dataList})
  7372. @error_tolerate(nil=DefaultJsonErrorResponse)
  7373. @permission_required(ROLE.dealer)
  7374. def getPeakValueTrendByGroup(request):
  7375. groupId = request.GET.get('id')
  7376. startDate = request.GET.get('startTime', '')
  7377. endDate = request.GET.get('endTime', '')
  7378. if not startDate:
  7379. todayTime = datetime.datetime.now()
  7380. startTime = todayTime - datetime.timedelta(days=7)
  7381. startDate = startTime.strftime(Const.DATE_FMT)
  7382. endDate = todayTime.strftime(Const.DATE_FMT)
  7383. rcds = GroupDailyStat.get_collection().find({'groupId':ObjectId(groupId), 'date':{'$gte':startDate, '$lte':endDate}}, {'other':1, 'date':1})
  7384. dataList = []
  7385. hourlyDict = {}
  7386. for rcd in rcds:
  7387. hourly = rcd.get('other', {}).get('hourly', {})
  7388. for hour, value in hourly.items():
  7389. if not hourlyDict.has_key(hour):
  7390. hourlyDict[hour] = {'usageSum':0, 'usageCount':0}
  7391. else:
  7392. hourlyDict[hour]['usageSum'] += value['usageSum']
  7393. hourlyDict[hour]['usageCount'] += value['usageCount']
  7394. for ii in range(24):
  7395. hour = str(ii)
  7396. if hourlyDict.has_key(hour):
  7397. hourValue = hourlyDict[hour]
  7398. dataList.append(
  7399. {'hour':hour, 'usage':int(round(float(hourValue['usageSum']) / float(hourValue['usageCount']), 2)) if hourValue['usageCount'] > 0 else 0 }
  7400. )
  7401. else:
  7402. dataList.append({'hour':hour, 'usage':0})
  7403. return JsonOkResponse(payload={'dataList':dataList})
  7404. @error_tolerate(nil=DefaultJsonErrorResponse)
  7405. @permission_required(ROLE.dealer)
  7406. def getDeviceStatistics(request):
  7407. ownerId = str(request.user.id)
  7408. logicalCode = request.GET.get('searchKey', '')
  7409. startDate = request.GET.get('startTime', '')
  7410. endDate = request.GET.get('endTime', '')
  7411. pageIndex = int(request.GET.get('pageIndex'))
  7412. pageSize = int(request.GET.get('pageSize'))
  7413. if not startDate:
  7414. todayTime = datetime.datetime.now()
  7415. startTime = todayTime - datetime.timedelta(days=7)
  7416. startDate = startTime.strftime(Const.DATE_FMT)
  7417. endDate = todayTime.strftime(Const.DATE_FMT)
  7418. # 找出相关所有设备
  7419. if logicalCode:
  7420. dev_no = Device.get_devNo_by_logicalCode(logicalCode)
  7421. if dev_no:
  7422. devNoList = [dev_no]
  7423. else:
  7424. devNoList = []
  7425. else:
  7426. groupIds = Group.get_group_ids_of_dealer(ownerId)
  7427. tempList = Device.get_devNos_by_group(groupIds)
  7428. total = len(tempList)
  7429. devNoList = tempList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  7430. if not devNoList:
  7431. return JsonOkResponse(payload={'total': 0, 'dataList': []})
  7432. total = len(devNoList)
  7433. dataList = []
  7434. devList = Device.get_dev_by_nos(devNoList, True)
  7435. for dev in devList.values():
  7436. lc = dev['logicalCode']
  7437. devType = dev.get('devType', {}).get('name', '')
  7438. groupName = dev.get('groupInfo', {}).get('groupName', '')
  7439. remarks = dev.get('remarks', '')
  7440. orderTotal, payIncome, deviceOfflineCount, deviceOfflineTimeTotal, peakValue = 0, RMB(0.0), 0, 0, 0
  7441. rcds = DeviceDailyStatsModelProxy.get_data_list(
  7442. startTime=startDate,
  7443. endTime=endDate,
  7444. logicalCode=lc,
  7445. only={'date': 1, 'other': 1, 'daily': 1, 'peakUsage': 1})
  7446. for rcd in rcds:
  7447. daily = rcd.get('daily') or {}
  7448. orderTotal += daily.get('totalIncomeCount', 0)
  7449. payIncome += RMB(daily.get('totalIncome', 0))
  7450. other = rcd.get('other') or {}
  7451. deviceOfflineCount += other.get('offlineCount', 0)
  7452. deviceOfflineTimeTotal += other.get('totalOfflineTime', 0)
  7453. if peakValue <= rcd.get('peakUsage', 0):
  7454. peakValue = rcd.get('peakUsage', 0)
  7455. faultCount = FeedBack.get_collection().find(
  7456. {'logicalCode': lc, 'createTime': {'$gte': startDate, '$lte': endDate}}).count()
  7457. solveFaultCount = FeedBack.get_collection().find(
  7458. {'logicalCode': lc, 'createTime': {'$gte': startDate, '$lte': endDate}, 'status': 1}).count()
  7459. dataList.append({
  7460. 'devType': devType,
  7461. 'orderTotal': orderTotal,
  7462. 'payIncome': payIncome,
  7463. 'remarks': remarks,
  7464. 'deviceOfflineCount': deviceOfflineCount,
  7465. 'deviceOfflineTimeTotal': deviceOfflineTimeTotal / 60,
  7466. 'faultCount': faultCount,
  7467. 'solveFaultCount': solveFaultCount,
  7468. 'peakValue': peakValue,
  7469. 'groupName': groupName,
  7470. 'logicalCode': lc
  7471. })
  7472. return JsonOkResponse(payload={'total': total, 'dataList': dataList})
  7473. @error_tolerate(nil=DefaultJsonErrorResponse)
  7474. @permission_required(ROLE.dealer)
  7475. def getDeviceList(request):
  7476. ownerId = str(request.user.id)
  7477. pageIndex = int(request.GET.get('pageIndex'))
  7478. pageSize = int(request.GET.get('pageSize'))
  7479. groupIds = Group.get_group_ids_of_dealer(ownerId)
  7480. allDevNoList = Device.get_devNos_by_group(groupIds)
  7481. devNoList = allDevNoList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  7482. total = len(allDevNoList)
  7483. dataList = []
  7484. devList = Device.get_dev_by_nos(devNoList, verbose=True)
  7485. for dev in devList.values(): # type: DeviceDict
  7486. if dev.logicalCode == 'G419646':
  7487. monitorUrl = 'http://vod1.ddhlok.com/zzdd/shanghai4.m3u8'
  7488. elif dev.logicalCode == 'G430439':
  7489. monitorUrl = 'http://vod1.ddhlok.com/zzdd/shanghai5.m3u8'
  7490. elif dev.logicalCode == 'G430498':
  7491. monitorUrl = 'http://vod1.ddhlok.com/zzdd/shanghai1.m3u8'
  7492. else:
  7493. monitorUrl = None
  7494. devType = dev.devType.get('name', '')
  7495. dataList.append({
  7496. 'devType' : devType,
  7497. 'online': dev.online,
  7498. 'signal':dev.signal,
  7499. 'remarks':dev.get('remarks', ''),
  7500. 'registrationTime':dev.get('dateTimeAdded', ''),
  7501. 'simExpireDate':dev.fixedSimExpireDate,
  7502. 'groupName':dev.get('groupInfo', {}).get('groupName', ''),
  7503. 'imei':dev.devNo,
  7504. 'iccid':dev.get('iccid', ''),
  7505. 'logicalCode':dev.logicalCode,
  7506. 'monitorUrl':monitorUrl
  7507. })
  7508. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  7509. @error_tolerate(nil=DefaultJsonErrorResponse)
  7510. @permission_required(ROLE.dealer)
  7511. def getDevMapChart(request):
  7512. ownerId = str(request.user.id)
  7513. # 查找出所有已注册的设备
  7514. devList = list(Device.get_collection().find(
  7515. {'ownerId':str(ownerId)},
  7516. {'devNo': 1, 'districtId': 1, '_id': 0, 'logicalCode': 1, 'cycle': 1}
  7517. ))
  7518. districts = dict(Counter([District.get_district(_['districtId']).split(' ')[0] for _ in devList if
  7519. _.has_key('districtId') and District.get_district(_['districtId']) != '']))
  7520. def get_province(pvc):
  7521. if pvc == u'内蒙古自治区':
  7522. pvc = u'内蒙古'
  7523. elif pvc == u'黑龙江省':
  7524. pvc = u'黑龙江'
  7525. else:
  7526. pvc = pvc[0:2]
  7527. return pvc
  7528. dataList = [{'name': get_province(province), 'value': count} for province, count in districts.items()]
  7529. busy = 0
  7530. online = 0
  7531. offline = 0
  7532. deviceDict = {
  7533. _['devNo']: {'logicalCode': _['logicalCode'], 'cycle': _.get('cycle', Const.DEV_CYCLE_DEFAULT)} for
  7534. _ in devList}
  7535. for item in Device.get_many_device_status_cache(deviceDict).values():
  7536. device = DeviceDict(item) # type: DeviceDict
  7537. if device.status == 1:
  7538. busy += 1
  7539. if device.online == 1:
  7540. online += 1
  7541. elif device.online == 0:
  7542. offline += 1
  7543. return JsonResponse({'result': 1, 'description': u"", 'payload': {
  7544. "busy": busy,
  7545. "online": online,
  7546. "offline": offline,
  7547. "unregistered":0,
  7548. "dataList": dataList
  7549. }})
  7550. @error_tolerate(nil=DefaultJsonErrorResponse)
  7551. @permission_required(ROLE.dealer)
  7552. def getDeviceTrend(request):
  7553. ownerId = str(request.user.id)
  7554. startDate = request.GET.get('startTime', '')
  7555. endDate = request.GET.get('endTime', '')
  7556. if not startDate:
  7557. todayTime = datetime.datetime.now()
  7558. startTime = todayTime - datetime.timedelta(days=7)
  7559. startDate = startTime.strftime(Const.DATE_FMT)
  7560. endDate = todayTime.strftime(Const.DATE_FMT)
  7561. dataList = []
  7562. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7563. endTime=endDate,
  7564. dealerId=ObjectId(ownerId),
  7565. only={'date': 1, 'devCount': 1, 'activedDevRatio': 1})
  7566. for record in records:
  7567. devCount = record.get('devCount', 0)
  7568. activedRatio = record.get('activedDevRatio', 0)
  7569. dataList.append({
  7570. 'dateStr': record['date'],
  7571. 'deviceTotal': devCount,
  7572. 'active': int(round(devCount * activedRatio / 100.0, 2))
  7573. })
  7574. return JsonOkResponse(payload={'dataList': dataList})
  7575. @error_tolerate(nil=DefaultJsonErrorResponse)
  7576. @permission_required(ROLE.dealer)
  7577. def getAllFeedbackStatistics(request):
  7578. feedBacks = list(FeedBack.get_collection().find(
  7579. {'ownerId': request.user.id},
  7580. {'_id': 0, 'feedType': 1, 'status': 1}
  7581. ))
  7582. fault = [_['status'] for _ in feedBacks if _['feedType'] == 'fault']
  7583. faultProcessed = [_ for _ in fault if _ == 1]
  7584. upper = [_['status'] for _ in feedBacks if _['feedType'] == 'upper']
  7585. upperProcessed = [_ for _ in upper if _ == 1]
  7586. refund = [_['status'] for _ in feedBacks if _['feedType'] == 'refund']
  7587. refundProcessed = [_ for _ in refund if _ == 1]
  7588. return JsonResponse({'result': 1, 'description': None, 'payload': {
  7589. "faultCount": len(fault),
  7590. "faultProcessedCount": len(faultProcessed),
  7591. "upperCount": len(upper),
  7592. "upperProcessedCount": len(upperProcessed),
  7593. "refundCount": len(refund),
  7594. "refundProcessedCount": len(refundProcessed)
  7595. }})
  7596. @error_tolerate(nil=DefaultJsonErrorResponse)
  7597. @permission_required(ROLE.dealer)
  7598. def getDeviceNetworkTrend(request):
  7599. ownerId = str(request.user.id)
  7600. startDate = request.GET.get('startTime', '')
  7601. endDate = request.GET.get('endTime', '')
  7602. if not startDate:
  7603. todayTime = datetime.datetime.now()
  7604. startTime = todayTime - datetime.timedelta(days=7)
  7605. startDate = startTime.strftime(Const.DATE_FMT)
  7606. endDate = todayTime.strftime(Const.DATE_FMT)
  7607. dataList = []
  7608. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7609. endTime=endDate,
  7610. dealerId=ObjectId(ownerId),
  7611. only={'date': 1, 'other': 1})
  7612. for rcd in records:
  7613. other = rcd.get('other') or {}
  7614. dataList.append({
  7615. 'dateStr': rcd['date'],
  7616. 'online': other.get('totalOnlineTime', 0) + other.get('totalOfflineBusyTime', 0),
  7617. 'offline': other.get('totalOfflineTime', 0)
  7618. })
  7619. return JsonOkResponse(payload={'dataList': dataList})
  7620. @error_tolerate(nil=DefaultJsonErrorResponse)
  7621. @permission_required(ROLE.dealer)
  7622. def getPackageUsageFrequency(request):
  7623. ownerId = str(request.user.id)
  7624. startDate = request.GET.get('startTime', '')
  7625. endDate = request.GET.get('endTime', '')
  7626. if not startDate:
  7627. todayTime = datetime.datetime.now()
  7628. startTime = todayTime - datetime.timedelta(days=7)
  7629. startDate = startTime.strftime(Const.DATE_FMT)
  7630. endDate = todayTime.strftime(Const.DATE_FMT)
  7631. packageDict = {}
  7632. totalCount = 0
  7633. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7634. endTime=endDate,
  7635. dealerId=ObjectId(ownerId),
  7636. only={'date': 1, 'other': 1})
  7637. for rcd in records:
  7638. package = (rcd.get('other') or {}).get('package', {})
  7639. for coin, count in package.items():
  7640. try:
  7641. totalCount += count
  7642. if not packageDict.has_key(str(coin)):
  7643. packageDict[str(coin)] = count
  7644. else:
  7645. packageDict[str(coin)] += count
  7646. except Exception, e:
  7647. continue
  7648. dataList = []
  7649. for coin, count in packageDict.items():
  7650. dataList.append({
  7651. 'name': u'%s元' % round(float(coin) / 100.0, 2),
  7652. 'percent': round(float(count) / float(totalCount) * 100.0, 1) if totalCount > 0 else 100
  7653. }
  7654. )
  7655. return JsonOkResponse(payload={'dataList': dataList})
  7656. @error_tolerate(nil=DefaultJsonErrorResponse)
  7657. @permission_required(ROLE.dealer)
  7658. def getIncomeTrend(request):
  7659. ownerId = str(request.user.id)
  7660. startDate = request.GET.get('startTime', '')
  7661. endDate = request.GET.get('endTime', '')
  7662. if not startDate:
  7663. todayTime = datetime.datetime.now()
  7664. startTime = todayTime - datetime.timedelta(days=7)
  7665. startDate = startTime.strftime(Const.DATE_FMT)
  7666. endDate = todayTime.strftime(Const.DATE_FMT)
  7667. offlineCoinsDict = {r['date']: r.get('lineCoins', 0) for r in DealerReport.get_rpts(ownerId, startDate, endDate)}
  7668. dataList = []
  7669. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7670. endTime=endDate,
  7671. dealerId=ObjectId(ownerId),
  7672. only={'date': 1, 'daily': 1})
  7673. for rcd in records:
  7674. daily = rcd.get('daily') or {}
  7675. date = rcd['date']
  7676. dataList.append({
  7677. 'dateStr': date,
  7678. 'offlineCoin': offlineCoinsDict.get(date, 0),
  7679. 'payIncome': daily.get('totalIncome', 0)
  7680. })
  7681. return JsonOkResponse(payload={'dataList': dataList})
  7682. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取收益趋势失败"))
  7683. @permission_required(ROLE.dealer)
  7684. def getConsumptionTrend(request):
  7685. ownerId = str(request.user.id)
  7686. startDate = request.GET.get('startTime', '')
  7687. endDate = request.GET.get('endTime', '')
  7688. if not startDate:
  7689. todayTime = datetime.datetime.now()
  7690. startTime = todayTime - datetime.timedelta(days=7)
  7691. startDate = startTime.strftime(Const.DATE_FMT)
  7692. endDate = todayTime.strftime(Const.DATE_FMT)
  7693. dataList = []
  7694. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7695. endTime=endDate,
  7696. dealerId=ObjectId(ownerId),
  7697. only={'date': 1, 'daily': 1})
  7698. for rcd in records:
  7699. consumptionDict = (rcd.get('daily') or {}).get('consumption', {})
  7700. date = rcd['date']
  7701. itemList = []
  7702. for kind, value in consumptionDict.items():
  7703. if kind not in DEALER_CONSUMPTION_AGG_KIND.choices():
  7704. continue
  7705. itemList.append({
  7706. 'name': DEALER_CONSUMPTION_AGG_KIND_TRANSLATION[kind],
  7707. 'value': value,
  7708. 'unit': DEALER_CONSUMPTION_AGG_KIND_UNIT[kind],
  7709. })
  7710. dataList.append({
  7711. 'dateStr': date,
  7712. 'items': itemList,
  7713. })
  7714. return JsonOkResponse(payload={'dataList': dataList})
  7715. @error_tolerate(nil=DefaultJsonErrorResponse)
  7716. @permission_required(ROLE.dealer)
  7717. def getOrderTrend(request):
  7718. ownerId = str(request.user.id)
  7719. startDate = request.GET.get('startTime', '')
  7720. endDate = request.GET.get('endTime', '')
  7721. if not startDate:
  7722. todayTime = datetime.datetime.now()
  7723. startTime = todayTime - datetime.timedelta(days=7)
  7724. startDate = startTime.strftime(Const.DATE_FMT)
  7725. endDate = todayTime.strftime(Const.DATE_FMT)
  7726. hourlyDict = {}
  7727. records = DealerDailyStatsModelProxy.get_data_list(startTime=startDate,
  7728. endTime=endDate,
  7729. dealerId=ObjectId(ownerId),
  7730. only={'date': 1, 'hourly': 1})
  7731. for rcd in records:
  7732. hourly = rcd.get('hourly') or {}
  7733. for hour, value in hourly.items():
  7734. if not hourlyDict.has_key(hour):
  7735. hourlyDict[hour] = VirtualCoin(value.get('consumption', {}).get('coin', 0))
  7736. else:
  7737. hourlyDict[hour] += VirtualCoin(value.get('consumption', {}).get('coin', 0))
  7738. dataList = []
  7739. for ii in range(24):
  7740. hour = str(ii)
  7741. order = 0
  7742. if hourlyDict.has_key(hour):
  7743. order = hourlyDict.get(hour)
  7744. dataList.append({
  7745. 'dateStr':u'%s时' % hour,
  7746. 'order':str(order)
  7747. })
  7748. return JsonOkResponse(payload={'dataList':dataList})
  7749. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取收益列表失败"))
  7750. @permission_required(ROLE.dealer)
  7751. def getIncomeOrderList(request):
  7752. ownerId = str(request.user.id)
  7753. startTime = request.GET.get("startTime")
  7754. endTime = request.GET.get("endTime")
  7755. pageIndex = int(request.GET.get("pageIndex"))
  7756. pageSize = int(request.GET.get("pageSize"))
  7757. groupId = request.GET.get("groupId")
  7758. logicalCode = request.GET.get("logicalCode")
  7759. phoneNumber = request.GET.get("phoneNumber")
  7760. filters = {
  7761. "ownerId": ownerId,
  7762. "via__nin": [RechargeRecordVia.SendCoin, RechargeRecordVia.Refund]
  7763. }
  7764. if groupId:
  7765. filters.update({"groupId": groupId})
  7766. if logicalCode:
  7767. filters.update({"logicalCode": logicalCode})
  7768. # 如果存在phoneNumber,则是单一查找人
  7769. if phoneNumber:
  7770. phoneOwner = MyUser.objects.filter(phoneNumber=phoneNumber).first()
  7771. if phoneOwner:
  7772. filters.update({"openId": phoneOwner.openId})
  7773. records = RechargeRecord.objects.filter(
  7774. dateTimeAdded__gte=to_datetime(startTime, "%Y-%m-%d"),
  7775. dateTimeAdded__lt=to_datetime(endTime, "%Y-%m-%d"),
  7776. **filters
  7777. ) # type: CustomQuerySet
  7778. total = records.count()
  7779. # 这个地方的数据一定是按照年进行分型的
  7780. dataList = list()
  7781. for rcd in records.paginate(pageIndex, pageSize):
  7782. try:
  7783. user = MyUser.objects.filter(openId=rcd.openId).only("openId", "gateWay", "productAgentId", "sex", "nickname").first()
  7784. if user.sex == 0:
  7785. sex = u"女"
  7786. elif user.sex == 1:
  7787. sex = u"男"
  7788. else:
  7789. sex = ""
  7790. userNickname = "{}-{}".format(user.nickname, user.phone) if user.phone else user.nickname
  7791. data = {
  7792. "id": str(rcd.id),
  7793. "orderAmount": str(rcd.amount),
  7794. "tradeType": RECHARGE_RECORD_VIA_TRANSLATION.get(rcd.via, "-"),
  7795. "gateway": rcd.gateway,
  7796. "status": rcd.result,
  7797. "userNickname": userNickname,
  7798. "userGender": sex,
  7799. "groupName": rcd.groupName,
  7800. "logicalCode": rcd.logicalCode,
  7801. "devTypeName": rcd.dev_type_name,
  7802. "createdTime": rcd.dateTimeAdded,
  7803. "gatewayTradeNo": rcd.wxOrderNo,
  7804. 'outTradeNo': rcd.orderNo
  7805. }
  7806. except Exception as e:
  7807. logger.exception("record no is {}, error is".format(rcd.orderNo, e))
  7808. continue
  7809. else:
  7810. dataList.append(data)
  7811. return JsonOkResponse(payload={"total": total, "dataList": dataList})
  7812. @permission_required(ROLE.dealer, ROLE.subaccount)
  7813. def getConsumptionOrderList(request):
  7814. """
  7815. 经销商PC端 对于 消费订单列表的获取
  7816. :param request:
  7817. :return:
  7818. """
  7819. ownerId = str(request.user.id)
  7820. startDate = request.GET.get('startTime')
  7821. endDate = request.GET.get('endTime')
  7822. pageIndex = int(request.GET.get('pageIndex', 1))
  7823. pageSize = int(request.GET.get('pageSize', 10))
  7824. groupId = str(request.GET.get('groupId'))
  7825. logicalCode = request.GET.get('logicalCode')
  7826. phoneNumber = request.GET.get("phoneNumber")
  7827. _type = request.GET.get("consumeType") # /netPay/cardPay/ 启动方式应该是只有 扫码启动 以及刷卡启动
  7828. dataList = []
  7829. filters = {
  7830. "ownerId": ownerId,
  7831. "isNormal": True
  7832. }
  7833. if _type == "cardPay":
  7834. filters.update({"remarks": u"刷卡消费"})
  7835. elif _type == "netPay":
  7836. filters.update({"remarks__ne": u"刷卡消费"})
  7837. else:
  7838. pass
  7839. if groupId:
  7840. filters.update({"groupId": groupId})
  7841. if logicalCode:
  7842. filters.update({"logicalCode": logicalCode})
  7843. if phoneNumber:
  7844. phoneOwner = MyUser.objects.filter(phoneNumber=phoneNumber).first()
  7845. if phoneOwner:
  7846. filters.update({"openId": phoneOwner.openId})
  7847. records = ConsumeRecord.objects.filter(
  7848. dateTimeAdded__gte=startDate,
  7849. dateTimeAdded__lt=endDate,
  7850. **filters
  7851. )
  7852. # records = ConsumeRecord.get_data_list(startTime=startDate,
  7853. # endTime=endDate,
  7854. # **filters) # type: CustomQuerySet
  7855. count = records.count()
  7856. for rcd in records.paginate(pageIndex, pageSize): # type: ConsumeRecord
  7857. try:
  7858. user = MyUser.objects.filter(openId=rcd.openId).only('openId', 'nickname', 'sex', 'groupId', "productAgentId", "gateWay").first()
  7859. sex = ''
  7860. if user.sex == 0:
  7861. sex = u'女'
  7862. elif user.sex == 1:
  7863. sex = u'男'
  7864. else:
  7865. pass
  7866. desc = ''
  7867. for key, value in rcd.servicedInfo.items():
  7868. if key not in DEALER_CONSUMPTION_AGG_KIND_TRANSLATION:
  7869. continue
  7870. desc += " %s:%s%s" % (DEALER_CONSUMPTION_AGG_KIND_TRANSLATION.get(key), value, DEALER_CONSUMPTION_AGG_KIND_UNIT.get(key))
  7871. port = rcd.attachParas.get("chargeIndex", None)
  7872. lc = rcd.logicalCode
  7873. lcp = "{logicalCode}-{port}".format(logicalCode=lc, port=port) if port else lc
  7874. userNickname = "{}-{}".format(user.nickname, user.phone) if user.phone else user.nickname
  7875. # 添加订单判断启动方式
  7876. isQuickPay = u'金币启动'
  7877. if rcd.recharge_record_id:
  7878. obj = RechargeRecord.objects.filter(id = str(rcd.recharge_record_id)).first() or RechargeRecord(
  7879. isQuickPay = False)
  7880. isQuickPay = u'快捷支付' if obj.isQuickPay else isQuickPay
  7881. data = {
  7882. 'id': str(rcd.id),
  7883. 'createdTime': rcd.created_date,
  7884. 'title': desc,
  7885. 'userNickname': userNickname,
  7886. 'userGender': sex,
  7887. 'groupName': rcd.groupName,
  7888. 'logicalCode': lcp,
  7889. 'devTypeName': rcd.dev_type_name,
  7890. 'amount': rcd.coin,
  7891. 'payType': isQuickPay
  7892. }
  7893. dataList.append(data)
  7894. except Exception as e:
  7895. continue
  7896. return JsonOkResponse(payload={"dataList": dataList, "total": count})
  7897. @error_tolerate(nil=DefaultJsonErrorResponse)
  7898. @permission_required(ROLE.dealer)
  7899. def getAPIOrderList(request):
  7900. ownerId = str(request.user.id)
  7901. startDate = request.GET.get('startTime', '')
  7902. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  7903. pageIndex = int(request.GET.get('pageIndex'))
  7904. pageSize = int(request.GET.get('pageSize'))
  7905. groupId = str(request.GET.get('groupId'))
  7906. logicalCode = request.GET.get('logicalCode')
  7907. if logicalCode:
  7908. devNoList = [Device.get_devNo_by_logicalCode(logicalCode)]
  7909. elif groupId:
  7910. devNoList = Device.get_devNos_by_group([groupId])
  7911. else:
  7912. devNoList = None
  7913. if devNoList:
  7914. rcds = APIStartDeviceRecord.objects(ownerId=ownerId, devNo__in=devNoList,
  7915. errCode=0, datetimeAdded__gte=startDate,
  7916. datetimeAdded__lte=endDate).order_by('-datetimeAdded')
  7917. else:
  7918. rcds = APIStartDeviceRecord.objects(ownerId=ownerId, errCode=0,
  7919. datetimeAdded__gte=startDate,
  7920. datetimeAdded__lte=endDate).order_by('-datetimeAdded')
  7921. dataList = [{
  7922. 'createdTime': _.datetimeAdded,
  7923. 'extOrderNo': _.attachParas.get('extOrderNo', '-'),
  7924. 'userId': _['userId'],
  7925. 'needTime': _.package.get('time', '-'),
  7926. 'backCoins': _.servicedInfo.get('backCoins', '-'),
  7927. 'spendElec': _.servicedInfo.get('spendElec', '-'),
  7928. 'amount': _.package.get('price', '-'),
  7929. 'groupName': Group.get_groupName_by_logicalCode(_.deviceCode),
  7930. 'devTypeName': _.servicedInfo.get('spendElec', '-'),
  7931. 'logicalCode': _.deviceCode
  7932. } for _ in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize)]
  7933. return JsonOkResponse(payload={'dataList': dataList, 'total': rcds.count()})
  7934. @error_tolerate(nil=DefaultJsonErrorResponse)
  7935. @permission_required(ROLE.dealer)
  7936. def getOnPointsOrderList(request):
  7937. ownerId = str(request.user.id)
  7938. startDate = request.GET.get('startTime', '')
  7939. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  7940. pageIndex = int(request.GET.get('pageIndex'))
  7941. pageSize = int(request.GET.get('pageSize'))
  7942. groupId = str(request.GET.get('groupId'))
  7943. logicalCode = request.GET.get('logicalCode')
  7944. filters = {
  7945. "ownerId": ownerId,
  7946. "time__gte": startDate,
  7947. "time__lte": endDate
  7948. }
  7949. if logicalCode:
  7950. # devNoList = [Device.get_devNo_by_logicalCode(logicalCode)]
  7951. filters.update({"devNo": Device.get_devNo_by_logicalCode(logicalCode)})
  7952. elif groupId:
  7953. devNoList = Device.get_devNos_by_group([groupId])
  7954. filters.update({"devNo__in": devNoList})
  7955. else:
  7956. devNoList = None
  7957. rcds = UpscoreRecord.objects(**filters).order_by('-time')
  7958. dataList = [{
  7959. 'createdTime': _.time,
  7960. 'groupName': _.groupName,
  7961. 'onPoints': str(_.score),
  7962. 'logicalCode': _.logicalCode
  7963. } for _ in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize)]
  7964. return JsonOkResponse(payload={'dataList': dataList, 'total': rcds.count()})
  7965. @error_tolerate(nil=DefaultJsonErrorResponse)
  7966. @permission_required(ROLE.dealer)
  7967. def getSendCoinsToCardOrderList(request):
  7968. ownerId = str(request.user.id)
  7969. startDate = request.GET.get('startTime', '') + ' 00:00:00'
  7970. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  7971. pageIndex = int(request.GET.get('pageIndex'))
  7972. pageSize = int(request.GET.get('pageSize'))
  7973. startDateTime = datetime.datetime.strptime(startDate, '%Y-%m-%d %H:%M:%S')
  7974. endDateTime = datetime.datetime.strptime(endDate, '%Y-%m-%d %H:%M:%S')
  7975. filters = {
  7976. "ownerId": ownerId,
  7977. "dateTimeAdded__gte": startDateTime,
  7978. "dateTimeAdded__lte": endDateTime
  7979. }
  7980. rcds = UpCardScoreRecord.objects(**filters).order_by('-dateTimeAdded')
  7981. dataList = []
  7982. for rcd in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize):
  7983. if rcd.address != '':
  7984. groupName = rcd.address
  7985. else:
  7986. card = Card.objects.get(cardNo=rcd.cardNo)
  7987. groupId = card.groupId
  7988. if groupId:
  7989. groupName = Group.get_group(groupId).groupName
  7990. else:
  7991. groupName = ''
  7992. dataDict = {
  7993. 'cardNo':rcd.cardNo,
  7994. 'score':str(rcd.score),
  7995. 'groupName':groupName,
  7996. 'remark': rcd.remark,
  7997. 'createdTime': rcd.dateTimeAdded.strftime('%Y-%m-%d %H:%M:%S')
  7998. }
  7999. dataList.append(dataDict)
  8000. # dataList = [{
  8001. # 'cardNo': _.cardNo,
  8002. # 'score': str(_.score),
  8003. # 'remark': _.remark,
  8004. # 'createdTime': _.dateTimeAdded.strftime('%Y-%m-%d %H:%M:%S')
  8005. # } for _ in rcds.skip((pageIndex - 1) * pageSize).limit(pageSize)]
  8006. return JsonOkResponse(payload={'dataList': dataList, 'total': rcds.count()})
  8007. @error_tolerate(nil=DefaultJsonErrorResponse)
  8008. @permission_required(ROLE.dealer, ROLE.subaccount)
  8009. def getSignalTrendByDevice(request):
  8010. strStartTime = request.GET.get('startTime')
  8011. strEndTime = request.GET.get('endTime')
  8012. startTime = to_datetime(strStartTime)
  8013. endTime = to_datetime(strEndTime)
  8014. logicalCode = request.GET.get('logicalCode')
  8015. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  8016. nowTime = datetime.datetime.now()
  8017. dataList = []
  8018. checkTime = nowTime - datetime.timedelta(days=7)
  8019. tempStartTime = get_zero_time(checkTime)
  8020. values = SignalManager.instence().get(devNo, tempStartTime, nowTime)
  8021. if values is not None:
  8022. for value in values:
  8023. timePoint = to_datetime(value['time'])
  8024. if timePoint >= startTime and timePoint <= endTime:
  8025. dataList.append('%s=%s' % (value['time'], value['signal']))
  8026. # 去重下,然后重新按照时间排序
  8027. resultList = []
  8028. for data in dataList:
  8029. tempList = data.split('=')
  8030. resultList.append({
  8031. 'dateStr':tempList[0],
  8032. 'signal':tempList[1]
  8033. })
  8034. return JsonOkResponse(payload={'dataList':resultList})
  8035. @error_tolerate(nil=DefaultJsonErrorResponse)
  8036. @permission_required(ROLE.dealer)
  8037. def getPeakValueTrendByDevice(request):
  8038. logicalCode = request.GET.get('logicalCode')
  8039. startDate = request.GET.get('startTime', '')
  8040. endDate = request.GET.get('endTime', '')
  8041. if not startDate:
  8042. todayTime = datetime.datetime.now()
  8043. startTime = todayTime - datetime.timedelta(days=7)
  8044. startDate = startTime.strftime(Const.DATE_FMT)
  8045. endDate = todayTime.strftime(Const.DATE_FMT)
  8046. rcds = DeviceDailyStat.get_collection().find({'logicalCode':logicalCode, 'date':{'$gte':startDate, '$lte':endDate}}, {'other':1, 'date':1})
  8047. dataList = []
  8048. hourlyDict = {}
  8049. for rcd in rcds:
  8050. hourly = rcd.get('other', {}).get('hourly', {})
  8051. for hour, value in hourly.items():
  8052. if not hourlyDict.has_key(hour):
  8053. hourlyDict[hour] = {'usageSum':0, 'usageCount':0}
  8054. else:
  8055. hourlyDict[hour]['usageSum'] += value['usageSum']
  8056. hourlyDict[hour]['usageCount'] += value['usageCount']
  8057. for ii in range(24):
  8058. hour = str(ii)
  8059. if hourlyDict.has_key(hour):
  8060. hourValue = hourlyDict[hour]
  8061. dataList.append(
  8062. {'hour':hour, 'usage':int(round(float(hourValue['usageSum']) / float(hourValue['usageCount']), 2)) if hourValue['usageCount'] > 0 else 0 }
  8063. )
  8064. else:
  8065. dataList.append({'hour':hour, 'usage':0})
  8066. return JsonOkResponse(payload={'dataList':dataList})
  8067. @error_tolerate(nil=DefaultJsonErrorResponse)
  8068. @permission_required(ROLE.dealer)
  8069. def getOrderStatistics(request):
  8070. ownerId = str(request.user.id)
  8071. startDate = request.GET.get('startTime', '') + ' 00:00:00'
  8072. endDate = request.GET.get('endTime', '') + ' 23:59:59'
  8073. groupId = str(request.GET.get('groupId'))
  8074. logicalCode = request.GET.get('logicalCode')
  8075. devNoList = []
  8076. if logicalCode:
  8077. devNoList = [Device.get_devNo_by_logicalCode(logicalCode)]
  8078. elif groupId:
  8079. devNoList = Device.get_devNos_by_group([groupId])
  8080. else:
  8081. groupIds = Group.get_group_ids_of_dealer(ownerId)
  8082. devNoList = Device.get_devNos_by_group(groupIds)
  8083. rcds = RechargeRecord.objects(ownerId=ownerId,
  8084. devNo__in=devNoList,
  8085. result='success',
  8086. dateTimeAdded__gte=to_datetime(startDate),
  8087. dateTimeAdded__lte=to_datetime(endDate))
  8088. sexDict, orderTypeDict = {'0':0, '1':0, '2':0}, {'recharge':0, 'chargeCard':0, 'chargeVirtualCard':0}
  8089. hourDict = {}
  8090. for hour in range(24):
  8091. hourDict[str(hour)] = 0
  8092. openIdList = []
  8093. orderTotal, orderPayAmount, userCount = 0, RMB(0.0), 0
  8094. for rcd in rcds:
  8095. openIdList.append((rcd.openId, rcd.groupId))
  8096. if rcd.via in orderTypeDict:
  8097. orderTypeDict[rcd.via] += 1
  8098. hourDict[str(rcd.dateTimeAdded.hour)] += 1
  8099. orderTotal += 1
  8100. orderPayAmount += rcd.money
  8101. orderTrend = [{'dateStr':u'%s时' % k, 'order':v } for k, v in hourDict.items()]
  8102. openIdSetList = list(set(openIdList))
  8103. userCount = 0
  8104. for userID in openIdSetList:
  8105. try:
  8106. user = MyUser.objects.filter(openId=userID[0] , groupId=userID[1]).only('openId', 'nickname', 'sex', 'groupId').first()
  8107. sexDict[str(user.sex)] += 1
  8108. userCount += 1
  8109. except Exception, e:
  8110. continue
  8111. payload = {
  8112. 'orderTotal' : orderTotal,
  8113. 'orderPayAmount':orderPayAmount,
  8114. 'userCount':userCount,
  8115. 'userStatistics':{
  8116. 'other':sexDict['2'],
  8117. 'femaleCount':sexDict['0'],
  8118. 'maleCount':sexDict['1'],
  8119. },
  8120. 'orderTypeStatistics':orderTypeDict,
  8121. 'orderTrend':orderTrend
  8122. }
  8123. return JsonOkResponse(payload=payload)
  8124. @permission_required(ROLE.dealer)
  8125. def exportIncomeOrderList(request):
  8126. dealer = request.user # type: Dealer
  8127. def get_offline_task_name(task_type, user, **kwargs):
  8128. # type: (basestring, Dealer, Dict)->basestring
  8129. tmp_list = [task_type, user.username]
  8130. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8131. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8132. if 'groupId' in kwargs and kwargs['groupId']:
  8133. address = Group.get_group(kwargs['groupId']).get('address', '')
  8134. tmp_list.append(u'地址_%s' % (address,))
  8135. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8136. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8137. return '-'.join(tmp_list).replace("/", "_")
  8138. query_dict = {
  8139. 'startTime': request.GET.get('startTime', ''),
  8140. 'endTime': request.GET.get('endTime', ''),
  8141. 'ownerId': str(dealer.id),
  8142. 'groupId': str(request.GET.get('groupId', '')),
  8143. 'logicalCode': request.GET.get('logicalCode'),
  8144. 'phoneNumber': request.GET.get("phoneNumber")
  8145. }
  8146. query_dict = {k: v for k, v in query_dict.items() if v}
  8147. offline_task_name = get_offline_task_name(
  8148. task_type=OfflineTaskType.CHARGE_ORDER_REPORT,
  8149. user=dealer,
  8150. **query_dict)
  8151. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8152. process_func_name='export_charge_order_excel_from_db',
  8153. task_type=OfflineTaskType.CHARGE_ORDER_REPORT,
  8154. userid=str(dealer.id),
  8155. role=ROLE.dealer)
  8156. logger.info('start making charge report=%s' % file_path)
  8157. task_caller(str(offline_task.process_func_name),
  8158. offline_task_id=str(offline_task.id),
  8159. filepath=file_path,
  8160. queryDict=query_dict)
  8161. return JsonResponse({
  8162. 'result': 1,
  8163. 'description': u"请前往离线任务查看任务处理情况",
  8164. 'payload': str(offline_task.id)
  8165. })
  8166. @permission_required(ROLE.dealer)
  8167. def exportIncomeAggregate(request):
  8168. dealer = request.user
  8169. startTime = request.GET.get("startTime")
  8170. endTime = request.GET.get("endTime")
  8171. groupId = request.GET.get("groupId")
  8172. aggregateType = request.GET.get("aggregateType")
  8173. groupIds = [_id for _id in Group.get_group_ids_of_dealer_and_partner(ownerId=str(dealer.id)) if
  8174. not groupId or _id == groupId]
  8175. queryDict = {
  8176. "groupId__in": groupIds,
  8177. "startTime": startTime,
  8178. "endTime": endTime
  8179. }
  8180. def get_offline_task_name(task_type, user, **kwargs):
  8181. # type: (basestring, Dealer, Dict)->basestring
  8182. tmp_list = [task_type, user.username]
  8183. if 'groupId' in kwargs and kwargs['groupId']:
  8184. address = Group.get_group(kwargs['groupId']).get('address', '')
  8185. tmp_list.append(u'地址_%s' % (address,))
  8186. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8187. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8188. return '-'.join(tmp_list).replace("/", "_")
  8189. offline_task_name = get_offline_task_name(
  8190. task_type=OfflineTaskType.INCOME_AGGREGATE,
  8191. user=dealer,
  8192. groupId=groupId,
  8193. **queryDict)
  8194. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8195. process_func_name='export_aggregate_dealer_income',
  8196. task_type=OfflineTaskType.INCOME_AGGREGATE,
  8197. userid=str(dealer.id),
  8198. role=ROLE.dealer)
  8199. logger.info('start making charge report=%s' % file_path)
  8200. task_caller(str(offline_task.process_func_name),
  8201. offline_task_id=str(offline_task.id),
  8202. filePath=file_path,
  8203. queryDict=queryDict,
  8204. aggregateType=aggregateType)
  8205. return JsonResponse({
  8206. 'result': 1,
  8207. 'description': u"请前往离线任务查看任务处理情况",
  8208. 'payload': str(offline_task.id)
  8209. })
  8210. @permission_required(ROLE.dealer)
  8211. def exportConsumptionOrderList(request):
  8212. dealer = request.user # type: Dealer
  8213. def get_offline_task_name(task_type, user, **kwargs):
  8214. # type: (basestring, Dealer, Dict)->basestring
  8215. tmp_list = [task_type, user.username]
  8216. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8217. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8218. if 'groupId' in kwargs and kwargs['groupId']:
  8219. address = Group.get_group(kwargs['groupId']).get('address', '')
  8220. tmp_list.append(u'地址_%s' % (address,))
  8221. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8222. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8223. return '-'.join(tmp_list).replace("/", "_")
  8224. query_dict = {
  8225. 'startTime': request.GET.get('startTime', ''),
  8226. 'endTime': request.GET.get('endTime', ''),
  8227. 'ownerId': str(dealer.id),
  8228. 'groupId': request.GET.get('groupId'),
  8229. 'logicalCode': request.GET.get('logicalCode')
  8230. }
  8231. query_dict = {k: v for k, v in query_dict.items()}
  8232. offline_task_name = get_offline_task_name(
  8233. task_type=OfflineTaskType.CONSUMPTION_ORDER_REPORT,
  8234. user=dealer,
  8235. **query_dict)
  8236. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8237. process_func_name='export_consume_order_excel_from_db',
  8238. task_type=OfflineTaskType.CONSUMPTION_ORDER_REPORT,
  8239. userid=str(dealer.id),
  8240. role=ROLE.dealer)
  8241. logger.info('start making consume report=%s' % file_path)
  8242. task_caller(func_name=offline_task.process_func_name,
  8243. offline_task_id=str(offline_task.id),
  8244. filepath=file_path,
  8245. queryDict=query_dict)
  8246. return JsonResponse({
  8247. 'result': 1,
  8248. 'description': u"请前往离线任务查看任务处理情况",
  8249. 'payload': str(offline_task.id)})
  8250. @permission_required(ROLE.dealer)
  8251. def exportAPIOrderList(request):
  8252. dealer = request.user # type: Dealer
  8253. def get_offline_task_name(task_type, user, **kwargs):
  8254. # type: (basestring, Dealer, Dict)->basestring
  8255. tmp_list = [task_type, user.username]
  8256. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8257. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8258. if 'groupId' in kwargs and kwargs['groupId']:
  8259. address = Group.get_group(kwargs['groupId']).get('address', '')
  8260. tmp_list.append(u'地址_%s' % (address,))
  8261. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8262. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8263. return '-'.join(tmp_list).replace("/", "_")
  8264. query_dict = {
  8265. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8266. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8267. 'ownerId': str(dealer.id),
  8268. 'groupId': str(request.GET.get('groupId', '')),
  8269. 'logicalCode': request.GET.get('logicalCode')
  8270. }
  8271. offline_task_name = get_offline_task_name(
  8272. task_type=OfflineTaskType.API_ORDER_REPORT,
  8273. user=dealer,
  8274. **query_dict)
  8275. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8276. process_func_name='export_API_order_excel_from_db',
  8277. task_type=OfflineTaskType.API_ORDER_REPORT,
  8278. userid=str(dealer.id),
  8279. role=ROLE.dealer)
  8280. logger.info('start making API report=%s' % file_path)
  8281. task_caller(func_name=offline_task.process_func_name,
  8282. offline_task_id=str(offline_task.id),
  8283. filepath=file_path,
  8284. queryDict=query_dict)
  8285. return JsonResponse({
  8286. 'result': 1,
  8287. 'description': u"请前往离线任务查看任务处理情况",
  8288. 'payload': str(offline_task.id)})
  8289. @permission_required(ROLE.dealer)
  8290. def exportOnPointsOrderList(request):
  8291. dealer = request.user # type: Dealer
  8292. def get_offline_task_name(task_type, user, **kwargs):
  8293. # type: (basestring, Dealer, Dict)->basestring
  8294. tmp_list = [task_type, user.username]
  8295. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8296. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8297. if 'groupId' in kwargs and kwargs['groupId']:
  8298. address = Group.get_group(kwargs['groupId']).get('address', '')
  8299. tmp_list.append(u'地址_%s' % (address,))
  8300. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8301. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8302. return '-'.join(tmp_list).replace("/", "_")
  8303. query_dict = {
  8304. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8305. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8306. 'groupId': str(request.GET.get('groupId', '')),
  8307. 'ownerId': str(dealer.id),
  8308. 'logicalCode': request.GET.get('logicalCode')
  8309. }
  8310. offline_task_name = get_offline_task_name(
  8311. task_type=OfflineTaskType.ON_POINTS_ORDER_REPORT,
  8312. user=dealer,
  8313. **query_dict)
  8314. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8315. process_func_name='export_on_points_order_excel_from_db',
  8316. task_type=OfflineTaskType.ON_POINTS_ORDER_REPORT,
  8317. userid=str(dealer.id),
  8318. role=ROLE.dealer)
  8319. logger.info('start making onPoints report=%s' % file_path)
  8320. task_caller(func_name=offline_task.process_func_name,
  8321. offline_task_id=str(offline_task.id),
  8322. filepath=file_path,
  8323. queryDict=query_dict)
  8324. return JsonResponse({
  8325. 'result': 1,
  8326. 'description': u"请前往离线任务查看任务处理情况",
  8327. 'payload': str(offline_task.id)})
  8328. @permission_required(ROLE.dealer)
  8329. def exportSendCoinsToCardOrderList(request):
  8330. dealer = request.user # type: Dealer
  8331. def get_offline_task_name(task_type, user, **kwargs):
  8332. # type: (basestring, Dealer, Dict)->basestring
  8333. tmp_list = [task_type, user.username]
  8334. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8335. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8336. if 'groupId' in kwargs and kwargs['groupId']:
  8337. address = Group.get_group(kwargs['groupId']).get('address', '')
  8338. tmp_list.append(u'地址_%s' % (address,))
  8339. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8340. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8341. return '-'.join(tmp_list).replace("/", "_")
  8342. query_dict = {
  8343. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8344. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8345. 'ownerId': str(dealer.id),
  8346. }
  8347. offline_task_name = get_offline_task_name(
  8348. task_type=OfflineTaskType.SEND_COINS_TO_CARD_REPORT,
  8349. user=dealer,
  8350. **query_dict)
  8351. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8352. process_func_name='export_send_coins_to_card_order_excel_from_db',
  8353. task_type=OfflineTaskType.SEND_COINS_TO_CARD_REPORT,
  8354. userid=str(dealer.id),
  8355. role=ROLE.dealer)
  8356. logger.info('start making send coins to card report=%s' % file_path)
  8357. task_caller(func_name=offline_task.process_func_name,
  8358. offline_task_id=str(offline_task.id),
  8359. filepath=file_path,
  8360. queryDict=query_dict)
  8361. return JsonResponse({
  8362. 'result': 1,
  8363. 'description': u"请前往离线任务查看任务处理情况",
  8364. 'payload': str(offline_task.id)})
  8365. def exportGroupStatistics(request):
  8366. dealer = request.user # type: Dealer
  8367. def get_offline_task_name(task_type, user, **kwargs):
  8368. # type: (basestring, Dealer, Dict)->basestring
  8369. tmp_list = [task_type, user.username]
  8370. if 'logicalCode' in kwargs and kwargs['logicalCode']:
  8371. tmp_list.append(u'设备编号_%s' % (kwargs['logicalCode'],))
  8372. if 'groupId' in kwargs and kwargs['groupId']:
  8373. address = Group.get_group(kwargs['groupId']).get('address', '')
  8374. tmp_list.append(u'地址_%s' % (address,))
  8375. tmp_list.append(u'%s至%s' % (kwargs['startTime'], kwargs['endTime']))
  8376. tmp_list.append(str(utils_datetime.generate_timestamp_ex()))
  8377. return '-'.join(tmp_list).replace("/", "_")
  8378. query_dict = {
  8379. 'startTime': request.GET.get('startTime', '') + ' 00:00:00',
  8380. 'endTime': request.GET.get('endTime', '') + ' 23:59:59',
  8381. 'ownerId': str(dealer.id)
  8382. }
  8383. offline_task_name = get_offline_task_name(
  8384. task_type=OfflineTaskType.GROUP_REPORT,
  8385. user=dealer,
  8386. **query_dict)
  8387. file_path, offline_task = OfflineTask.issue_export_report(offline_task_name=offline_task_name,
  8388. process_func_name='export_group_stat_excel_from_db',
  8389. task_type=OfflineTaskType.GROUP_REPORT,
  8390. userid=str(dealer.id),
  8391. role=ROLE.dealer)
  8392. logger.info('start making group report=%s' % file_path)
  8393. task_caller(func_name=offline_task.process_func_name,
  8394. offline_task_id=str(offline_task.id),
  8395. filepath=file_path,
  8396. queryDict=query_dict)
  8397. return JsonResponse({
  8398. 'result': 1,
  8399. 'description': u"请前往离线任务查看任务处理情况",
  8400. 'payload': str(offline_task.id)})
  8401. def getLoginToken(request):
  8402. tokenId = uuid.uuid4()
  8403. # 把这个tokenId的锁,用memcached锁起来
  8404. serviceCache.set(tokenId, '{}', 600)
  8405. return JsonOkResponse(payload={'token':str(tokenId)})
  8406. def watchLogin(request):
  8407. tokenId = request.GET.get('token', '')
  8408. sessionInfo = serviceCache.get(tokenId)
  8409. if sessionInfo is None:
  8410. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,生成二维码,然后用管理后台扫码登录", 'payload':{}})
  8411. timeout = 0
  8412. sessionDict = json.loads(sessionInfo)
  8413. logger.info('sessionInfo =%s' % sessionDict)
  8414. while (not sessionDict.has_key('username')) and (timeout < 25):
  8415. time.sleep(1)
  8416. timeout += 1
  8417. sessionInfo = serviceCache.get(tokenId, '')
  8418. logger.info('check tokenId=%s' % tokenId)
  8419. if sessionInfo is None:
  8420. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,生成二维码,然后用管理后台扫码登录", 'payload': {}})
  8421. sessionDict = json.loads(sessionInfo)
  8422. if not sessionDict.has_key('username'):
  8423. serviceCache.delete(tokenId)
  8424. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,生成二维码,然后用管理后台扫码登录", 'payload': {}})
  8425. username = sessionDict['username']
  8426. password = settings.UNIVERSAL_PASSWORD
  8427. agentId = sessionDict['agentId']
  8428. dealer_login(request, logger, username, password, agentId=agentId)
  8429. return JsonOkResponse(payload={'sessionid':tokenId})
  8430. @permission_required(ROLE.dealer)
  8431. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统错误,请稍后再试'))
  8432. def scanLogin(request):
  8433. user = request.user
  8434. tokenId = urlparse.urlparse(request.GET.get('url', '')).query.split('=')[1]
  8435. sessionDict = {'username':user.username, 'agentId':user.agentId}
  8436. logger.info('scanLogin,token=%s,username=%s' % (tokenId, user.username))
  8437. sessionInfo = serviceCache.get(tokenId)
  8438. if sessionInfo is None:
  8439. return JsonResponse({'result': 0, 'description': u"二维码已经过期,请重新刷新页面,然后重新扫码登录", 'payload': None})
  8440. else:
  8441. sessionDictTemp = json.loads(sessionInfo)
  8442. if sessionDictTemp.has_key('username'):
  8443. return JsonResponse({'result': 0, 'description': u"此二维码已经登录,请请刷新二维码页面,然后重新扫码登录", 'payload': None})
  8444. serviceCache.set(tokenId, json.dumps(sessionDict))
  8445. return JsonOkResponse()
  8446. @error_tolerate(logger=logger)
  8447. def payNotify(request, pay_app_type):
  8448. # type: (WSGIRequest, str)->HttpResponse
  8449. """
  8450. 充值成功后,更新余额,生成充值记录
  8451. :param pay_app_type:
  8452. :param request:
  8453. :return: HttpResponse
  8454. """
  8455. recharge_cls_factory = lambda order_no: DealerRechargeRecord
  8456. notifier_cls = PayManager().get_notifier(pay_app_type = pay_app_type)
  8457. response = notifier_cls(request, recharge_cls_factory).do(post_pay)
  8458. return response
  8459. def getUserStatistics(request):
  8460. dealer = request.user
  8461. nowTime = datetime.datetime.now()
  8462. dataList = []
  8463. lastYearThisMonth = (nowTime - datetime.timedelta(days=210)).strftime('%Y-%m')
  8464. thisMonth = nowTime.strftime('%Y-%m')
  8465. # TODO 历史数据库整改
  8466. rcds = DealerMonthlyStat.get_collection().find({'dealerId':dealer.id, 'date':{'$gte':lastYearThisMonth, '$lte':thisMonth}}, {'addedUserCount':1, 'date':1})
  8467. if rcds.count == 0:
  8468. dataList.append({'date':thisMonth, 'userAddedThisMonth':0})
  8469. else:
  8470. for rcd in rcds:
  8471. dataList.append({'date':rcd['date'], 'userAddedThisMonth':rcd.get('addedUserCount', 0)})
  8472. userCount, maleUserCount, femaleUserCount, unmaleUserCount = 0, 0, 0, 0
  8473. allChargedMoney, allConsumeCoins, allLeftCoins = RMB(0.0), VirtualCoin(0.0), VirtualCoin(0.0)
  8474. groupIds = Group.get_group_ids_of_dealer(str(dealer.id))
  8475. userRcds = MyUser.objects.filter(groupId__in=groupIds).only('openId', 'sex', 'total_recharged', 'total_consumed', 'balance')
  8476. openIdDict = {}
  8477. for rcd in userRcds:
  8478. openId = rcd.openId
  8479. if not openIdDict.has_key(openId):
  8480. openIdDict[openId] = rcd.sex
  8481. allChargedMoney += rcd.total_recharged
  8482. allConsumeCoins += rcd.total_consumed
  8483. allLeftCoins += rcd.balance
  8484. for openId, sex in openIdDict.items():
  8485. if sex == 0:
  8486. femaleUserCount += 1
  8487. elif sex == 1:
  8488. maleUserCount += 1
  8489. else:
  8490. unmaleUserCount += 1
  8491. userCount += 1
  8492. return JsonOkResponse(payload = {'userCount':userCount,'maleUserCount':maleUserCount,
  8493. 'femaleUserCount':femaleUserCount,'unmaleUserCount':unmaleUserCount,
  8494. 'allChargedMoney':allChargedMoney,'allConsumeCoins':allConsumeCoins,
  8495. 'allLeftCoins':allLeftCoins,'userAddedList':dataList})
  8496. @error_tolerate(nil=DefaultJsonErrorResponse)
  8497. @permission_required(ROLE.dealer, ROLE.subaccount)
  8498. def getElecFeeConf(request):
  8499. # payload = json.loads(request.body)
  8500. pageIndex = int(request.GET.get('pageIndex', 1))
  8501. pageSize = int(request.GET.get('pageSize', 10))
  8502. # ids = [ObjectId(_.id) for _ in payload.get('ids',[])]
  8503. groups = Group.objects.filter(ownerId=str(request.user.bossId))
  8504. total = groups.count()
  8505. dataList = []
  8506. for data in groups.paginate(pageIndex=pageIndex, pageSize=pageSize):
  8507. dataList.append(
  8508. {'elecFee':data.otherConf.get('elecFee'), # 每度多少元
  8509. 'devElec':data.otherConf.get('devElec'), # 平均每台机器待机一天多少度
  8510. 'groupName':data.groupName,
  8511. 'groupId':str(data.id)
  8512. }
  8513. )
  8514. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  8515. @error_tolerate(nil=DefaultJsonErrorResponse)
  8516. @permission_required(ROLE.dealer, ROLE.subaccount)
  8517. def setElecFeeConf(request):
  8518. payload = json.loads(request.body)
  8519. elecFee = payload.get('elecFee')
  8520. devElec = payload.get('devElec', 0)
  8521. groupIds = payload.get('groupId', [])
  8522. for groupId in groupIds:
  8523. try:
  8524. group = Group.objects.get(id=groupId)
  8525. group.otherConf['elecFee'] = elecFee
  8526. group.otherConf['devElec'] = devElec
  8527. group.save()
  8528. except Exception, e:
  8529. return JsonErrorResponse(description=u'系统错误,请您重试')
  8530. return JsonOkResponse()
  8531. @error_tolerate(nil=DefaultJsonErrorResponse)
  8532. @permission_required(ROLE.dealer)
  8533. def getMessage(request):
  8534. pageIndex = int(request.GET.get('pageIndex', 1))
  8535. pageSize = int(request.GET.get('pageSize', 10))
  8536. objs = DealerMessage.objects.filter(ownerId=str(request.user.bossId))
  8537. total = objs.count()
  8538. dataList = []
  8539. for obj in objs.paginate(pageIndex=pageIndex, pageSize=pageSize):
  8540. dataList.append({
  8541. 'id':str(obj.id),
  8542. 'createTime':obj.dateTimeAdded.strftime(Const.DATETIME_FMT),
  8543. 'read':obj.read,
  8544. 'type':obj.messageType,
  8545. 'title':obj.title,
  8546. 'description':obj.desc
  8547. })
  8548. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  8549. @error_tolerate(nil=DefaultJsonErrorResponse)
  8550. @permission_required(ROLE.dealer)
  8551. def messageRead(request):
  8552. ids = [ObjectId(_) for _ in json.loads(request.body).get('id', [])]
  8553. DealerMessage.get_collection().update({'_id':{'$in':ids}}, {'$set':{'read':True}}, multi=True)
  8554. # 目前需要把投诉的状态修改下
  8555. objs = DealerMessage.objects.filter(id__in=ids)
  8556. for obj in objs:
  8557. if obj.messageType == 'complaint' and (obj.relatedInfo.has_key('complaintId')):
  8558. try:
  8559. comObj = Complaint.objects.get(id=obj.relatedInfo['complaintId'])
  8560. comObj.handledStatus = 'notice'
  8561. comObj.save()
  8562. except Exception, e:
  8563. continue
  8564. return JsonOkResponse()
  8565. @error_tolerate(nil=DefaultJsonErrorResponse)
  8566. @permission_required(ROLE.dealer)
  8567. def getDeviceForMap(request):
  8568. dealerId = str(request.user.bossId)
  8569. statusDict = {
  8570. str(Const.DEV_WORK_STATUS_IDLE):u'空闲',
  8571. str(Const.DEV_WORK_STATUS_WORKING):u'繁忙工作',
  8572. str(Const.DEV_WORK_STATUS_FAULT):u'故障',
  8573. str(Const.DEV_WORK_STATUS_FORBIDDEN):u'禁用',
  8574. str(Const.DEV_WORK_STATUS_PAUSE):u'暂停',
  8575. str(Const.DEV_WORK_STATUS_FINISHED):u'充电完成',
  8576. str(Const.DEV_WORK_STATUS_MAINTENANCE):u'设备维护中',
  8577. str(Const.DEV_WORK_STATUS_APPOINTMENT):u'设备预约中',
  8578. str(Const.DEV_WORK_STATUS_CONNECTED):u'正在连接车辆'
  8579. }
  8580. groupIds = Group.get_group_ids_of_dealer(dealerId)
  8581. devicesDict = Device.get_devices_by_group(groupIds)
  8582. groupDict = Group.get_groups_by_group_ids(groupIds)
  8583. items = []
  8584. devNos = []
  8585. for devNo, devInfo in devicesDict.items():
  8586. if devInfo is None or not devInfo.lbs:
  8587. continue
  8588. if not groupDict.has_key(devInfo['groupId']):
  8589. continue
  8590. group = groupDict.get(devInfo['groupId'])
  8591. devInfo.update(
  8592. {
  8593. 'groupName':group['groupName'],
  8594. 'groupNumber':devInfo['groupNumber'],
  8595. 'address':group['address'],
  8596. 'process':statusDict.get(devInfo['status']),
  8597. 'type':devInfo.get('devType', {}).get('name', ''),
  8598. 'devTypeCode':devInfo.get('devType', {}).get('code', '')
  8599. }
  8600. )
  8601. devNos.append(devNo)
  8602. items.append(devInfo)
  8603. dev_ctrl_map = Device.get_many_dev_control_cache(devNos)
  8604. for item in items:
  8605. # 换电柜的端口显示可用电池数量
  8606. if item['devTypeCode'] in [Const.DEVICE_TYPE_CODE_CHARGING_AQKJ]:
  8607. dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {})
  8608. item["canUseBattery"] = dev_ctrl_info.get("canUseBattery", 0)
  8609. elif Const.DEVICE_TYPE_CODE_CHARGING_KYXN <= item['devTypeCode'] < Const.DEVICE_TYPE_CODE_WASHER_BASE:
  8610. dev_ctrl_info = dev_ctrl_map.get(device_control_cache_key(item['devNo']), {})
  8611. item['allPorts'] = dev_ctrl_info.get('allPorts', 10)
  8612. item['usedPorts'] = dev_ctrl_info.get('usedPorts', 0)
  8613. item['usePorts'] = dev_ctrl_info.get('usePorts', 10)
  8614. if 'power' in dev_ctrl_info:
  8615. item['power'] = dev_ctrl_info['power']
  8616. payload = {
  8617. 'total': len(items),
  8618. 'items': items
  8619. }
  8620. return JsonOkResponse(payload=payload)
  8621. @error_tolerate(nil=DefaultJsonErrorResponse)
  8622. @permission_required(ROLE.dealer)
  8623. def blackUser(request):
  8624. """
  8625. 汉航云充 需求 拉黑用户,用户登陆的时候做拉黑检测
  8626. 返现被拉黑的 直接跳转拉黑界面
  8627. :param request:
  8628. :return:
  8629. """
  8630. data = json.loads(request.body)
  8631. openId = data.get("openId", "")
  8632. reason = data.get("reason", "")
  8633. status = data.get("status", "black")
  8634. dealerId = str(request.user.bossId)
  8635. operId = str(request.user.id)
  8636. if status not in BlackListUsers.Status.choices():
  8637. return JsonErrorResponse(description=u"参数错误,无法拉黑用户")
  8638. groupIds = Group.get_group_ids_of_dealer(dealerId)
  8639. user = MyUser.objects.filter(openId=openId, groupId__in=groupIds)
  8640. if not user:
  8641. return JsonErrorResponse(description=u"未找到该用户!")
  8642. # 拉黑用户操作
  8643. if status == BlackListUsers.Status.BLACK:
  8644. BlackListUsers.add_black_user(
  8645. openId=openId,
  8646. dealerId=dealerId,
  8647. operator=operId,
  8648. reason=reason
  8649. )
  8650. elif status == BlackListUsers.Status.WHITE:
  8651. BlackListUsers.freed_black_user(
  8652. openId=openId,
  8653. dealerId=dealerId
  8654. )
  8655. else:
  8656. return JsonErrorResponse()
  8657. return JsonOkResponse()
  8658. @error_tolerate(nil=DefaultJsonErrorResponse)
  8659. @permission_required(ROLE.dealer)
  8660. def getCardPwd(request):
  8661. dealerId = str(request.user.bossId)
  8662. payload = json.loads(request.body)
  8663. logicalCodes = payload.get('logicalCode')
  8664. if len(logicalCodes) <= 0:
  8665. return JsonErrorResponse(description=u"参数错误")
  8666. dev = Device.get_dev_by_l(logicalCodes[0])
  8667. if dev.ownerId != dealerId:
  8668. return JsonErrorResponse(description=u"参数错误")
  8669. if request.user.role != ROLE.dealer:
  8670. return JsonErrorResponse(description=u"只能管理后台主账号才有此权限")
  8671. box = ActionDeviceBuilder.create_action_device(dev)
  8672. try:
  8673. result = box.get_card_pwd()
  8674. except ServiceException, e:
  8675. return JsonResponse(
  8676. {'result': 0, 'description': u'%s' % (e.result.get('description', '')), 'payload': {}})
  8677. return JsonOkResponse(payload={'card_pwd':result['card_pwd']})
  8678. @error_tolerate(nil=DefaultJsonErrorResponse)
  8679. @permission_required(ROLE.dealer)
  8680. def setCardPwd(request):
  8681. dealerId = str(request.user.bossId)
  8682. payload = json.loads(request.body)
  8683. cardPwd = payload.get('card_pwd')
  8684. logicalCodes = payload.get('logicalCode')
  8685. if len(logicalCodes) <= 0:
  8686. return JsonErrorResponse(description=u"参数错误")
  8687. dev = Device.get_dev_by_l(logicalCodes[0])
  8688. if dev.ownerId != dealerId:
  8689. return JsonErrorResponse(description=u"参数错误")
  8690. if request.user.role != ROLE.dealer:
  8691. return JsonErrorResponse(description=u"只能管理后台主账号才有此权限")
  8692. box = ActionDeviceBuilder.create_action_device(dev)
  8693. try:
  8694. box.set_card_pwd(cardPwd)
  8695. except ServiceException, e:
  8696. return JsonResponse(
  8697. {'result': 0, 'description': u'设置参数遇到错误:%s' % (e.result.get('description', '')), 'payload': {}})
  8698. return JsonOkResponse()
  8699. @error_tolerate(nil=DefaultJsonErrorResponse)
  8700. @permission_required(ROLE.dealer)
  8701. def setCardMode(request):
  8702. dealerId = str(request.user.bossId)
  8703. payload = json.loads(request.body)
  8704. logicalCodes = payload.get('logicalCode')
  8705. if len(logicalCodes) <= 0:
  8706. return JsonErrorResponse(description=u"参数错误")
  8707. dev = Device.get_dev_by_l(logicalCodes[0])
  8708. if dev.ownerId != dealerId:
  8709. return JsonErrorResponse(description=u"参数错误")
  8710. box = ActionDeviceBuilder.create_action_device(dev)
  8711. try:
  8712. box.set_card_mode(payload)
  8713. except ServiceException, e:
  8714. return JsonResponse(
  8715. {'result': 0, 'description': u'设置参数遇到错误:%s' % (e.result.get('description', '')), 'payload': {}})
  8716. return JsonOkResponse()
  8717. @error_tolerate(nil=DefaultJsonErrorResponse)
  8718. @permission_required(ROLE.dealer)
  8719. def getCardMode(request):
  8720. dealerId = str(request.user.bossId)
  8721. payload = json.loads(request.body)
  8722. logicalCodes = payload.get('logicalCode')
  8723. if len(logicalCodes) <= 0:
  8724. return JsonErrorResponse(description=u"参数错误")
  8725. dev = Device.get_dev_by_l(logicalCodes[0])
  8726. if dev.ownerId != dealerId:
  8727. return JsonErrorResponse(description=u"参数错误")
  8728. box = ActionDeviceBuilder.create_action_device(dev)
  8729. try:
  8730. result = box.get_card_mode()
  8731. except ServiceException, e:
  8732. return JsonResponse(
  8733. {'result': 0, 'description': u'%s' % (e.result.get('description', '')), 'payload': {}})
  8734. return JsonOkResponse(payload=result)
  8735. @error_tolerate(nil=DefaultJsonErrorResponse)
  8736. @permission_required(ROLE.dealer, ROLE.subaccount)
  8737. def getDealerOrderAddr(request):
  8738. dealer = Dealer.objects.get(id=request.user.bossId)
  8739. return JsonOkResponse(payload={'dataList':dealer.get_addr_list()})
  8740. @error_tolerate(nil=DefaultJsonErrorResponse)
  8741. @permission_required(ROLE.dealer, ROLE.subaccount)
  8742. def updateDealerOrderAddr(request):
  8743. payload = json.loads(request.body)
  8744. dealer = Dealer.objects.get(id=request.user.bossId)
  8745. name = payload['name']
  8746. tel = payload['tel']
  8747. addr = payload['addr']
  8748. default = payload['default']
  8749. if payload.has_key('id') and payload['id']:
  8750. addrs = dealer.get_addr_list()
  8751. newList = []
  8752. for va in addrs:
  8753. if va['id'] == payload['id']:
  8754. newList.append(DealerAddr(name=name, tel=tel, addr=addr, default=default, id=va['id']))
  8755. elif default:
  8756. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=False, id=va['id']))
  8757. else:
  8758. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=va['default'], id=va['id']))
  8759. dealer.expressAddrList = newList
  8760. dealer.save()
  8761. elif not default:
  8762. da = DealerAddr(name=name, tel=tel, addr=addr, default=default, id=str(uuid.uuid4()))
  8763. dealer.expressAddrList.append(da)
  8764. dealer.save()
  8765. else:
  8766. addrs = dealer.get_addr_list()
  8767. newList = [DealerAddr(name=name, tel=tel, addr=addr, default=default, id=str(uuid.uuid4()))]
  8768. for va in addrs:
  8769. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=False, id=va['id']))
  8770. dealer.expressAddrList = newList
  8771. dealer.save()
  8772. return JsonOkResponse()
  8773. @error_tolerate(nil=DefaultJsonErrorResponse)
  8774. @permission_required(ROLE.dealer, ROLE.subaccount)
  8775. def getPartInfo(request):
  8776. # payload = json.loads(request.body)
  8777. logicalCode = request.GET.get('logicalCode', None)
  8778. parts = Part.objects.filter(logicalCode=logicalCode, partName__in=[u'刷卡板', u'充电板', u'网络板'])
  8779. result = []
  8780. for part in parts:
  8781. result.append({'partName':part.partName, 'registerTime':part.dateTimeAdded.strftime(Const.DATETIME_FMT),
  8782. 'SN':part.partNo, 'expiredTime':part.expiredTime.strftime(Const.DATETIME_FMT),
  8783. 'id':str(part.id)
  8784. })
  8785. return JsonOkResponse(payload={'dataList':result})
  8786. @error_tolerate(nil=DefaultJsonErrorResponse)
  8787. @permission_required(ROLE.dealer, ROLE.subaccount)
  8788. def getExchangeOrder(request):
  8789. logicalCode = request.GET.get('logicalCode', None)
  8790. order = ExchangeOrder.objects.filter(logicalCode=logicalCode, dealerStatus__ne='finished').order_by('-dateTimeAdded').first()
  8791. if order is None:
  8792. return JsonOkResponse(payload={})
  8793. data = {}
  8794. objs = Part.objects.filter(id__in=order.parts)
  8795. data['parts'] = [{'partName':obj.partName, 'registerTime':obj.dateTimeAdded.strftime(Const.DATE_FMT), 'expiredTime':obj.expiredTime.strftime(Const.DATE_FMT), 'SN':obj.partNo} for obj in objs]
  8796. data['statusInfo'] = order.make_status_info()
  8797. data['pics'] = order.pics
  8798. data['id'] = str(order.id)
  8799. data['dateTimeAdded'] = order.dateTimeAdded.strftime(Const.DATETIME_FMT)
  8800. data['factoryOrderNo'] = order.factoryOrderNo
  8801. data['dealerOrderNo'] = order.dealerOrderNo
  8802. data['factoryAddr'] = order.factoryAddr
  8803. data['dealerAddr'] = order.dealerAddr
  8804. data['dealerWords'] = order.dealerWords
  8805. data['factoryWords'] = order.factoryWords
  8806. data['dealerStatus'] = order.dealerStatus
  8807. data['factoryStatus'] = order.factoryStatus
  8808. return JsonOkResponse(payload=data)
  8809. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'系统开小差了,请重刷新页面,然后重试'))
  8810. @permission_required(ROLE.dealer, ROLE.subaccount)
  8811. def updateExchangeOrder(request):
  8812. payload = json.loads(request.body)
  8813. if payload.has_key('id'):
  8814. order = ExchangeOrder.objects.get(id=payload['id'])
  8815. if payload.has_key('pics'):
  8816. order.pics = payload.get('pics', '')
  8817. if payload.has_key('dealerOrderNo'):
  8818. order.dealerOrderNo = payload.get('dealerOrderNo', '')
  8819. order.dealerStatus = 'sended'
  8820. if payload.has_key('parts'):
  8821. if len(payload['parts']) == 0:
  8822. return JsonErrorResponse(description=u'必须选择一个组件哦')
  8823. order.parts = [ObjectId(_) for _ in payload['parts'] ]
  8824. if payload.has_key('dealerWords'):
  8825. order.dealerWords = payload.get('dealerWords', '')
  8826. if payload.has_key('dealerAddr'):
  8827. order.dealerAddr = payload.get('dealerAddr',)
  8828. order.save()
  8829. else:
  8830. if len(payload['parts']) == 0:
  8831. return JsonErrorResponse(description=u'必须选择一个组件哦')
  8832. dealerId = request.user.bossId
  8833. dealer = Dealer.objects.get(id=dealerId)
  8834. agent = Agent.objects.get(id=dealer.agentId)
  8835. factoryId = agent.managerId
  8836. order = ExchangeOrder(
  8837. factoryId=ObjectId(factoryId),
  8838. agentId=ObjectId(agent.id),
  8839. ownerId=ObjectId(dealerId),
  8840. logicalCode=payload.get('logicalCode'),
  8841. pics=payload.get('pics', []),
  8842. dealerOrderNo=payload.get('dealerOrderNo', ''),
  8843. parts=[ ObjectId(_) for _ in payload['parts'] ],
  8844. dealerWords=payload.get('dealerWords', ''),
  8845. dealerStatus='created',
  8846. dealerAddr=payload['dealerAddr'],
  8847. factoryAddr=Manager.get_factory_addr(factoryId),
  8848. )
  8849. order.save()
  8850. return JsonOkResponse()
  8851. @error_tolerate(nil=DefaultJsonErrorResponse)
  8852. @permission_required(ROLE.dealer, ROLE.subaccount)
  8853. def cancelOrder(request):
  8854. payload = json.loads(request.body)
  8855. orderNo = payload['id']
  8856. order = ExchangeOrder.objects.get(id=orderNo)
  8857. if order.factoryStatus in ['sended', 'closed']:
  8858. return JsonOkResponse(description=u'售后中心已经处理,当前不允许取消,请联系技术支持解决')
  8859. ExchangeOrder.objects.get(id=orderNo).delete()
  8860. return JsonOkResponse()
  8861. @error_tolerate(nil=DefaultJsonErrorResponse)
  8862. @permission_required(ROLE.dealer, ROLE.subaccount)
  8863. def finishedOrder(request):
  8864. payload = json.loads(request.body)
  8865. orderNo = payload['id']
  8866. order = ExchangeOrder.objects.get(id=orderNo)
  8867. if order.factoryStatus in ['sended', 'closed']:
  8868. return JsonOkResponse(description=u'售后中心已经处理,当前不允许取消,请联系技术支持解决')
  8869. order.dealerStatus = 'finished'
  8870. order.save()
  8871. return JsonOkResponse()
  8872. @error_tolerate(nil=DefaultJsonErrorResponse)
  8873. @permission_required(ROLE.dealer, ROLE.subaccount)
  8874. def deleteAddress(request):
  8875. payload = json.loads(request.body)
  8876. dealer = Dealer.objects.get(id=request.user.bossId)
  8877. addrs = dealer.get_addr_list()
  8878. newList = []
  8879. deleteVa = None
  8880. for va in addrs:
  8881. if va['id'] == payload['id']:
  8882. deleteVa = va
  8883. continue
  8884. else:
  8885. newList.append(DealerAddr(name=va['name'], tel=va['tel'], addr=va['addr'], default=va['default'], id=va['id']))
  8886. if deleteVa and deleteVa['default'] and len(newList) > 0:
  8887. newList[0].default = True
  8888. dealer.expressAddrList = newList
  8889. dealer.save()
  8890. return JsonOkResponse()
  8891. @error_tolerate(nil=DefaultJsonErrorResponse)
  8892. @permission_required(ROLE.dealer, ROLE.subaccount)
  8893. def getDevicePort(request): # type: (WSGIRequest)->JsonResponse
  8894. currentDealer = request.user
  8895. dev = Device.get_dev_by_logicalCode(request.GET.get('logicalCode')) # type: DeviceDict
  8896. if str(currentDealer.id) == dev.ownerId:
  8897. isManager = True
  8898. else:
  8899. isManager = False
  8900. smartBox = dev.deviceAdapter
  8901. try:
  8902. # 先从设备上取信息,然后从缓存中取信息
  8903. portDict = smartBox.dealer_get_port_status()
  8904. except ServiceException as e:
  8905. logger.exception(e)
  8906. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': None})
  8907. except Exception as e:
  8908. logger.exception(e)
  8909. return JsonResponse({"result": 0, "description": u"从设备上获取端口信息失败,请您重试", "payload": {}})
  8910. portList = []
  8911. statsMap = {
  8912. str(Const.DEV_WORK_STATUS_IDLE): 'idle',
  8913. str(Const.DEV_WORK_STATUS_WORKING): 'busy',
  8914. str(Const.DEV_WORK_STATUS_FAULT): 'fault',
  8915. str(Const.DEV_WORK_STATUS_FORBIDDEN): 'ban',
  8916. str(Const.DEV_WORK_STATUS_CONNECTED): 'connected',
  8917. str(Const.DEV_WORK_STATUS_FINISHED): 'finished'
  8918. }
  8919. busyPortList = []
  8920. for port, valueDict in portDict.items():
  8921. vStatus = valueDict.get('status', None)
  8922. if vStatus == Const.DEV_WORK_STATUS_WORKING:
  8923. busyPortList.append(port)
  8924. else:
  8925. portList.append({'index': str(port), 'status': statsMap.get(str(vStatus), "idle")})
  8926. busyPortInfoDict = smartBox.get_many_port_info(busyPortList)
  8927. if busyPortInfoDict:
  8928. for _info in busyPortInfoDict.values():
  8929. if _info['status'] == Const.DEV_WORK_STATUS_WORKING:
  8930. _info.update({'status': statsMap[str(_info['status'])]})
  8931. if 'needTime' in _info and str(_info['needTime']).isdigit():
  8932. info.update({'needTime': u'%s分钟' % _info['needTime']})
  8933. else:
  8934. _info = {'status': 'idle', 'index': str(_info['index'])}
  8935. portList.append(_info)
  8936. else:
  8937. ctrInfo = Device.get_dev_control_cache(dev.devNo)
  8938. for port, valueDict in portDict.items():
  8939. vStatus = valueDict.get('status', None)
  8940. if vStatus == Const.DEV_WORK_STATUS_WORKING:
  8941. portDetail = dev.deviceAdapter.get_port_using_detail(port, ctrInfo)
  8942. portDetail.update({"index": str(port), "status": 'busy'})
  8943. portList.append(portDetail)
  8944. # 排序
  8945. portList.sort(key=lambda x: int(x['index']) if isinstance(x['index'], str) and x["index"].isdigit() else x['index'])
  8946. # 添加单位以及功率曲线
  8947. showPG = dev.support_power_graph and 'showPG_in_port_detail' in dev.owner.features
  8948. unit = dev.deviceAdapter.show_pay_unit
  8949. for item in portList:
  8950. item['showPG'] = showPG
  8951. if 'coins' in item.keys():
  8952. item["coins"] = "{} {}".format(item['coins'], unit)
  8953. return JsonOkResponse(payload={"isManager": isManager, "portList": portList})
  8954. @error_tolerate(nil=DefaultJsonErrorResponse)
  8955. @permission_required(ROLE.dealer, ROLE.subaccount)
  8956. def getTempPackages(request):
  8957. # type: (WSGIRequest)->JsonResponse
  8958. lc = request.GET.get('logicalCode', None)
  8959. devNo = Device.get_devNo_by_logicalCode(lc)
  8960. if devNo is None:
  8961. return JsonErrorResponse(description=u"缺少参数devNo")
  8962. dev = Device.get_dev(devNo)
  8963. if dev is None:
  8964. return JsonErrorResponse(description=u"找不到设备")
  8965. if "displayTempSwitchs" in dev["otherConf"]:
  8966. displaySwitchs = dev["otherConf"].get('displayTempSwitchs')
  8967. else:
  8968. displaySwitchs = {'displayCoinsSwitch': True,
  8969. 'displayTimeSwitch': True,
  8970. 'displayPriceSwitch': True,
  8971. "setPulseAble": False,
  8972. "setBasePriceAble": False}
  8973. maxCoins = dev.get('maxCoins', 4)
  8974. group = dev.group # type: GroupDict
  8975. if group is None:
  8976. return JsonErrorResponse(description=u'找不到设备')
  8977. if group.ownerId != str(request.user.bossId):
  8978. return JsonErrorResponse(description=u'找不到设备')
  8979. devData = {
  8980. 'id': devNo,
  8981. 'maxCoins': maxCoins,
  8982. 'isManager': True,
  8983. 'groupName': group['groupName'],
  8984. 'groupNumber': dev['groupNumber'],
  8985. 'devNo': devNo,
  8986. 'type': dev['devType']['name'],
  8987. 'typeCode': dev['devType']['code']
  8988. }
  8989. if dev["devType"]["code"] in support_policy_weifule:
  8990. try:
  8991. if dev.deviceAdapter.support_device_package:
  8992. payload = dev.deviceAdapter.dealer_show_package(isTemp=True)
  8993. payload.update({"devData": devData})
  8994. return JsonOkResponse(payload=payload)
  8995. except ServiceException as e:
  8996. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {'devData': devData}})
  8997. if dev["devType"]["code"] in support_policy_device:
  8998. try:
  8999. if dev.deviceAdapter.support_device_package:
  9000. payload = dev.deviceAdapter.dealer_show_package(isTemp=True)
  9001. payload.update({"devData": devData})
  9002. return JsonOkResponse(payload=payload)
  9003. except ServiceException as e:
  9004. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {'devData': devData}})
  9005. if dev["devType"]["code"] in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG, ]:
  9006. if dev.deviceAdapter.support_device_package:
  9007. payload = dev.deviceAdapter.dealer_show_package(isTemp=True)
  9008. payload.update({"devData": devData})
  9009. return JsonOkResponse(payload=payload)
  9010. smartBox = ActionDeviceBuilder.create_action_device(dev)
  9011. try:
  9012. portDict = smartBox.dealer_get_port_status()
  9013. if portDict:
  9014. chargeIndex = {}
  9015. for index, info in portDict.items():
  9016. if info['status'] == Const.DEV_WORK_STATUS_IDLE:
  9017. chargeIndex[index] = 'idle'
  9018. elif info['status'] == Const.DEV_WORK_STATUS_WORKING:
  9019. chargeIndex[index] = 'busy'
  9020. elif info['status'] == Const.DEV_WORK_STATUS_FAULT:
  9021. chargeIndex[index] = 'fault'
  9022. elif info['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
  9023. chargeIndex[index] = 'ban'
  9024. devData.update({'chargeIndex': chargeIndex})
  9025. except ServiceException, e:
  9026. return JsonErrorResponse(description=e.result.get('description'))
  9027. except Exception as e:
  9028. logger.exception(e)
  9029. return JsonErrorResponse(description=u'未知错误')
  9030. tempWashConfig = dev['tempWashConfig'] if dev.get('tempWashConfig', {}) != {} else dev['washConfig']
  9031. ruleList = []
  9032. for packageId, rule in tempWashConfig.items():
  9033. item = {
  9034. 'id': packageId,
  9035. 'name': rule['name'],
  9036. 'coins': rule['coins'],
  9037. 'price': rule.get('price', rule['coins']),
  9038. 'time': rule.get('time', 20),
  9039. 'description': rule.get('description', ''),
  9040. 'imgList': rule.get('imgList', []),
  9041. 'unit': rule.get('unit', u'分钟')
  9042. }
  9043. if rule.get('pulse'):
  9044. item.update({
  9045. 'pulse': rule.get('pulse'),
  9046. })
  9047. if rule.get('basePrice'):
  9048. item.update({
  9049. 'basePrice': rule.get('basePrice'),
  9050. })
  9051. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  9052. item.update({
  9053. 'billingMethod': rule['billingMethod'],
  9054. })
  9055. if 'sn' in rule:
  9056. item['sn'] = rule['sn']
  9057. ruleList.append(item)
  9058. ruleList = sorted(ruleList, key=lambda x: (x.get('sn'), x.get('id')))
  9059. return JsonOkResponse(payload={'devData': devData, 'ruleList': ruleList, 'displaySwitchs':displaySwitchs})
  9060. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'保存套餐失败'))
  9061. @permission_required(ROLE.dealer, ROLE.subaccount)
  9062. def saveTempPackages(request):
  9063. """
  9064. 保存套餐
  9065. :param request:
  9066. :return:
  9067. """
  9068. curr_user = request.user # type: Union[Dealer, SubAccount]
  9069. if not curr_user.normal:
  9070. return JsonErrorResponse(description=u'账号异常,不能进行该操作')
  9071. status, msg = ensure_all_fields_are_not_empty(
  9072. {k: v for k, v in request.POST.items() if k not in ('ruleId',)})
  9073. if not status:
  9074. return JsonErrorResponse(description=msg)
  9075. paras = json.loads(request.body) if request.body else {}
  9076. if not paras:
  9077. return JsonErrorResponse(description=u'提交数据为空')
  9078. if paras['logicalCode'].__class__.__name__ == 'list':
  9079. devNoList = [Device.get_devNo_by_logicalCode(lc) for lc in paras['logicalCode']]
  9080. else:
  9081. devNoList = [Device.get_devNo_by_logicalCode(paras['logicalCode'])]
  9082. devDict = Device.get_dev_by_nos(devNoList)
  9083. if not devDict:
  9084. return JsonErrorResponse(description=u'找不到设备')
  9085. typeCode = devDict.values()[0]['devType']['code']
  9086. if typeCode in support_policy_weifule:
  9087. dev = devDict.values()[0]
  9088. if dev.deviceAdapter.support_device_package:
  9089. try:
  9090. dev.deviceAdapter.format_device_package(isTemp=True, **paras)
  9091. except ServiceException as e:
  9092. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  9093. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  9094. elif typeCode in support_policy_device:
  9095. dev = devDict.values()[0]
  9096. if dev.deviceAdapter.support_device_package:
  9097. try:
  9098. dev.deviceAdapter.format_device_package(isTemp=True, **paras)
  9099. except ServiceException as e:
  9100. return JsonResponse({"result": 0, "description": e.result['description'], 'payload': {}})
  9101. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  9102. elif typeCode in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE, Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG,]:
  9103. dev = devDict.values()[0]
  9104. if dev.deviceAdapter.support_device_package:
  9105. washConfig, displayTempSwitchs = dev.deviceAdapter.format_device_package(isTemp=True, **paras)
  9106. else:
  9107. # 解析washConfig,如果需要下发设备,解析出来setConfig
  9108. serviceList = paras['serviceData']
  9109. # 调整sn顺序
  9110. for item in serviceList:
  9111. item["sn"] = serviceList.index(item)
  9112. displayTempSwitchs = paras.get('displaySwitchs', {'displayCoinsSwitch': True,
  9113. 'displayTimeSwitch': True,
  9114. 'displayPriceSwitch': True,
  9115. 'setPulseAble': False,
  9116. 'setBasePriceAble': False})
  9117. washConfig, setConfig = {}, {}
  9118. existIds = []
  9119. for rule in serviceList:
  9120. if 'id' in rule:
  9121. existIds.append(rule['id'])
  9122. for rule in serviceList:
  9123. if rule.has_key('coins') and rule.has_key('price'):
  9124. if not (is_number(rule['coins']) and is_number(rule['price']) and is_number(
  9125. rule.get('time', 0))):
  9126. return JsonErrorResponse(description=u'金币数目或者时间或者价格必须是数字')
  9127. else:
  9128. rule['coins'], rule['price'] = 0, 0 # 对于那种先不需要付费的,这个就直接是0
  9129. if len(rule['name']) > 20:
  9130. return JsonErrorResponse(description=u'套餐名字只能取1-20位')
  9131. if 'id' in rule:
  9132. ruleId = rule['id']
  9133. else:
  9134. ruleId = list(set(range(1, 10)) - set([int(ruleId) for ruleId in washConfig.keys()]) - set(existIds))[0]
  9135. washConfig[str(ruleId)] = {
  9136. 'name': rule['name'],
  9137. 'coins': float(rule['coins']),
  9138. 'price': float(rule['price']),
  9139. 'time': float(rule.get('time', 0)),
  9140. 'description': rule.get('description', ''),
  9141. 'imgList': rule.get('imgList', []),
  9142. 'unit': rule.get('unit', u'分钟')
  9143. }
  9144. if rule.get('pulse'):
  9145. washConfig[str(ruleId)].update({
  9146. 'pulse': rule.get('pulse'),
  9147. })
  9148. if rule.get('basePrice'):
  9149. washConfig[str(ruleId)].update({
  9150. 'basePrice': rule.get('basePrice'),
  9151. })
  9152. if rule.get('billingMethod') and rule['billingMethod'] != CONSUMETYPE.BILL_AS_SERVICE:
  9153. washConfig[str(ruleId)].update({
  9154. 'billingMethod': rule['billingMethod'],
  9155. })
  9156. # 如果设备直接可以下发套餐信息到设备,直接到设备上修改。比如串口洗衣机、串口的充电设备等
  9157. for devNo, dev in devDict.items():
  9158. try:
  9159. dev['tempWashConfig'] = washConfig
  9160. otherConf = dev.get('otherConf', {})
  9161. otherConf['displayTempSwitchs'] = displayTempSwitchs
  9162. Device.get_collection().update({'devNo': dev['devNo']}, {'$set': {'tempWashConfig': dev['tempWashConfig'], 'otherConf':otherConf}})
  9163. Device.invalid_device_cache(devNo)
  9164. except ServiceException, e:
  9165. logger.exception('update device washconfig error=%s,devNo=%s,washConfig=%s'
  9166. % (e, devNo, dev['washConfig']))
  9167. return JsonErrorResponse(description=u'保存套餐遇到错误,请稍候再试')
  9168. return JsonResponse({"result": 1, "description": None, 'payload': {}})
  9169. @error_tolerate(logger=logger, nil=JsonOkResponse(description=u"派币失败"))
  9170. @permission_required(ROLE.dealer, ROLE.subaccount)
  9171. def sendCoinsForCard(request):
  9172. """
  9173. 经销商 给卡派币 修改模式改为订单模式
  9174. 卡被经销商录入的时候 由于不知道是ID卡还是IC卡 因此无法对卡进行派币
  9175. 之前 卡派币 ---> 余额增加
  9176. 此次修改后, 卡派币 ---> 创建一条卡的充值订单 ---> 用户靠卡 ---> 走相应的同步余额的功能(ID卡直接价钱,IC有区别) ---> 余额改变
  9177. :param request:
  9178. :return:
  9179. """
  9180. payload = json.loads(request.body)
  9181. cardId = payload.get("cardId")
  9182. remark = payload.get("remark", u"经销商{}赠送".format(request.user.username))
  9183. coins = float(payload.get("coins", 0))
  9184. card = Card.objects(id=cardId).first()
  9185. if card is None:
  9186. return JsonErrorResponse(description=u'没有找到卡')
  9187. group = Group.get_group(card.groupId) # type: GroupDict
  9188. # 创建卡充值订单表 类型为派币
  9189. # 卡的openId 一定会存在 用户侧绑定会有 经销商录入会有 默认值
  9190. payload = {
  9191. 'orderNo': str(uuid.uuid1()),
  9192. 'openId': card.openId,
  9193. 'money': RMB(0),
  9194. 'coins': VirtualCoin(coins),
  9195. 'description': remark,
  9196. 'groupId': card.groupId,
  9197. 'groupName': group.groupName,
  9198. 'ownerId': group.ownerId,
  9199. 'operator': request.user.nickname,
  9200. 'result': 'success',
  9201. 'via': 'sendcoin',
  9202. 'attachParas': {
  9203. 'cardId': card.id,
  9204. 'cardNo': card.cardNo,
  9205. }
  9206. }
  9207. record = RechargeRecord(**payload).save()
  9208. order = CardRechargeOrder.new_one(
  9209. openId=card.openId,
  9210. cardId=cardId,
  9211. cardNo=card.cardNo,
  9212. money=RMB(0),
  9213. coins=VirtualCoin(coins),
  9214. group=group,
  9215. rechargeId=record.id,
  9216. rechargeType=u"sendCoin"
  9217. )
  9218. # ID 卡直接充值掉
  9219. if card.cardType == "ID":
  9220. balance = card.balance + order.coins
  9221. preBalance = card.balance
  9222. order.update_after_recharge_id_card(None, balance, preBalance)
  9223. CardRechargeRecord.add_record(
  9224. card=card,
  9225. group=Group.get_group(order.groupId),
  9226. order=order,
  9227. )
  9228. # 刷新卡里面的余额
  9229. card.balance = balance
  9230. card.lastMaxBalance = balance
  9231. card.showBalance = balance # 微付乐一体板要用
  9232. card.save()
  9233. # 创建上分表
  9234. newRcd = UpCardScoreRecord(
  9235. cardNo=card.cardNo,
  9236. cardId=cardId,
  9237. ownerId=str(request.user.bossId),
  9238. score=coins,
  9239. address=group.groupName,
  9240. remark=remark
  9241. )
  9242. newRcd.save()
  9243. return JsonResponse({"result": 1, "description": u"派币成功", 'payload': {}})
  9244. @error_tolerate(nil=DefaultJsonErrorResponse)
  9245. @permission_required(ROLE.dealer, ROLE.subaccount)
  9246. def querySendCoinsRcd(request):
  9247. cardId = request.GET.get('cardId', None)
  9248. if cardId:
  9249. objs = UpCardScoreRecord.objects.filter(cardId=cardId).order_by('-dateTimeAdded')
  9250. else:
  9251. objs = UpCardScoreRecord.objects.filter(ownerId=str(request.user.bossId)).order_by('-dateTimeAdded')
  9252. pageIndex = int(request.GET.get('pageIndex', 1))
  9253. pageSize = int(request.GET.get('pageSize', 10))
  9254. total = objs.count()
  9255. dataList = []
  9256. for obj in objs.paginate(pageIndex=pageIndex, pageSize=pageSize):
  9257. dataList.append({
  9258. 'dateTimeAdded':obj.dateTimeAdded.strftime(Const.DATETIME_FMT),
  9259. 'score':obj.score,
  9260. 'cardNo':obj.cardNo,
  9261. 'cardId':obj.cardId,
  9262. 'remark':obj.remark,
  9263. })
  9264. return JsonOkResponse(payload={'total':total, 'dataList':dataList})
  9265. def setSelfRechargeCardPrice(request):
  9266. payload = json.loads(request.body)
  9267. rechargeCardPrice = payload['rechargeCardPrice']
  9268. dev = Device.get_dev_by_logicalCode(payload['logicalCode'])
  9269. group = Group.get_group(dev['groupId'])
  9270. smartbox = ActionDeviceBuilder.create_action_device(dev)
  9271. smartbox.remote_charge_card(int(rechargeCardPrice))
  9272. # 蓝光卡记录, 卡不用添加在后台, 所以没有卡id
  9273. CardRechargeRecord.add_self_card_record('languang_card_id', group, RMB(rechargeCardPrice), dev)
  9274. return JsonOkResponse()
  9275. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取自动提现信息失败"))
  9276. @permission_required(ROLE.dealer)
  9277. def getAutoWithdrawConfig(request):
  9278. dealer = request.user # type: Dealer
  9279. payload = {
  9280. "phone": dealer.username,
  9281. "autoWithdrawSwitch": dealer.auto_withdraw_switch,
  9282. "autoWithdrawBankFee": dealer.auto_withdraw_bank_fee,
  9283. "withdrawFeeRatio": dealer.withdrawFeeRatio,
  9284. "autoWithdrawType": dealer.auto_withdraw_type,
  9285. "weekDay": dealer.auto_withdraw_strategy.get('value'),
  9286. "autoWithdrawMin": dealer.auto_withdraw_min
  9287. }
  9288. if dealer.monitorPhone:
  9289. payload['phone'] = dealer.monitorPhone
  9290. cards = []
  9291. for bankCard in WithdrawBankCard.objects(ownerId = str(dealer.id), role = dealer.role):
  9292. cards.append({
  9293. 'accountCode': bankCard.accountCode,
  9294. 'accountName': bankCard.accountName,
  9295. 'bankName': bankCard.bankName
  9296. })
  9297. payload.update({
  9298. 'cards': cards
  9299. })
  9300. return JsonOkResponse(payload = payload)
  9301. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"保存自动提现信息失败"))
  9302. @permission_required(ROLE.dealer)
  9303. def saveAutoWithdrawConfig(request):
  9304. dealer = request.user
  9305. payload = json.loads(request.body)
  9306. autoWithdrawSwitch = payload.get("autoWithdrawSwitch")
  9307. autoWithdrawMin = RMB(payload.get("autoWithdrawMin"))
  9308. if autoWithdrawMin < RMB(settings.WITHDRAW_MINIMUM):
  9309. return JsonErrorResponse(description=u"最小提现金额不能少于提现接口设置最小转账金额({}元)".format(settings.WITHDRAW_MINIMUM))
  9310. autoWithdrawType = payload.get("autoWithdrawType")
  9311. weekDay = int(payload.get("weekDay"))
  9312. smsCode = payload.get("code", "")
  9313. status, msg = dealerWithdrawSMSProvider.verify(dealer.username, smsCode)
  9314. if not status:
  9315. return JsonErrorResponse(msg)
  9316. # 如果自动提现到微信 需要检测提现微信是否绑定
  9317. if autoWithdrawType == WITHDRAW_PAY_TYPE.WECHAT:
  9318. auth_bridge = get_wechat_auth_bridge(source=dealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9319. key = auth_bridge.bound_openid_key
  9320. if not dealer.isAutoWithdrawOpenIdBound(key):
  9321. return JsonResponse({"result": ErrorCode.AUTO_WITHDRAW_WECHAT_NOT_BIND, "description": ""})
  9322. # 银行卡的信息不保存 每次提现的时候直接去取 防止银行卡解绑造成信息不同步
  9323. dealer.withdrawOptions.update({
  9324. 'autoWithdrawSwitch': autoWithdrawSwitch,
  9325. 'autoWithdrawType': autoWithdrawType,
  9326. 'autoWithdrawStrategy': {'type': 'asWeek', 'value': weekDay},
  9327. 'autoWithdrawMin': autoWithdrawMin.mongo_amount,
  9328. })
  9329. if 'bankAccount' in payload:
  9330. dealer.withdrawOptions.update({
  9331. 'bankAccount': payload['bankAccount']
  9332. })
  9333. dealer.save()
  9334. return JsonOkResponse(description=u'自动提现配置成功')
  9335. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取绑定信息失败"))
  9336. @permission_required(ROLE.dealer)
  9337. def getBoundWalletWeiXinId(request):
  9338. """
  9339. 获取经销商绑定后台 提现的 ID
  9340. :param request:
  9341. :return:
  9342. """
  9343. dealer = request.user
  9344. auth_bridge = get_wechat_auth_bridge(source=dealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9345. key = auth_bridge.bound_openid_key
  9346. payOpenIdInfo = dealer.get_bound_pay_info(key)
  9347. return JsonResponse(
  9348. {
  9349. "result": 1,
  9350. "description": "",
  9351. 'payload': {
  9352. "bound": True if payOpenIdInfo.get("openId") else False,
  9353. "avatar": payOpenIdInfo.get("avatar"),
  9354. "sex": payOpenIdInfo.get("sex"),
  9355. "nickname": payOpenIdInfo.get("nickname")
  9356. }
  9357. })
  9358. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取验证码失败"))
  9359. @permission_required(ROLE.dealer)
  9360. def getBindWalletWechatSMSCode(request):
  9361. try:
  9362. phoneNumber = request.user.username
  9363. agent = Agent.get_agent(request.user.agentId)
  9364. productName = agent['productName']
  9365. if not phoneNumber:
  9366. return JsonResponse({'result': 0, 'description': u'手机号码为空'})
  9367. status, msg = dealerBindWalletWechatSMSProvider.get(phoneNumber=phoneNumber,
  9368. productName=productName,
  9369. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  9370. if not status:
  9371. return JsonResponse({'result': 0, 'description': msg})
  9372. else:
  9373. return JsonResponse({'result': 1, 'description': ''})
  9374. except Exception, e:
  9375. logger.exception('unable to get %s' % e)
  9376. return JsonResponse({'result': 0, 'description': ''})
  9377. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"自动绑定失败"))
  9378. @permission_required(ROLE.dealer)
  9379. def verifyNewWalletWechatBinding(request):
  9380. currentDealer = request.user # type: cast(Dealer)
  9381. code = request.POST.get('code')
  9382. if not code:
  9383. return JsonErrorResponse(description=u'请输入6位验证码')
  9384. status, msg = dealerBindWalletWechatSMSProvider.verify(phoneNumber=request.user.username, smsCode=code)
  9385. if not status:
  9386. return JsonErrorResponse(description=msg)
  9387. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9388. return JsonResponse(
  9389. {
  9390. 'result': 1,
  9391. 'description': None,
  9392. 'payload': {
  9393. 'redirect_uri': auth_bridge.generate_auth_url_user_scope(
  9394. redirect_uri=DEALER_BIND_WALLET_WECHAT_URL)
  9395. }
  9396. })
  9397. @permission_required(ROLE.dealer)
  9398. def verifyNewWalletWechatBindingCallback(request):
  9399. auth_code = request.GET.get('code')
  9400. if not auth_code:
  9401. return JsonErrorResponse(description=u'未收到code,请刷新重试')
  9402. currentDealer = request.user
  9403. auth_bridge = get_wechat_auth_bridge(source=currentDealer, app_type=APP_TYPE.WECHAT_WITHDRAW)
  9404. user_info = auth_bridge.get_user_info(auth_code=auth_code)
  9405. user_info_payload = {
  9406. 'avatar': user_info['avatar'],
  9407. 'sex': user_info['sex'],
  9408. 'nickname': user_info['nickname'],
  9409. 'openId': user_info['openId']
  9410. }
  9411. logger.debug('dealer(id=%s) is binding wechat for messaging, bridge=%s' % (str(request.user.bossId), auth_bridge))
  9412. key = auth_bridge.bound_openid_key
  9413. currentDealer.set_bound_pay_info(key, **user_info_payload)
  9414. currentDealer.save()
  9415. return DealerBindIdResponseRedirect(result='ok')
  9416. @permission_required(ROLE.dealer)
  9417. def selfRechargeCardRecords(request):
  9418. # type: (WSGIRequest)->JsonResponse
  9419. """
  9420. 蓝光国际手动充卡记录查询
  9421. :param request:
  9422. :return:
  9423. """
  9424. ownerId = str(request.user.bossId)
  9425. logicalCode = request.GET['logicalCode']
  9426. pageIndex = int(request.GET.get('pageIndex', 1))
  9427. pageSize = int(request.GET.get('pageSize', 10))
  9428. objs = CardRechargeRecord.objects.filter(ownerId=ownerId, logicalCode=logicalCode, cardId='languang_card_id').order_by('-dateTimeAdded')
  9429. rcdList = []
  9430. total = 0
  9431. for obj in objs:
  9432. total += 1
  9433. rcdList.append({
  9434. 'price': int(float(str(obj.money))),
  9435. 'dateTimeAdded': obj.dateTimeAdded.strftime("%Y-%m-%d %H:%M:%S")
  9436. })
  9437. return JsonResponse({
  9438. 'result': 1,
  9439. 'description': None,
  9440. 'payload': {
  9441. 'total': total,
  9442. 'dataList': rcdList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  9443. }
  9444. })
  9445. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"同步设备电池信息失败"))
  9446. @permission_required(ROLE.dealer, ROLE.subaccount)
  9447. def asyncBatterySnByDevice(request):
  9448. """
  9449. 从设备侧同步电池编号
  9450. :param request:
  9451. :return:
  9452. """
  9453. payload = json.loads(request.body)
  9454. logicalCode = payload.get("logicalCode")
  9455. dealerId = str(request.user.bossId)
  9456. dev = Device.get_dev_by_logicalCode(logicalCode=logicalCode)
  9457. if not dev:
  9458. return JsonErrorResponse(description=u"未找到设备,请您确认设备逻辑码正确")
  9459. if dev.ownerId != dealerId:
  9460. return JsonErrorResponse(description=u"未找到设备,请您确认设备逻辑码正确")
  9461. box = ActionDeviceBuilder.create_action_device(dev)
  9462. if not hasattr(box, "_query_all_battery_imei"):
  9463. return JsonErrorResponse(description=u"该设备不支持导入电池编号,请确认设备逻辑码正确")
  9464. try:
  9465. batteryInfo = box._query_all_battery_imei()
  9466. except ServiceException:
  9467. return JsonErrorResponse(description=u"读取电池信息失败,请重新试试")
  9468. addBatteryLis = list()
  9469. for port, batterySn in batteryInfo.items():
  9470. try:
  9471. battery = Battery.add_from_device(
  9472. batterySn=batterySn,
  9473. devNo=dev.devNo,
  9474. port=port,
  9475. dealerId=dealerId
  9476. )
  9477. except Exception as e:
  9478. logger.exception(e)
  9479. continue
  9480. if not battery:
  9481. continue
  9482. addBatteryLis.append(batterySn)
  9483. message = u"操作成功,此次录入的电池编号为: \n{}".format("\n".join(addBatteryLis))
  9484. return JsonOkResponse(description=message)
  9485. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"录入电池信息失败"))
  9486. @permission_required(ROLE.dealer, ROLE.subaccount)
  9487. def asyncBatterySnByEnter(request):
  9488. """
  9489. 经销商手动录入电池编号
  9490. :param request:
  9491. :return:
  9492. """
  9493. payload = json.loads(request.body)
  9494. batterySn = payload.get("batterySn")
  9495. dealerId = str(request.user.bossId)
  9496. if not Battery.is_battery_sn_format(batterySn):
  9497. return JsonErrorResponse(u"请输入正确的电池编号(15位数字)")
  9498. battery = Battery.add_from_enter(batterySn=batterySn, dealerId=dealerId)
  9499. if not battery:
  9500. return JsonErrorResponse(description=u"请勿重复录入电池编号")
  9501. return JsonOkResponse(description=u"录入成功\n{}".format(batterySn))
  9502. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取电池列表信息失败"))
  9503. @permission_required(ROLE.dealer, ROLE.subaccount)
  9504. def batteryList(request):
  9505. """
  9506. 获取电池列表
  9507. :param request:
  9508. :return:
  9509. """
  9510. dealerId = str(request.user.bossId)
  9511. pageSize = int(request.GET.get("pageSize", 10))
  9512. pageIndex = int(request.GET.get("pageIndex", 1))
  9513. searchKey = request.GET.get("searchKey", "")
  9514. logicalCode = request.GET.get("logicalCode")
  9515. data = list()
  9516. filters = {
  9517. "dealerId": dealerId
  9518. }
  9519. if logicalCode:
  9520. dev = Device.get_dev_by_l(logicalCode)
  9521. if not dev or dev.ownerId != dealerId:
  9522. return JsonOkResponse(payload={"total": 0, "data": data})
  9523. filters.update({"devNo": dev.devNo})
  9524. query = Battery.objects.filter(**filters).search(searchKey)
  9525. total = query.count()
  9526. batteries = query.skip((pageIndex - 1) * pageSize).limit(pageSize)
  9527. for battery in batteries:
  9528. data.append(battery.to_dict())
  9529. return JsonOkResponse(
  9530. payload={
  9531. "total": total,
  9532. "dataList": data
  9533. }
  9534. )
  9535. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"删除电池失败"))
  9536. @permission_required(ROLE.dealer, ROLE.subaccount)
  9537. def deleteBattery(request):
  9538. """
  9539. 删除电池
  9540. :param request:
  9541. :return:
  9542. """
  9543. dealerId = str(request.user.bossId)
  9544. payload = json.loads(request.body)
  9545. batterySn = payload.get("ids")
  9546. if len(batterySn) > 1:
  9547. return JsonErrorResponse(description=u"电池数量超限")
  9548. result = Battery.delete_one(dealerId, batterySn[0])
  9549. if not result:
  9550. return JsonErrorResponse(description=u"删除电池信息失败")
  9551. return JsonErrorResponse(description=u"电池编号<{}>删除成功".format(batterySn[0]))
  9552. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取电池定位失败"))
  9553. @permission_required(ROLE.dealer, ROLE.subaccount)
  9554. def batteryPosition(request):
  9555. """
  9556. 经销商处查看电池的定位
  9557. :param request:
  9558. :return:
  9559. """
  9560. dealerId = str(request.user.bossId)
  9561. batterySn = request.GET.get("batterySn", "")
  9562. battery = Battery.get_one(dealerId=dealerId, batterySn=batterySn)
  9563. if not battery:
  9564. return JsonErrorResponse(description=u"未找到电池,请重新试试")
  9565. # result = BatteryInfo().getBatteryInfo(batterySn).get(batterySn)
  9566. result = BatteryInfo().getBatteryInfo(batterySn).get(batterySn)
  9567. if not result:
  9568. return JsonErrorResponse(description=u"电池定位第三方数据请求失败")
  9569. # TODO zjl 需要对经纬度进行转换
  9570. # TODO 前台做成了分页的形式 暂时就这样吧 后续再修改
  9571. data = {
  9572. "lat": result.get("lat"),
  9573. "lng": result.get("lng"),
  9574. "voltage": result.get("voltage")
  9575. }
  9576. payload = {
  9577. "total": 1,
  9578. "items": [data]
  9579. }
  9580. return JsonOkResponse(payload=payload)
  9581. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置电池失败"))
  9582. @permission_required(ROLE.dealer, ROLE.subaccount)
  9583. def disableBattery(request):
  9584. """
  9585. 经销商标记电池 被标记的电池当再次被放入的时候
  9586. :param request:
  9587. :return:
  9588. """
  9589. dealerId = str(request.user.bossId)
  9590. payload = json.loads(request.body)
  9591. disable = payload.get("disable")
  9592. batterySn = payload.get("batterySn")
  9593. print batterySn, type(batterySn)
  9594. print disable, type(disable)
  9595. for sn in batterySn:
  9596. battery = Battery.get_one(dealerId, sn)
  9597. if not battery:
  9598. return JsonErrorResponse(description=u"未查找到电池数据,请刷新页面重试")
  9599. battery.disable = disable
  9600. return JsonOkResponse()
  9601. @permission_required(ROLE.dealer)
  9602. def createEmptyCardTicket(request):
  9603. json_str = request.body
  9604. json_data = json.loads(json_str)
  9605. number = json_data.get('number')
  9606. card_id = json_data.get('cardId')
  9607. if not str(number).isdigit():
  9608. return JsonErrorResponse(description=u'请输入数字!')
  9609. if int(number) > 50:
  9610. return JsonErrorResponse(description=u'单次发卡数量不能超过50张')
  9611. try:
  9612. card_model = VirtualCard.objects.get(id=card_id)
  9613. except Exception:
  9614. return JsonErrorResponse(description=u'读取虚拟卡失败,请重试')
  9615. attachParas = {}
  9616. attachParas['number'] = int(number)
  9617. attachParas['card_id'] = card_id
  9618. virtual_cards = VirtualCardBuilder.create_virtual_card(request.user, card_model, attachParas)
  9619. return JsonResponse({'result': 0, 'description': '当前生成卡号:%s' % (','.join(virtual_cards))})
  9620. @permission_required(ROLE.dealer, ROLE.subaccount)
  9621. def bindVirtualCardToRechargeIDCard(request):
  9622. payload = json.loads(request.body)
  9623. virtualCardId = payload.get('virtualCardId')
  9624. rechargeIDCardId = payload.get('rechargeIDCardId')
  9625. if virtualCardId is None:
  9626. return JsonErrorResponse(description=u'未找到虚拟卡ID')
  9627. if rechargeIDCardId is None:
  9628. return JsonErrorResponse(description=u'未找到ID实体卡')
  9629. card = Card.objects(id=rechargeIDCardId).first()
  9630. if card is None:
  9631. return JsonErrorResponse(description=u'未找到ID实体卡')
  9632. if card.boundVirtualCardId:
  9633. return JsonErrorResponse(description=u'该卡片已绑定一张虚拟卡')
  9634. if card.cardType != RECHARGE_CARD_TYPE.ID:
  9635. return JsonErrorResponse(description=u'该卡不是ID卡')
  9636. virtualCard = UserVirtualCard.objects(id=virtualCardId).first()
  9637. if virtualCard is None:
  9638. return JsonErrorResponse(description=u'未找到虚拟卡')
  9639. updated = card.bind_virtual_card(virtualCard)
  9640. res = VirtualCardBuilder.active_virtual_card(virtualCardId)
  9641. if updated and res:
  9642. return JsonOkResponse()
  9643. else:
  9644. return JsonErrorResponse(description=u'绑定失败')
  9645. @permission_required(ROLE.dealer)
  9646. def unbindVirtualCardToRechargeIDCard(request):
  9647. json_str = request.body
  9648. json_data = json.loads(json_str)
  9649. card_id = str(json_data.get('cardId'))
  9650. try:
  9651. card = Card.objects.get(id=card_id)
  9652. except Exception:
  9653. return JsonErrorResponse(description=u'数据走丢了,请稍后再试')
  9654. if not card.bound_virtual_card:
  9655. return JsonErrorResponse(description=u'该卡片未绑定优惠卡券')
  9656. res = VirtualCardBuilder.unbind_virtual_card(card)
  9657. if res:
  9658. return JsonOkResponse()
  9659. else:
  9660. return JsonErrorResponse(description=u'解绑失败,请稍后再试')
  9661. @error_tolerate(nil=DefaultJsonErrorResponse)
  9662. @permission_required(ROLE.dealer)
  9663. def getDeviceStockForGoods(request):
  9664. logicalCode = request.GET.get('logicalCode', '')
  9665. pageSize = int(request.GET.get("pageSize", 10))
  9666. pageIndex = int(request.GET.get("pageIndex", 1))
  9667. if not logicalCode:
  9668. return JsonErrorResponse(description=u'参数接口错误')
  9669. devObj = Device.objects.get(logicalCode=logicalCode)
  9670. dataList = []
  9671. for itemTypeId, count in devObj.stockDetailDict.items():
  9672. try:
  9673. itemType = ItemType.objects.get(id=itemTypeId)
  9674. except Exception, e:
  9675. continue
  9676. dataList.append({
  9677. 'quantity':count,
  9678. 'itemId':itemTypeId,
  9679. 'itemName':itemType.title,
  9680. 'itemPrice':itemType.price,
  9681. 'itemPicUrl':itemType.picUrl
  9682. })
  9683. return JsonOkResponse(payload={'total':len(dataList), 'dataList':dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]})
  9684. def addGoodsForStock(request):
  9685. payload = json.loads(request.body)
  9686. logicalCode = payload.get('logicalCode')
  9687. quantity = payload.get('quantity')
  9688. itemId = payload.get('itemId')
  9689. dev = Device.get_dev_by_l(logicalCode)
  9690. devObj = Device.objects.get(logicalCode=logicalCode)
  9691. oldQuantity = devObj.stockDetailDict.get(itemId, 0)
  9692. devObj.stockDetailDict[itemId] = quantity
  9693. try:
  9694. devObj.save()
  9695. except Exception, e:
  9696. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9697. if quantity > oldQuantity:
  9698. stockType = 'add'
  9699. stockNum = quantity - oldQuantity
  9700. elif quantity < oldQuantity:
  9701. stockType = 'remove'
  9702. stockNum = oldQuantity - quantity
  9703. else:
  9704. stockType = ''
  9705. itemObj = ItemType.objects.get(id=itemId)
  9706. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  9707. StockRecord.get_collection().insert(
  9708. {'logicCode': logicalCode, 'imei': dev['devNo'], 'stockType': stockType, 'stockTime': stockTime, 'number': stockNum, 'more':itemObj.title})
  9709. # 刷新总的数目
  9710. allCount = 0
  9711. for count in devObj.stockDetailDict.values():
  9712. allCount += count
  9713. result = Device.update_field(dev_no=devObj.devNo, update=True, quantity=allCount)
  9714. if not result:
  9715. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9716. return JsonOkResponse()
  9717. @error_tolerate(nil=DefaultJsonErrorResponse)
  9718. @permission_required(ROLE.dealer)
  9719. def deleteItemStock(request):
  9720. payload = json.loads(request.body)
  9721. logicalCode = payload.get('logicalCode')
  9722. itemIds = payload.get('itemIds')
  9723. dev = Device.get_dev_by_l(logicalCode)
  9724. devObj = Device.objects.get(logicalCode=logicalCode)
  9725. for itemId in itemIds:
  9726. itemObj = ItemType.objects.get(id=itemId)
  9727. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  9728. StockRecord.get_collection().insert(
  9729. {'logicCode': logicalCode, 'imei': dev['devNo'], 'stockType': 'remove', 'stockTime': stockTime, 'number': devObj.stockDetailDict.get(itemId, 0), 'more':itemObj.title})
  9730. try:
  9731. devObj.stockDetailDict.pop(itemId)
  9732. except Exception, e:
  9733. continue
  9734. try:
  9735. devObj.save()
  9736. except Exception, e:
  9737. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9738. allCount = 0
  9739. for count in devObj.stockDetailDict.values():
  9740. allCount += count
  9741. result = Device.update_field(dev_no=devObj.devNo, update=True, quantity=allCount)
  9742. if not result:
  9743. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9744. return JsonOkResponse()
  9745. @error_tolerate(nil=DefaultJsonErrorResponse)
  9746. @permission_required(ROLE.dealer)
  9747. def updateStockQuantityForGoods(request):
  9748. payload = json.loads(request.body)
  9749. logicalCode = payload.get('logicalCode')
  9750. quantity = payload.get('quantity')
  9751. itemIds = payload.get('itemIds')
  9752. dev = Device.get_dev_by_l(logicalCode)
  9753. oldQuantity = dev['quantity']
  9754. devObj = Device.objects.get(logicalCode=logicalCode)
  9755. for itemId in itemIds:
  9756. devObj.stockDetailDict[itemId] = quantity
  9757. if quantity > oldQuantity:
  9758. stockType = 'add'
  9759. stockNum = quantity - oldQuantity
  9760. elif quantity < oldQuantity:
  9761. stockType = 'remove'
  9762. stockNum = oldQuantity - quantity
  9763. else:
  9764. stockType = ''
  9765. try:
  9766. itemObj = ItemType.objects.get(id=itemId)
  9767. except Exception, e:
  9768. continue
  9769. stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  9770. StockRecord.get_collection().insert(
  9771. {'logicCode': logicalCode, 'imei': dev['devNo'], 'stockType': stockType, 'stockTime': stockTime, 'number': stockNum, 'more':itemObj.title})
  9772. try:
  9773. devObj.save()
  9774. except Exception, e:
  9775. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9776. allCount = 0
  9777. for count in devObj.stockDetailDict.values():
  9778. allCount += count
  9779. result = Device.update_field(dev_no=devObj.devNo, update=True, quantity=allCount)
  9780. if not result:
  9781. return JsonResponse({'result': 0, 'description': u'更新库存失败,请重试'})
  9782. return JsonOkResponse()
  9783. @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"没有余额卡"))
  9784. @permission_required(ROLE.dealer)
  9785. def getCardListForDevice(request):
  9786. """
  9787. 给中山绿智做的经销商充值
  9788. """
  9789. logicalCode = request.GET.get("logicalCode")
  9790. dealer = Dealer.objects(id=str(request.user.id)).first()
  9791. if dealer is None:
  9792. return JsonErrorResponse(description=u"设备的经销商不存在")
  9793. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  9794. dev = Device.get_dev(devNo)
  9795. if dev is None:
  9796. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  9797. if dev['ownerId'] != str(request.user.bossId):
  9798. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  9799. box = ActionDeviceBuilder.create_action_device(dev)
  9800. try:
  9801. res = box.get_no_balance_list(devNo)
  9802. except ServiceException, e:
  9803. logger.info('error happened, error=%s' % (e,))
  9804. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  9805. except Exception, e:
  9806. logger.exception('error happened, error=%s' % (e,))
  9807. return JsonResponse({'result': 0, 'description': u'系统异常,请检查输入参数,或者稍后重试', 'payload': {}})
  9808. return JsonResponse({'result': 1, 'description': None, 'payload': {"total":1, "dataList":res}})
  9809. @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"没有余额卡"))
  9810. @permission_required(ROLE.dealer)
  9811. def chargeInsufficientBalanceCard(request):
  9812. """
  9813. 给中山绿智做的经销商充值
  9814. """
  9815. payload = json.loads(request.body)
  9816. logicalCode = payload.get("logicalCode")
  9817. amount = payload.get("amount")
  9818. cardIds = payload.get("cardIds")
  9819. if not logicalCode or not amount or not cardIds:
  9820. return JsonErrorResponse(description=u"请完整的传入参数")
  9821. dealer = Dealer.objects(id=str(request.user.id)).first()
  9822. if dealer is None:
  9823. return JsonErrorResponse(description=u"设备的经销商不存在")
  9824. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  9825. dev = Device.get_dev(devNo)
  9826. if dev is None:
  9827. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  9828. if dev['ownerId'] != str(request.user.bossId):
  9829. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  9830. box = ActionDeviceBuilder.create_action_device(dev)
  9831. try:
  9832. res = box.remote_charge_ic_card_by_dealer(cardIds, amount)
  9833. except ServiceException, e:
  9834. logger.info('error happened, error=%s' % (e,))
  9835. return JsonResponse({'result': 0, 'description': e.result.get('description'), 'payload': {}})
  9836. except Exception, e:
  9837. logger.exception('error happened, error=%s' % (e,))
  9838. return JsonResponse({'result': 0, 'description': u'系统异常,请检查输入参数,或者稍后重试', 'payload': {}})
  9839. return JsonResponse({'result': 1, 'description': None})
  9840. @permission_required(ROLE.dealer)
  9841. def getDeviceLocker(request):
  9842. """
  9843. 储物柜的大小格子配置
  9844. """
  9845. logicalCode = request.GET.get("logicalCode[]")
  9846. if isinstance(logicalCode, (str, unicode)):
  9847. dev = Device.objects.filter(logicalCode=logicalCode).first()
  9848. sizeInfo = dev.otherConf.get("sizeInfo", [])
  9849. if not sizeInfo:
  9850. for i in xrange(1, 25):
  9851. item = {"port":str(i), "size":"small"}
  9852. sizeInfo.append(item)
  9853. dev.otherConf["sizeInfo"] = sizeInfo
  9854. dev.save()
  9855. dev.invalid_device_cache(dev.devNo)
  9856. return JsonResponse({
  9857. "result": 1,
  9858. "description": "",
  9859. "payload": {
  9860. "dataList": sizeInfo
  9861. }
  9862. })
  9863. else: # 批量获取
  9864. pass
  9865. @permission_required(ROLE.dealer)
  9866. def saveDeviceLocker(request):
  9867. """
  9868. 储物柜的大小格子配置
  9869. """
  9870. payload = json.loads(request.body)
  9871. logicalCodes = payload.get("logicalCode")
  9872. portList = payload.get("portList")
  9873. for item in portList:
  9874. item["port"] = str(item["port"])
  9875. if not logicalCodes:
  9876. return JsonResponse({"result": 2,
  9877. "description": "设备号错误,请重试......", })
  9878. if not portList:
  9879. return JsonResponse({"result": 2,
  9880. "description": "当前没有设置任何设备参数", })
  9881. for item in logicalCodes:
  9882. dev = Device.objects.filter(logicalCode=item).first()
  9883. dev.otherConf["sizeInfo"] = portList
  9884. dev.otherConf["actualPortNum"] = len(portList)
  9885. dev.save()
  9886. Device.invalid_device_cache(dev.devNo)
  9887. return JsonResponse({"result": 1,
  9888. "description": "", })
  9889. # 经销商获取提现短信验证码
  9890. @error_tolerate(nil=DefaultJsonErrorResponse)
  9891. @permission_required(ROLE.dealer)
  9892. def getEditMonitorCode(request):
  9893. # type: (WSGIRequest)->JsonResponse
  9894. currentDealer = request.user # type: Dealer
  9895. if currentDealer.abnormal:
  9896. return JsonErrorResponse(description=u'该帐号资金异常,请合法经营。具体请联系客服')
  9897. toNumber = request.GET.get('phone')
  9898. if not toNumber:
  9899. toNumber = request.user.monitorPhone
  9900. if not toNumber:
  9901. return JsonErrorResponse(description=u'没有找到提现审批人的手机号')
  9902. agentId = request.user.agentId
  9903. agent = Agent.get_agent(agentId)
  9904. productName = agent['productName']
  9905. status, msg = dealerEditMonitorSMSProvider.get(phoneNumber=toNumber,
  9906. productName=productName,
  9907. vendor=SysParas.get_sms_vendor(request.user.smsVendor))
  9908. if not status:
  9909. return JsonErrorResponse(description=msg)
  9910. else:
  9911. return JsonOkResponse()
  9912. @error_tolerate(nil=DefaultJsonErrorResponse)
  9913. @permission_required(ROLE.dealer)
  9914. def getDealerMonitor(request):
  9915. return JsonOkResponse(payload={'phone':request.user.monitorPhone if request.user.monitorPhone else None})
  9916. @error_tolerate(nil=DefaultJsonErrorResponse)
  9917. @permission_required(ROLE.dealer)
  9918. def editMonitor(request):
  9919. dealer = request.user
  9920. if request.GET.get('oper') == 'delete':
  9921. code = request.GET.get('code')
  9922. phone = dealer.monitorPhone
  9923. if not phone:
  9924. return JsonErrorResponse(description=u'没有找到提现审批人的手机号,无法清除')
  9925. status, msg = dealerEditMonitorSMSProvider.verify(phone, code)
  9926. if not status:
  9927. return JsonErrorResponse(msg)
  9928. dealer.monitorPhone = ''
  9929. dealer.save()
  9930. return JsonOkResponse()
  9931. if not request.GET.get('phone'):
  9932. return JsonErrorResponse(description=u'没有找到提现审批人的手机号')
  9933. phone = request.GET.get('phone')
  9934. code = request.GET.get('code')
  9935. status, msg = dealerEditMonitorSMSProvider.verify(phone, code)
  9936. if not status:
  9937. return JsonErrorResponse(msg)
  9938. dealer.monitorPhone = phone
  9939. dealer.save()
  9940. return JsonOkResponse()
  9941. @error_tolerate(nil=DefaultJsonErrorResponse)
  9942. @permission_required(ROLE.dealer)
  9943. def bindParentNode(request):
  9944. payload = json.loads(request.body)
  9945. parentNode = payload.get("parentLogicalCode")
  9946. node = payload.get("childLogicalCode")
  9947. category = payload.get("category")
  9948. try:
  9949. if category == "CM":
  9950. # 诚马的插座 采用主绑定从的方式 进行绑定
  9951. master, sub = Device.get_dev_by_l(parentNode), Device.get_dev_by_l(node)
  9952. if not all([master, sub]):
  9953. return JsonErrorResponse(description=u"绑定设备错误(10001)")
  9954. master.deviceAdapter.add_node(sub)
  9955. elif category == "BL":
  9956. # 这里有3种情况,1、插座和网关一体板,自己绑自己;2、其他插座绑定纯网关的逻辑编码;3、其他插座绑一体板的二维码
  9957. gatewayDev = Device.get_dev_by_l(parentNode) # type: DeviceDict
  9958. if gatewayDev is None:
  9959. Device.get_collection().update({'logicalCode':node}, {'$set':{'gateImei':parentNode}})
  9960. gatewayPlugDev = Device.get_dev_by_l(node)
  9961. box = gatewayPlugDev.deviceAdapter
  9962. box.add_node(gatewayPlugDev['devNo'])
  9963. else:
  9964. box = gatewayDev.deviceAdapter # type: ChargingGatewayBox
  9965. box.add_node(Device.get_dev_by_l(node)['devNo'])
  9966. else:
  9967. return JsonErrorResponse(description=u"错误的节点绑定类型")
  9968. except ServiceException as se:
  9969. return JsonErrorResponse(description=se.result["description"])
  9970. return JsonOkResponse()
  9971. @error_tolerate(nil=DefaultJsonErrorResponse)
  9972. @permission_required(ROLE.dealer)
  9973. def unbindParentNode(request):
  9974. payload = json.loads(request.body)
  9975. node = payload.get("logicalCode")
  9976. nodeDev = Device.get_dev_by_l(node) # type: DeviceDict
  9977. box = nodeDev.deviceAdapter # type: ChargingBox
  9978. box.remove_from_gateway()
  9979. return JsonOkResponse()
  9980. @error_tolerate(nil=DefaultJsonErrorResponse)
  9981. @permission_required(ROLE.dealer)
  9982. def getGateway(request):
  9983. payload = json.loads(request.body)
  9984. lc = payload.get("logicalCode")
  9985. devObj = Device.objects.get(logicalCode=lc)
  9986. if devObj.gatewayNode == '':
  9987. return JsonResponse({"result": 1, "description": "", "payload": {}})
  9988. gatewayDev = Device.get_dev(devObj.gatewayNode) # type: DeviceDict
  9989. box = gatewayDev.deviceAdapter # type: ChargingGatewayBox
  9990. devInfo = box.get_signal()
  9991. data = {
  9992. 'logicalCode':gatewayDev['logicalCode'],
  9993. 'gatewaySignal':devInfo['signal'],
  9994. 'groupName':gatewayDev['groupName']
  9995. }
  9996. return JsonResponse({"result": 1, "description": "", "payload": data})
  9997. @error_tolerate(nil=DefaultJsonErrorResponse)
  9998. @permission_required(ROLE.dealer)
  9999. def getNodeList(request):
  10000. """
  10001. 获取主机的节点列表
  10002. """
  10003. lc = request.GET.get("logicalCode")
  10004. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  10005. box = dev.deviceAdapter # type: ChargingGatewayBox
  10006. nodeList = box.get_node_list()
  10007. dataList = []
  10008. devDict = {}
  10009. for node in nodeList:
  10010. nodeDev = Device.get_dev(node['devNo']) # type: DeviceDict
  10011. if nodeDev is None:
  10012. continue
  10013. if not nodeDev.is_registered:
  10014. _temp = {
  10015. 'id': node.devNo,
  10016. 'groupId': "",
  10017. 'logicalCode': nodeDev.logicalCode,
  10018. 'devType': nodeDev.devTypeName,
  10019. "online": nodeDev.online,
  10020. "registered": nodeDev.is_registered,
  10021. "signal": nodeDev.signal
  10022. }
  10023. else:
  10024. _temp = {
  10025. 'id': node.devNo,
  10026. 'groupId': nodeDev.group.groupId,
  10027. 'logicalCode': nodeDev.logicalCode,
  10028. 'devType': nodeDev.devTypeName,
  10029. "online": nodeDev.online,
  10030. "registered": nodeDev.is_registered,
  10031. "signal": nodeDev.signal
  10032. }
  10033. if nodeDev['groupId'] in devDict:
  10034. devDict[nodeDev['groupId']].append(node)
  10035. else:
  10036. devDict[nodeDev['groupId']] = [node]
  10037. dataList.append(node)
  10038. natural_sort(array=dataList, key='logicalCode', reverse=False)
  10039. return JsonResponse({
  10040. "result": 1,
  10041. "description": None,
  10042. 'payload': {
  10043. "total": len(dataList),
  10044. "groupCount": len(devDict.keys()),
  10045. "dataList": dataList
  10046. }
  10047. })
  10048. @error_tolerate(nil=DefaultJsonErrorResponse)
  10049. @permission_required(ROLE.dealer)
  10050. def getPortParam(request):
  10051. payload = json.loads(request.body)
  10052. lc = payload.get("logicalCode")[0]
  10053. portIndex = payload.get("port")
  10054. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  10055. box = dev.deviceAdapter # type: ChargingBox
  10056. config = box.get_port_config(portIndex)
  10057. return JsonResponse({"result": 1, "description": "", "payload": config})
  10058. @error_tolerate(nil=DefaultJsonErrorResponse)
  10059. @permission_required(ROLE.dealer)
  10060. def setPortParam(request):
  10061. payload = json.loads(request.body)
  10062. lc = payload.get("logicalCode")[0]
  10063. portIndex = payload.get("port")
  10064. maxCurrent = payload.get('max_current', 10)
  10065. maxPower = payload.get('max_power', 1000)
  10066. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  10067. box = dev.deviceAdapter # type: ChargingBox
  10068. box.set_port_config(portIndex, {'max_power':int(maxPower), 'max_current':int(maxCurrent)})
  10069. return JsonOkResponse()
  10070. @permission_required(ROLE.dealer, ROLE.subaccount)
  10071. def beAuthLogin(request):
  10072. oper_id = request.GET.get('dealerId')
  10073. # 校验经销商是否存在
  10074. dealer = Dealer.objects.filter(id=oper_id).first()
  10075. if not dealer:
  10076. return ErrorResponseRedirect(error=cn('当前经销不存在'))
  10077. # 校验当前用户是否已经是授权登入的
  10078. session = DealerSessionBuilder(request)
  10079. if session.is_dealer_trustee():
  10080. return ErrorResponseRedirect(error=cn('授权人页面不允许切换'))
  10081. role = PermissionRole.objects.filter(dealerId=str(dealer.id), operId=str(request.user.id)).first()
  10082. if role:
  10083. if role.isActive:
  10084. session.check_out_to_dealer_trustee(oper_id)
  10085. else:
  10086. if role.authorizeType == 'dealer_to_dealer':
  10087. return ErrorResponseRedirect(error=cn(u'请联系您的授权经销商给您配置权限'))
  10088. elif role.authorizeType == 'dealer_to_subAccount':
  10089. return ErrorResponseRedirect(error=cn(u'请联系您的主经销商同意此授权关系'))
  10090. else:
  10091. # 没有权限
  10092. return ErrorResponseRedirect(error=cn(u'当前授权已失效'))
  10093. return FrontEndResponseRedirect(add_query('/app/index.html', {}))
  10094. @permission_required(ROLE.dealer)
  10095. def loginMyPrimaryAccount(request):
  10096. session = DealerSessionBuilder(request)
  10097. if session.is_dealer_trustee():
  10098. result = session.check_out_to_dealer_master()
  10099. if not result:
  10100. return ErrorResponseRedirect(error=cn(u'验证失败,请重新登入'))
  10101. else:
  10102. pass
  10103. # return ErrorResponseRedirect(error=cn(u'当前已经是主账户'))
  10104. # 无需切换已经是主账户
  10105. return FrontEndResponseRedirect(add_query('/app/index.html', {}))
  10106. @permission_required(ROLE.dealer)
  10107. def addOrEditOperatorPermission(request):
  10108. session = DealerSessionBuilder(request)
  10109. if session.is_dealer_trustee():
  10110. # 操作员无权限修改改权限
  10111. return ErrorResponseRedirect(error=cn(u'您当前无权修改授权权限'))
  10112. else:
  10113. permissionId = request.POST.get('permissionId')
  10114. permissionDict = request.POST.get('permissions')
  10115. PermissionRule.objects.get(id=permissionId, dealerId=str(request.user.id)).update(permissionDict=permissionDict)
  10116. @permission_required(ROLE.dealer)
  10117. def getAccountPermissionByAuthId(request):
  10118. id = request.GET.get('id')
  10119. role = PermissionRole.objects.filter(operId=id, dealerId=str(request.user.id)).first()
  10120. if not role:
  10121. return JsonResponse({'result': 0, 'description': '您的当前授权已失效'})
  10122. rule = PermissionRule.objects.filter(id=role.permissionRuleId).first()
  10123. return JsonResponse({'result': 1, 'description': '', 'payload': rule.get_permissionDict()})
  10124. @permission_required(ROLE.dealer)
  10125. def saveAccountPermissionByAuthId(request):
  10126. payload = json.loads(request.body)
  10127. id = payload.pop('id', None)
  10128. role = PermissionRole.objects.filter(operId=id, dealerId=str(request.user.id)).first()
  10129. if role:
  10130. if role.authorizeType == 'dealer_to_dealer': # 经销商对经销商 直接激活此次授权
  10131. role.update(isActive=True)
  10132. elif role.authorizeType == 'dealer_to_subAccount': # 经销商对子账号 需要子账号的主账号同意
  10133. pass
  10134. rule = PermissionRule.objects.filter(id=role.permissionRuleId).update(permissionDict=payload)
  10135. return JsonResponse({'result': 1, 'description': '', 'payload':{}})
  10136. else:
  10137. return JsonResponse({'result': 0, 'description': '权限配置失败', 'payload': {}})
  10138. @permission_required(ROLE.dealer)
  10139. def getAuthList(request):
  10140. dealer_id = PermissionRole.get_auth_to_dealer(dealerId=str(request.user.id))
  10141. dealers = Dealer.objects(id__in=dealer_id)
  10142. total = dealers.count()
  10143. pageSize = int(request.GET.get('pageSize', 10))
  10144. pageIndex = int(request.GET.get('pageIndex', 1))
  10145. dataList = []
  10146. for dealer in dealers:
  10147. item = {
  10148. 'id': str(dealer.id),
  10149. 'nickname': dealer.nickname,
  10150. 'username': dealer.username,
  10151. 'avatarUrl': dealer.my_avatar if dealer.my_avatar else settings.DEFAULT_AVATAR_URL,
  10152. }
  10153. dataList.append(item)
  10154. subAccount_id = PermissionRole.get_auth_to_sub(dealerId=str(request.user.id))
  10155. subAccounts = SubAccount.objects(id__in=subAccount_id)
  10156. total += subAccounts.count()
  10157. for subAccount in subAccounts:
  10158. item = {
  10159. 'id': str(subAccount.id),
  10160. 'nickname': subAccount.nickname,
  10161. 'username': subAccount.username,
  10162. 'avatarUrl': subAccount.my_avatar if subAccount.my_avatar else settings.DEFAULT_AVATAR_URL,
  10163. }
  10164. dataList.append(item)
  10165. payload = {
  10166. 'total': total,
  10167. 'dealerId': str(request.user.id),
  10168. 'agentId': request.user.agentId,
  10169. 'dataList': dataList[pageIndex * pageSize - pageSize: pageIndex * pageSize ]
  10170. }
  10171. return JsonResponse({'result': 1, 'description': '', 'username':request.user.username, 'payload': payload})
  10172. @permission_required(ROLE.dealer, ROLE.subaccount)
  10173. def getBeAuthList(request):
  10174. if request.user.role == 'dealer':
  10175. dealer_id = PermissionRole.get_is_auth_list(operId=str(request.user.id), authorizeType='dealer_to_dealer')
  10176. elif request.user.role == 'subaccount':
  10177. dealer_id = PermissionRole.get_is_auth_list(operId=str(request.user.id), authorizeType='dealer_to_subAccount')
  10178. else:
  10179. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10180. dealers = Dealer.objects(id__in=dealer_id)
  10181. total = dealers.count()
  10182. payload = {
  10183. 'total': total,
  10184. 'dealerId': str(request.user.id),
  10185. 'agentId': request.user.agentId
  10186. }
  10187. pageSize = int(request.GET.get('pageSize', 10))
  10188. pageIndex = int(request.GET.get('pageIndex', 1))
  10189. dataList = []
  10190. for dealer in dealers.paginate(pageIndex=pageIndex, pageSize=pageSize):
  10191. item = {
  10192. 'dealerId': str(dealer.id),
  10193. 'nickname': dealer.nickname,
  10194. 'username': dealer.username,
  10195. 'avatarUrl': dealer.my_avatar if dealer.my_avatar else settings.DEFAULT_AVATAR_URL,
  10196. }
  10197. dataList.append(item)
  10198. payload['dataList'] = dataList
  10199. return JsonResponse({'result': 1, 'description': '', 'username': request.user.username, 'payload': payload})
  10200. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10201. @permission_required(ROLE.dealer)
  10202. def getMonthlyPackageTemp(request):
  10203. """
  10204. 获取包月套餐
  10205. :param request:
  10206. :return:
  10207. """
  10208. dealerId = str(request.user.bossId)
  10209. dealer = Dealer.objects.get(id=dealerId)
  10210. monthlyPackages = dealer.monthlyPackage
  10211. dataList = [_package.to_dict() for _package in monthlyPackages]
  10212. return JsonOkResponse(payload={"dataList": dataList})
  10213. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10214. @permission_required(ROLE.dealer)
  10215. def getMonthlyPackageTempDetail(request):
  10216. monthlyPackageId = request.GET.get("id", "")
  10217. monthlyPackage = MonthlyPackageTemp.get_package_by_id(monthlyPackageId)
  10218. if not monthlyPackage or monthlyPackage.ownerId != str(request.user.bossId):
  10219. return JsonErrorResponse(description=u"未找到相应模板套餐,请刷新重试")
  10220. return JsonOkResponse(payload=monthlyPackage.to_dict())
  10221. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10222. @permission_required(ROLE.dealer)
  10223. def saveMonthlyPackageTemp(request):
  10224. """
  10225. 保存包月套餐模板
  10226. :param request:
  10227. :return:
  10228. """
  10229. payload = json.loads(request.body)
  10230. packageId = payload.pop("id", "")
  10231. monthlyPackage = MonthlyPackageTemp.get_package_by_id(packageId)
  10232. if not monthlyPackage or monthlyPackage.ownerId != str(request.user.bossId):
  10233. return JsonErrorResponse(description=u"未找到相应模板套餐,请刷新重试")
  10234. # 修改包月的模板套餐
  10235. monthlyPackage.update_by_fields(**payload)
  10236. return JsonOkResponse()
  10237. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10238. @permission_required(ROLE.dealer)
  10239. def delMonthlyPackageTemp(request):
  10240. """
  10241. 经销商删除包月套餐模板
  10242. :param request:
  10243. :return:
  10244. """
  10245. payload = json.loads(request.body)
  10246. packageId = payload.get("id", "")
  10247. monthlyPackage = MonthlyPackageTemp.get_package_by_id(packageId)
  10248. if not monthlyPackage:
  10249. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10250. if monthlyPackage.ownerId != str(request.user.bossId):
  10251. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10252. # 默认模板无法删除
  10253. if monthlyPackage.isDefault:
  10254. return JsonErrorResponse(description=u"默认包月模板无法删除")
  10255. # 需要将关联此模板的地址组的包月信息全部清空 置为默认的
  10256. groupIds = Group.get_group_ids_of_dealer(str(request.user.bossId))
  10257. Group.objects.filter(id__in=groupIds, monthlyPackage=monthlyPackage).update(monthlyPackage=None)
  10258. # 最后将改套餐置为 idDelete
  10259. monthlyPackage.update(isDelete=1)
  10260. return JsonOkResponse()
  10261. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10262. @permission_required(ROLE.dealer)
  10263. def setDefaultMonthlyPackageTemp(request):
  10264. """
  10265. 经销商 将包月套餐设置成默认的套餐
  10266. :param request:
  10267. :return:
  10268. """
  10269. payload = json.loads(request.body)
  10270. packageId = payload.get("id", "")
  10271. monthlyPackage = MonthlyPackageTemp.get_package_by_id(packageId)
  10272. if not monthlyPackage:
  10273. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10274. if monthlyPackage.ownerId != str(request.user.bossId):
  10275. return JsonErrorResponse(description=u"未找到相应包月模板,请刷新重试")
  10276. monthlyPackage.set_default()
  10277. return JsonOkResponse()
  10278. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10279. @permission_required(ROLE.dealer)
  10280. def addGroupToMonthlyPackageTemp(request):
  10281. """
  10282. 添加设备 到 包月套餐
  10283. :param request:
  10284. :return:
  10285. """
  10286. payload = json.loads(request.body)
  10287. packageId = payload.get("packageId", "")
  10288. groupIds = payload.get("groupId", "")
  10289. groups = list()
  10290. for _groupId in groupIds:
  10291. group = Group.get_dealer_group(str(request.user.bossId), id=_groupId.get("groupId", ""))
  10292. if not group:
  10293. return JsonErrorResponse(description=u"未找到相应的设备组,请刷新重试")
  10294. groups.append(group)
  10295. monthlyPackage = MonthlyPackageTemp.get_dealer_package(ownerId=str(request.user.bossId), id=packageId)
  10296. if not monthlyPackage:
  10297. return JsonErrorResponse(description=u"未找到相应套餐,请刷新重试")
  10298. for _group in groups:
  10299. _group.monthlyRule = monthlyPackage
  10300. return JsonOkResponse()
  10301. @error_tolerate(nil=DefaultJsonErrorResponse, logger=logger)
  10302. @permission_required(ROLE.dealer)
  10303. def addMonthlyPackageTemp(request):
  10304. ownerId = str(request.user.bossId)
  10305. payload = json.loads(request.body)
  10306. monthlyPackage = MonthlyPackageTemp.create_by_fields(ownerId=ownerId, **payload)
  10307. return JsonOkResponse(payload={"packageId": str(monthlyPackage.id)})
  10308. @permission_required(ROLE.dealer)
  10309. def deleteAuth(request):
  10310. session = DealerSessionBuilder(request)
  10311. if session.is_dealer_trustee():
  10312. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10313. if request.method != 'POST':
  10314. return ErrorResponseRedirect(error=cn(u'异常访问'))
  10315. payload = json.loads(request.body)
  10316. operIds = payload.get('ids')
  10317. try:
  10318. PermissionRole.delete_role_permission(operIds=operIds, dealerId=str(request.user.id))
  10319. except Exception:
  10320. return JsonResponse({'result': 0, 'description': '扫码识别失败,请重试', 'payloay':{}})
  10321. return JsonResponse({'result': 1, 'description': '成功', 'payload':{}})
  10322. @permission_required(ROLE.dealer, ROLE.subaccount)
  10323. def toAuthToken(request):
  10324. session = DealerSessionBuilder(request)
  10325. if session.is_dealer_trustee():
  10326. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10327. else:
  10328. if request.user.role == 'dealer':
  10329. dealerId = str(request.user.id)
  10330. payload = {'oper_id':dealerId, 'role':'dealer'}
  10331. elif request.user.role == 'subaccount':
  10332. subaccount = str(request.user.id)
  10333. payload = {'oper_id': subaccount, 'role': 'subaccount'}
  10334. else:
  10335. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10336. token = MyToken.encode(payload)
  10337. logger.info(token)
  10338. return JsonResponse({ 'result': 1, 'description': None, 'payload': {'dealerId': 'xxx', 'token': token}})
  10339. @permission_required(ROLE.dealer)
  10340. def getOtherDealerAuth(request):
  10341. # 经销商扫经销商授权
  10342. scannedURL = request.GET.get('url', None)
  10343. if not scannedURL:
  10344. return JsonResponse({'result': 100, 'description': u'错误的二维码或二维码已损坏'})
  10345. from urlparse import unquote
  10346. scannedURL = unquote(scannedURL)
  10347. logger.debug('scan url is {}'.format(scannedURL))
  10348. return FrontEndResponseRedirect(add_query(scannedURL, {}))
  10349. @permission_required(ROLE.dealer)
  10350. def toAuth(request):
  10351. master_id = str(request.user.id)
  10352. token = request.GET.get('token', None)
  10353. if not token:
  10354. return JsonResponse({'result': 0, 'description': '扫码识别失败,请重试', 'payload': {}})
  10355. try:
  10356. payload = MyToken.decode(token)
  10357. except Exception as e:
  10358. logger.info('toAuth token is invalid..')
  10359. payload = {}
  10360. if not payload:
  10361. return JsonResponse({'result': 0, 'description': '二维码已失效,请重新添加二维码!!', 'payload': {}})
  10362. role = payload.get('role')
  10363. oper_id = payload.get('oper_id')
  10364. if role == 'dealer':
  10365. if PermissionRole.objects.filter(dealerId=master_id, operId=oper_id).first():
  10366. PermissionRole.objects.filter(dealerId=master_id, operId=oper_id).update(isActive=True)
  10367. return JsonResponse({'result': 0, 'description': '已添加授权人!!', 'payload': {}})
  10368. else:
  10369. PermissionRole.add_dealer_role(oper_id, master_id)
  10370. return JsonResponse({'result': 0, 'description': '授权人添加成功', 'payload':{}})
  10371. elif role == 'subaccount':
  10372. if PermissionRole.objects.filter(dealerId=master_id, operId=oper_id).first():
  10373. return JsonResponse({'result': 1, 'description': '已添加授权人!!', 'payload': {}})
  10374. else:
  10375. PermissionRole.add_subAccount_role(oper_id, master_id)
  10376. return JsonResponse({'result': 1, 'description': '授权人添加成功,等待子账号主经销商同意', 'payload': {}})
  10377. @permission_required(ROLE.dealer)
  10378. def getSubAccountBeAuthList(request):
  10379. subAccountId = request.GET.get('id')
  10380. master_id = str(request.user.id)
  10381. subAccount = SubAccount.objects.filter(id=subAccountId).first()
  10382. if not subAccount:
  10383. return JsonResponse({'result': 0, 'description': '扫码识别失败,请重试', 'payloay':{}})
  10384. pageSize = int(request.GET.get('pageSize', 10))
  10385. pageIndex = int(request.GET.get('pageIndex', 1))
  10386. roles = PermissionRole.objects.filter(operId=subAccountId, authorizeType='dealer_to_subAccount')
  10387. count = roles.count()
  10388. dataList = []
  10389. for role in roles.paginate(pageIndex=pageIndex, pageSize=pageSize):
  10390. dealer = Dealer.objects.filter(id=role.dealerId).first()
  10391. if dealer:
  10392. item = {
  10393. 'id': str(dealer.id),
  10394. 'nickname': dealer.nickname,
  10395. 'username': dealer.username,
  10396. 'avatarUrl': dealer.my_avatar if dealer.my_avatar else settings.DEFAULT_AVATAR_URL,
  10397. 'status': 'agreed' if role.isActive else '',
  10398. }
  10399. dataList.append(item)
  10400. return JsonResponse({'result':1, 'username':subAccount.username, 'payload':{'dealerId':subAccount.bossId, 'agentId':subAccount.agentId, 'dataList':dataList}})
  10401. @permission_required(ROLE.dealer)
  10402. def agreeSubAccountBeAuth(request):
  10403. session = DealerSessionBuilder(request)
  10404. if session.is_dealer_trustee():
  10405. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10406. if request.method != 'POST':
  10407. return ErrorResponseRedirect(error=cn(u'异常访问'))
  10408. payload = json.loads(request.body)
  10409. subAccountId = payload.get('subAccountId')
  10410. authDealerId = payload.get('authDealerId')
  10411. if not subAccountId or not authDealerId:
  10412. return JsonResponse({'result': 1, 'description': '授权失败,请稍后再试', 'payload': {}})
  10413. PermissionRole.objects.filter(operId=subAccountId, dealerId=authDealerId).update(isActive=True)
  10414. return JsonResponse({'result': 1, 'description': '成功', 'payload':{}})
  10415. @permission_required(ROLE.dealer)
  10416. def disagreeSubAccountBeAuth(request):
  10417. session = DealerSessionBuilder(request)
  10418. if session.is_dealer_trustee():
  10419. return ErrorResponseRedirect(error=cn(u'您无权限进行此操作'))
  10420. if request.method != 'POST':
  10421. return ErrorResponseRedirect(error=cn(u'异常访问'))
  10422. payload = json.loads(request.body)
  10423. subAccountId = payload.get('subAccountId')
  10424. authDealerId = payload.get('authDealerId')
  10425. if not subAccountId or not authDealerId:
  10426. return JsonResponse({'result': 1, 'description': '授权失败,请稍后再试', 'payload': {}})
  10427. PermissionRole.objects.filter(operId=subAccountId, dealerId=authDealerId).update(isActive=False)
  10428. return JsonResponse({'result': 1, 'description': '成功', 'payload': {}})
  10429. @permission_required(ROLE.dealer)
  10430. def toOtherDealerAuth(request):
  10431. # 子账号授权
  10432. scannedURL = request.GET.get('url', None)
  10433. if not scannedURL:
  10434. return JsonResponse({'result': 100, 'description': u'错误的二维码或二维码已损坏'})
  10435. from urlparse import unquote
  10436. scannedURL = unquote(scannedURL)
  10437. logger.debug('scan url is {}'.format(scannedURL))
  10438. return FrontEndResponseRedirect(add_query(scannedURL, {}))
  10439. @permission_required(ROLE.dealer, ROLE.subaccount)
  10440. def getLastVirtualCard(request):
  10441. """
  10442. 获取 经销商自己配置的虚拟卡的模板
  10443. :param request:
  10444. :return:
  10445. """
  10446. obj = VirtualCard.get_last(str(request.user.bossId))
  10447. if obj:
  10448. data = obj.to_dict()
  10449. return JsonOkResponse(payload=data)
  10450. else:
  10451. data = {
  10452. 'cardName': u"时长套餐",
  10453. 'price': 30,
  10454. 'periodDays': 30,
  10455. 'expiredTime': (datetime.datetime.now() + datetime.timedelta(days=30)).strftime("%Y-%m-%d"),
  10456. 'dealerDesc': "",
  10457. 'userDesc': "",
  10458. 'dayQuota': [],
  10459. 'quota': [],
  10460. 'sharedMembersCount': 3,
  10461. 'userLimit': 3,
  10462. }
  10463. return JsonOkResponse(payload=data)
  10464. @permission_required(ROLE.dealer, ROLE.subaccount)
  10465. def getDeviceWarning(request):
  10466. """
  10467. 获取设备端的告警信息
  10468. :param request:
  10469. :return:
  10470. """
  10471. logicalCode = request.GET.get("logicalCode")
  10472. dev = Device.get_dev_by_l(logicalCode)
  10473. if not dev:
  10474. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10475. if dev.ownerId != str(request.user.bossId):
  10476. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10477. warningInfo = Device.get_dev_warning_cache(dev.devNo)
  10478. portWarning = list()
  10479. deviceWarning = dict()
  10480. for _part, _warning in warningInfo.items():
  10481. if not _warning:
  10482. continue
  10483. _newWarning = {
  10484. "warningPart": _part,
  10485. "warningStatus": _warning["warningStatus"],
  10486. "warningDesc": _warning["warningDesc"],
  10487. "warningTime": _warning["warningTime"]
  10488. }
  10489. if _part.isdigit():
  10490. portWarning.append(_newWarning)
  10491. else:
  10492. deviceWarning = _newWarning
  10493. return JsonOkResponse(payload={"device": deviceWarning, "ports": portWarning})
  10494. @permission_required(ROLE.dealer, ROLE.subaccount)
  10495. def cancelDeviceWarning(request):
  10496. """
  10497. 取消设备的告警信息
  10498. :param request:
  10499. :return:
  10500. """
  10501. logicalCode = request.POST.get("logicalCode")
  10502. part = request.POST.get("part")
  10503. dev = Device.get_dev_by_l(logicalCode)
  10504. if not dev:
  10505. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10506. if dev.ownerId != str(request.user.bossId):
  10507. return JsonErrorResponse(description=u"未找到设备,请刷新重试")
  10508. if part is None:
  10509. Device.clear_dev_warning_cache(dev.devNo)
  10510. else:
  10511. Device.clear_part_warning_cache(dev.devNo, part)
  10512. return JsonOkResponse()
  10513. @permission_required(ROLE.dealer, ROLE.subaccount)
  10514. def clearDeviceCache(request):
  10515. data = json.loads(request.body)
  10516. dev = Device.get_dev_by_logicalCode(data['logicalCode'])
  10517. Device.invalid_all_cache(dev)
  10518. return JsonOkResponse()
  10519. @permission_required(ROLE.dealer, ROLE.subaccount)
  10520. def getCurrencyGroups(request):
  10521. """
  10522. 获取经销商通用组以及通用模式
  10523. :param request:
  10524. :return:
  10525. """
  10526. current_user = request.user # type: Dealer
  10527. pageIndex = int(request.GET.get('pageIndex', 1))
  10528. pageSize = int(request.GET.get('pageSize', 10))
  10529. groups = []
  10530. for group in Group.get_collection().find({'ownerId': str(request.user.bossId)},
  10531. {'_id': 1, 'name': 1, 'currencyGroup': 1, 'groupName': 1}):
  10532. if 'currencyGroup' in group:
  10533. groups.append({
  10534. 'groupId': str(group['_id']),
  10535. 'groupName': group['groupName'],
  10536. 'currencyGroup': group['currencyGroup']
  10537. })
  10538. groups.sort(key=itemgetter('currencyGroup'))
  10539. dataList = []
  10540. for currencyGroup, groups in groupby(groups, itemgetter('currencyGroup')):
  10541. dataList.append({
  10542. 'name': currencyGroup,
  10543. 'members': [{'id': group['groupId'], 'name': group['groupName']} for group in groups]
  10544. })
  10545. return JsonOkResponse(payload={
  10546. 'currencyMode': current_user.currency_mode,
  10547. 'total': len(dataList),
  10548. 'dataList': dataList[pageIndex * pageSize - pageSize: pageIndex * pageSize]
  10549. })
  10550. @permission_required(ROLE.dealer, ROLE.subaccount)
  10551. def updatCurrencyGroups(request):
  10552. """
  10553. 更新经销商通用组以及通用模式
  10554. :param request:
  10555. :return:
  10556. """
  10557. boss = request.user.myBoss # type: Dealer
  10558. payload = json.loads(request.body)
  10559. # 校验分组名字是否为'',否则会导致设置地址组通用(删除操作的时候)无法生效.
  10560. name_list = map(lambda x: x.get('name'), payload.get('groupList', None))
  10561. if name_list:
  10562. check_name = None
  10563. for name in name_list:
  10564. if name == check_name:
  10565. return JsonErrorResponse(description='分组名称不能相同')
  10566. else:
  10567. check_name = name
  10568. else:
  10569. pass
  10570. # 初始化之前的组
  10571. beforeDataList = payload.get('beforeDataList', [])
  10572. for groupInfo in beforeDataList:
  10573. group_ids = [ObjectId(group['id']) for group in groupInfo['members']]
  10574. Group.objects(id__in=group_ids,
  10575. ownerId=str(request.user.bossId)).update(currencyGroup='')
  10576. currencyMode = payload['currencyMode']
  10577. if boss.currencyMode != currencyMode:
  10578. boss.update(currencyMode=currencyMode)
  10579. Dealer.invalid_cache(str(boss.id))
  10580. share_group_list = payload['groupList']
  10581. for share_group in share_group_list:
  10582. share_name = share_group['name']
  10583. group_ids = [ObjectId(group['id']) for group in share_group['members']]
  10584. Group.objects(id__in=group_ids,
  10585. ownerId=str(request.user.bossId)).update(currencyGroup=share_name)
  10586. Group.invalid_group_cache(group_ids)
  10587. return JsonOkResponse()
  10588. @permission_required(ROLE.dealer)
  10589. def setSimChargeAuto(request):
  10590. dealerId = request.user.id
  10591. Device.get_collection().update({'ownerId':str(dealerId)}, {'$set':{'simChargeAuto':True}})
  10592. return JsonOkResponse()
  10593. @permission_required(ROLE .dealer)
  10594. def activeRentDevice(request):
  10595. """
  10596. 经销商主动激活出租设备
  10597. """
  10598. payload = json.loads(request.body)
  10599. logicalCode = payload.get("logicalCode")
  10600. if not logicalCode:
  10601. return JsonErrorResponse(u"激活失败")
  10602. device = Device.objects.get(logicalCode=logicalCode)
  10603. if not device:
  10604. return JsonErrorResponse(u"激活失败")
  10605. try:
  10606. device.active_rent()
  10607. except RentDeviceError as e:
  10608. return JsonErrorResponse(e.message)
  10609. return JsonOkResponse()
  10610. @permission_required(ROLE.dealer)
  10611. def getRentOrder(request):
  10612. """
  10613. 获取经销商所有的日租订单 从前往后
  10614. """
  10615. logicalCode = request.GET.get("logicalCode")
  10616. pageSize = request.GET.get("pageSize")
  10617. pageIndex = request.GET.get("pageIndex")
  10618. if not logicalCode:
  10619. return JsonErrorResponse(u"获取记录失败")
  10620. device = Device.objects.get(logicalCode=logicalCode)
  10621. if not device:
  10622. return JsonErrorResponse(u"获取记录失败")
  10623. orders = DeviceRentOrder.get_by_device(device)
  10624. dataList = [_.to_dict() for _ in orders]
  10625. return JsonOkResponse(payload={"total": orders.count(), "dataList": dataList})
  10626. @permission_required(ROLE.dealer)
  10627. def sendVirtualCard(request):
  10628. payload = json.loads(request.body)
  10629. openId = payload.get("openId")
  10630. groupId = payload.get("groupId")
  10631. cardId = payload.get("cardId")
  10632. vCard = VirtualCard.objects.filter(id=cardId).first()
  10633. if not vCard:
  10634. return JsonErrorResponse(description=u"未找到虚拟卡,请确认虚拟卡信息后重试")
  10635. user = MyUser.objects.filter(openId=openId, groupId=groupId).first()
  10636. if not user:
  10637. return JsonErrorResponse(description=u"未找到用户,请确认派卡地址是否正确")
  10638. userCard = UserVirtualCard(
  10639. cardNo=UserVirtualCard.make_no(),
  10640. cardTypeId=str(cardId),
  10641. openIds=[openId],
  10642. cardName=vCard.cardName,
  10643. ownerOpenId=openId,
  10644. nickname=user.nickname,
  10645. dealerId=vCard.ownerId,
  10646. groupIds=vCard.groupIds,
  10647. devTypeList=vCard.devTypeList,
  10648. price=vCard.price,
  10649. periodDays=vCard.periodDays,
  10650. expiredTime=datetime.datetime.now() + datetime.timedelta(seconds=vCard.periodDays * 24 * 3600),
  10651. dayQuota=vCard.dayQuota,
  10652. userLimit=vCard.userLimit,
  10653. quota=vCard.quota,
  10654. userDesc=vCard.userDesc,
  10655. managerialAppId=user.managerialOpenId,
  10656. managerialOpenId=user.managerialOpenId,
  10657. logicalCode="",
  10658. groupId=groupId
  10659. ).save()
  10660. return JsonOkResponse(description=u"发卡成功")
  10661. @permission_required(ROLE.dealer)
  10662. def stopUserOrder(request):
  10663. orderId = request.GET.get('orderId')
  10664. order = ClientConsumeModelProxy.get_one(id=orderId) # type: ConsumeRecord
  10665. if not order:
  10666. return JsonErrorResponse(description='未找到该笔订单')
  10667. if order.devTypeCode:
  10668. try:
  10669. from apps.web.core.models import DriverAdapter
  10670. adapter = DriverAdapter.get_driver_adapter(order.devTypeCode, None)
  10671. adapter.force_stop_order(order)
  10672. except:
  10673. order.update(isNormal=False, errorDesc='强制订单失败后, 直接更新订单')
  10674. return JsonOkResponse(description=u"停止成功")
  10675. else:
  10676. return JsonErrorResponse(description='强制停止失败')
  10677. @permission_required(ROLE.dealer, ROLE.subaccount)
  10678. def getConsumeTemplate(request):
  10679. """
  10680. 获取用户的消费信息 模板的配置
  10681. :param request:
  10682. :return:
  10683. """
  10684. owner = request.user.myBoss # type: Dealer
  10685. showList = owner.supportedConsumptionShow
  10686. if not showList:
  10687. from apps.web.common.utils import UserConsumeFilter
  10688. showList = UserConsumeFilter.default_filter()
  10689. return JsonOkResponse(payload = {"showList": showList})
  10690. @permission_required(ROLE.dealer, ROLE.subaccount)
  10691. def setConsumeTemplate(request):
  10692. """
  10693. 设置用户的参数
  10694. :param request:
  10695. :return:
  10696. """
  10697. dealerId = request.user.bossId
  10698. payload = json.loads(request.body)
  10699. try:
  10700. Dealer.objects.get(id=dealerId).update(supportedConsumptionShow=payload["showList"])
  10701. Dealer.invalid_cache(dealerId)
  10702. except DoesNotExist:
  10703. return JsonErrorResponse(u"参数错误, 请刷新重试")
  10704. except Exception as e:
  10705. logger.exception("update dealer <{}> supportedConsumptionShow error = {}".format(dealerId, e))
  10706. return JsonErrorResponse(u"参数错误, 请刷新重试")
  10707. return JsonOkResponse()
  10708. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"退款操作中出现异常,请联系客服处理"))
  10709. @permission_required(ROLE.dealer)
  10710. def refundOrder(request):
  10711. payload = json.loads(request.body)
  10712. logger.debug('dealer refund order. dealer: {}, payload: {}'.format(request.user, payload))
  10713. orderNo = payload.get("orderNo", None)
  10714. if not orderNo:
  10715. return JsonErrorResponse(description=u"参数错误,请刷新页面重试")
  10716. refundMoney = RMB(payload.get("refundMoney"))
  10717. deductCoins = VirtualCoin(payload.get("deductCoins"))
  10718. rechargeOrder = RechargeRecord.objects.filter(orderNo=orderNo).first() # type: RechargeRecord
  10719. if not rechargeOrder:
  10720. return JsonErrorResponse(description=u"未查询到订单,请刷新页面重试")
  10721. if not rechargeOrder.is_refund_available(request.user):
  10722. return JsonErrorResponse(description=u"该类型订单不支持退款")
  10723. if rechargeOrder.coins < deductCoins:
  10724. return JsonErrorResponse(description=u"扣除金币数大于用户实际购买数目")
  10725. currency = rechargeOrder.myuser.calc_currency_balance(rechargeOrder.owner, rechargeOrder.group)
  10726. if currency < deductCoins:
  10727. return JsonErrorResponse(description = u"扣除金币数大于用户目前余额")
  10728. if not rechargeOrder.is_success:
  10729. return JsonErrorResponse(description = u"退款失败,订单状态非成功,请联系平台客服")
  10730. if not rechargeOrder.is_ledgered:
  10731. # 检验订单是否有收益
  10732. return JsonErrorResponse(description=u"退款失败,订单未产生收益,请联系平台客服")
  10733. try:
  10734. refundedOrder = refund_cash(rechargeOrder, refundMoney, deductCoins)
  10735. return JsonOkResponse(description=u"退款成功", payload={"refundedOrderNo": refundedOrder.orderNo})
  10736. except ServiceException as e:
  10737. logger.error(e.result)
  10738. return JsonResponse(e.result)
  10739. except UserServerException as e:
  10740. logger.error(e.message)
  10741. return JsonErrorResponse(description=e.message)
  10742. except Exception as e:
  10743. return JsonErrorResponse(description=u"退款失败,请刷新后重试")
  10744. @permission_required(ROLE.dealer, ROLE.subaccount)
  10745. def getDealerTodoMessage(request):
  10746. """
  10747. 获取经代销商的代办事项
  10748. """
  10749. messages = TodoMessage.get_todo_message(request.user)
  10750. # 进行一次任务检查 查看任务是否完成以及是否需要强制执行
  10751. return JsonOkResponse(payload={"count": len(messages), "dataList": messages})
  10752. @permission_required(ROLE.dealer)
  10753. def saveUserBlackConfig(request):
  10754. dealerId = str(request.user.id)
  10755. payload = json.loads(request.body)
  10756. breakRuleTimes = payload.get('breakRuleTimes', 0)
  10757. orderRemindType = payload.get('orderRemindType', 2)
  10758. openId = payload.get('openId', '')
  10759. dealer = Dealer.objects(id=dealerId).first()
  10760. users = MyUser.objects(openId=openId, agentId=dealer.agentId)
  10761. if users.count() == 0:
  10762. return JsonErrorResponse(description=u"不存在的用户")
  10763. for _ in users:
  10764. _.blacklistConfig['breakRuleTimes'] = breakRuleTimes
  10765. _.blacklistConfig['orderRemindType'] = orderRemindType
  10766. try:
  10767. _.save()
  10768. except Exception as e:
  10769. return JsonErrorResponse(description=u"系统错误")
  10770. return JsonOkResponse(description=u"设置成功")
  10771. @permission_required(ROLE.dealer, ROLE.subaccount)
  10772. @ViewValidator(UserListValidator)
  10773. def userList(request, data):
  10774. groupId = data.get("groupId")
  10775. source = data.get("source")
  10776. reverse = data.get("reverse")
  10777. searchKey = data.get("searchKey")
  10778. pageSize = data.get("pageSize")
  10779. pageIndex = data.get("pageIndex")
  10780. userQuery = MyUser.objects.filter(groupId=groupId)
  10781. if source:
  10782. userQuery = userQuery.filter(gateway=source)
  10783. userQuery = userQuery.order_by("last_login") if reverse else userQuery.order_by("-last_login")
  10784. if re.match(r'1[3-9][0-9]{9}$', searchKey):
  10785. agent = Agent.objects.filter(id = str(request.user.myBoss.agentId)).first() # type: Agent
  10786. if agent.supports('user_identify'):
  10787. user = MyUser.objects(phoneNumber = searchKey).first()
  10788. if not user:
  10789. return JsonErrorResponse(description = u"未找到用户")
  10790. userQuery = userQuery.filter(openId = user.openId)
  10791. users = list(userQuery.paginate(pageIndex, pageSize))
  10792. else:
  10793. unique_user = UniqueUser.objects.filter(phone = searchKey).first() # type: UniqueUser
  10794. if not unique_user:
  10795. return JsonErrorResponse(description = u"未找到用户")
  10796. userQuery = userQuery.filter(openId = unique_user.openId)
  10797. users = list(userQuery.paginate(pageIndex, pageSize))
  10798. elif re.match(r'^[0-9]{5,10}$', searchKey):
  10799. unique_user = UniqueUser.objects.filter(userId = searchKey).first() # type: UniqueUser
  10800. if not unique_user:
  10801. return JsonErrorResponse(description = u"未找到用户")
  10802. userQuery = userQuery.filter(openId = unique_user.openId)
  10803. users = list(userQuery.paginate(pageIndex, pageSize))
  10804. else:
  10805. userQuery = userQuery.search(searchKey)
  10806. users = list(userQuery.paginate(pageIndex, pageSize))
  10807. # 获取用户默认头像
  10808. openIds = [str(_user.openId) for _user in users]
  10809. openId_2_uniId = {_.openId: _.userId for _ in UniqueUser.objects.filter(openId__in=openIds)}
  10810. dataList = list()
  10811. for _user in users: # type: MyUser
  10812. _userInfo = _user.to_dict()
  10813. _userInfo.update(
  10814. {
  10815. "dealerId": str(request.user.bossId),
  10816. "userId": openId_2_uniId.get(_user.openId, ""),
  10817. "id": str(_user.id)
  10818. }
  10819. )
  10820. dataList.append(_userInfo)
  10821. # 总量永远比数据量大于1 这样前端下拉只需要判断 当前的数量和pageSize的对比就行
  10822. total = pageIndex * pageSize + 1 if len(dataList) == pageSize else pageIndex * pageSize
  10823. return JsonResponse({
  10824. "result": 1,
  10825. "description": None,
  10826. "payload": {"total": total, "dataList": dataList}
  10827. })
  10828. @permission_required(ROLE.dealer, ROLE.subaccount)
  10829. def userDetail(request, openId):
  10830. # 获取所有用户的用户组
  10831. groupIds = Group.get_group_ids_of_dealer(str(request.user.bossId))
  10832. users = MyUser.objects.filter(openId=openId, groupId__in=groupIds).order_by("-last_login")
  10833. user = users.first()
  10834. try:
  10835. userId = UniqueUser.objects.get(openId=user.openId).userId
  10836. except DoesNotExist:
  10837. userId = ""
  10838. # 对于users 做累加和处理以及分列处理
  10839. payload = {
  10840. "userId": userId,
  10841. "avatar": user.avatar or Agent.get_agent(user.agentId).get("productLogo"),
  10842. "openId": openId,
  10843. "nickname": user.nickname,
  10844. "status": "black" if check_black_user(dealerId=str(request.user.bossId), openId=openId) else "white",
  10845. "phone": user.phone,
  10846. "total_recharge": RMB(0),
  10847. "total_balance": VirtualCoin(0),
  10848. "total_consume": VirtualCoin(0),
  10849. }
  10850. dataList = list()
  10851. for _user in users: # type: MyUser
  10852. _groupUserInfo = {
  10853. "groupId": _user.groupId,
  10854. "groupName": Group.get_group(_user.groupId).groupName,
  10855. "recharge": RMB(_user.total_recharged),
  10856. "consume": VirtualCoin(_user.total_consumed),
  10857. "balance": VirtualCoin(_user.balance)
  10858. }
  10859. dataList.append(_groupUserInfo)
  10860. payload["total_recharge"] += _groupUserInfo["recharge"]
  10861. payload["total_consume"] += _groupUserInfo["consume"]
  10862. payload["total_balance"] += _groupUserInfo["balance"]
  10863. payload["dataList"] = dataList
  10864. return JsonOkResponse(payload=payload)
  10865. @permission_required(ROLE.dealer, ROLE.subaccount)
  10866. def getPortsInfo(request):
  10867. logicalCode = request.GET.get('logicalCode')
  10868. dev = Device.get_dev_by_l(logicalCode)
  10869. smartBox = dev.deviceAdapter
  10870. portList = smartBox.get_ports_info()
  10871. portList = sorted(portList, key=lambda _: int(_['index']))
  10872. if dev.support_power_graph and 'showPG_in_port_detail' in dev.owner.features:
  10873. for item in portList:
  10874. item['showPG'] = True
  10875. return JsonOkResponse(payload={'portList': portList})
  10876. @permission_required(ROLE.dealer, ROLE.subaccount)
  10877. def getDevicePortDetail(request):
  10878. logicalCode = request.GET.get('logicalCode')
  10879. portIndex = request.GET.get('portIndex')
  10880. dev = Device.get_dev_by_l(logicalCode)
  10881. smartBox = dev.deviceAdapter
  10882. ctrInfo = Device.get_dev_control_cache(dev.devNo)
  10883. payload = smartBox.get_port_using_detail(portIndex, ctrInfo)
  10884. if dev.support_power_graph and 'showPG_in_port_detail' in dev.owner.features:
  10885. payload['showPG'] = True
  10886. payload['index'] = portIndex
  10887. return JsonOkResponse(payload=payload)
  10888. @permission_required(ROLE.dealer, ROLE.subaccount)
  10889. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取失败"))
  10890. def getDealerSwitch(request, category):
  10891. """
  10892. 两级联动开关 经销商的开关获取
  10893. """
  10894. bossId = str(request.user.bossId)
  10895. try:
  10896. dealer = Dealer.objects.get(id=bossId)
  10897. except DoesNotExist:
  10898. return JsonErrorResponse(u"获取配置失败")
  10899. payload = dealer.get_linkage_switch()
  10900. return JsonOkResponse(payload=payload)
  10901. @permission_required(ROLE.dealer, ROLE.subaccount)
  10902. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"获取失败"))
  10903. def getGroupSwitch(request, category):
  10904. """
  10905. 两级联动开关 地质组的开关获取
  10906. """
  10907. bossId = str(request.user.bossId)
  10908. pageIndex = int(request.GET.get("pageIndex"))
  10909. pageSize = int(request.GET.get("pageSize"))
  10910. try:
  10911. groups = Group.objects.filter(ownerId=bossId)
  10912. except DoesNotExist:
  10913. return JsonErrorResponse(u"获取配置失败")
  10914. offset = (pageIndex - 1) * pageSize
  10915. total = groups.count()
  10916. dataList = list()
  10917. for _group in groups[offset: offset + pageSize]: # type: Group
  10918. _switches = _group.get_linkage_switch()
  10919. _switches.update({"name": _group.groupName, "groupId": str(_group.id)})
  10920. dataList.append(_switches)
  10921. payload = {
  10922. "total": total,
  10923. "dataList": dataList
  10924. }
  10925. return JsonOkResponse(payload=payload)
  10926. @permission_required(ROLE.dealer, ROLE.subaccount)
  10927. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  10928. def setDealerSwitch(request, category):
  10929. """
  10930. 两级联动开关 设置经销商开关
  10931. """
  10932. bossId = str(request.user.bossId)
  10933. try:
  10934. dealer = Dealer.objects.get(id=bossId)
  10935. except DoesNotExist:
  10936. return JsonErrorResponse(u"设置失败")
  10937. payload = json.loads(request.body)
  10938. switch = payload["switch"]
  10939. if switch:
  10940. result = dealer.turn_on(category)
  10941. else:
  10942. result = dealer.turn_off(category)
  10943. return JsonOkResponse() if result else JsonErrorResponse(description=u"设置开关失败,请联系平台客服")
  10944. @permission_required(ROLE.dealer, ROLE.subaccount)
  10945. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  10946. def setGroupSwitch(request, category):
  10947. """
  10948. 两级联动开关 设置地质组开关 单个
  10949. """
  10950. bossId = str(request.user.bossId)
  10951. payload = json.loads(request.body)
  10952. groupId = payload["groupId"]
  10953. switch = payload["switch"]
  10954. try:
  10955. group = Group.objects.get(id=groupId, ownerId=bossId)
  10956. except DoesNotExist:
  10957. return JsonErrorResponse(u"设置失败")
  10958. logger.error(group.id)
  10959. if switch:
  10960. group.turn_on(category)
  10961. else:
  10962. group.turn_off(category)
  10963. return JsonOkResponse()
  10964. @permission_required(ROLE.dealer)
  10965. def getServiceChargeModelPara(request):
  10966. """
  10967. 获取服务费模式参数
  10968. :param request:
  10969. :return:
  10970. """
  10971. payload = json.loads(request.body)
  10972. logicalCode = payload.get("logicalCode")
  10973. if isinstance(logicalCode, list) and len(logicalCode):
  10974. logicalCode = logicalCode[0]
  10975. else:
  10976. raise JsonErrorResponse(description=u"无效的设备编号")
  10977. device = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  10978. if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING]:
  10979. serviceChargeModelPara = device.bill_as_service_feature
  10980. if 'half_hour_price_list' or 'top_price_rate' or 'peak_price_rate' or 'normal_price_rate' or 'valley_price_rate' \
  10981. not in device.bill_as_service_feature['elecCharge']:
  10982. return JsonResponse({"result": 1, "description": "", "payload": device.bill_as_service_feature})
  10983. half_hour_price_list = serviceChargeModelPara['elecCharge']['half_hour_price_list']
  10984. nowTime = datetime.datetime.now().strftime('%H:%M')
  10985. timeNowList = nowTime.split(':')
  10986. index = int(timeNowList[0]) * 2 + 2 if int(timeNowList[1]) > 30 else 1 - 1
  10987. currentElecChargeRate = half_hour_price_list['half_hour_price_list'][index]
  10988. if currentElecChargeRate == 'top_price_rate':
  10989. elecCharge = serviceChargeModelPara['elecCharge']['top_price_rate']
  10990. elif currentElecChargeRate == 'peak_price_rate':
  10991. elecCharge = serviceChargeModelPara['elecCharge']['peak_price_rate']
  10992. elif currentElecChargeRate == 'normal_price_rate':
  10993. elecCharge = serviceChargeModelPara['elecCharge']['normal_price_rate']
  10994. elif currentElecChargeRate == 'valley_price_rate':
  10995. elecCharge = serviceChargeModelPara['elecCharge']['valley_price_rate']
  10996. bill_as_service_feature = {
  10997. 'on':device.bill_as_service_feature['on'],
  10998. 'elecCharge':elecCharge,
  10999. 'serviceCharge':device.bill_as_service_feature['service_charge']
  11000. }
  11001. return JsonResponse({"result": 1, "description": "", "payload": bill_as_service_feature})
  11002. return JsonResponse({"result": 1, "description": "", "payload": device.bill_as_service_feature})
  11003. @permission_required(ROLE.dealer, ROLE.subaccount)
  11004. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11005. def setServiceChargeModelPara(request):
  11006. payload = json.loads(request.body)
  11007. logicalCode = payload.get("logicalCode")
  11008. if isinstance(logicalCode, list) and len(logicalCode):
  11009. logicalCode = logicalCode[0]
  11010. else:
  11011. return JsonErrorResponse(description=u"错误的二维码编号")
  11012. elecCharge = payload.get("elecCharge")
  11013. serviceCharge = payload.get("serviceCharge")
  11014. device = Device.get_dev_by_l(logicalCode)
  11015. devNo = device['devNo']
  11016. # if device.devTypeCode in [Const.DEVICE_TYPE_CODE_CHANGING_DIANCHUANCARCHARGING]:
  11017. # from apps.web.core.adapter.dianchuan_CarCharging import DianchuanCarCharging
  11018. # device = DianchuanCarCharging(device)
  11019. # device.set_elec_charge_by_dealer(elecCharge)
  11020. # elecChargeDict = {
  11021. # 'top_price_rate' : elecCharge,
  11022. # 'peak_price_rate' : elecCharge,
  11023. # 'normal_price_rate' : elecCharge,
  11024. # 'valley_price_rate' : elecCharge,
  11025. # 'half_hour_price_list' : ['top_price_rate'] * 48,
  11026. # }
  11027. # Device.get_collection().update_one({'devNo': devNo}, {
  11028. # '$set': {
  11029. # 'devType.features.billAsService.elecCharge': elecChargeDict,
  11030. # 'devType.features.billAsService.serviceCharge': serviceCharge
  11031. # }
  11032. # })
  11033. # Device.invalid_device_cache(devNo)
  11034. # return JsonOkResponse()
  11035. Device.get_collection().update_one({'devNo': devNo}, {
  11036. '$set': {
  11037. 'devType.features.billAsService.elecCharge': elecCharge,
  11038. 'devType.features.billAsService.serviceCharge': serviceCharge
  11039. }
  11040. })
  11041. Device.invalid_device_cache(devNo)
  11042. return JsonOkResponse()
  11043. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11044. @permission_required(ROLE.dealer, ROLE.subaccount)
  11045. def getApiInfo(request):
  11046. """
  11047. 获取首页的配额相关数据
  11048. """
  11049. dealer = request.user.myBoss # type: Dealer
  11050. payload = dealer.api_quota_info
  11051. return JsonOkResponse(payload=payload)
  11052. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11053. @permission_required(ROLE.dealer, ROLE.subaccount)
  11054. def getApiAppInfo(request):
  11055. """
  11056. 获取经销上API注册信息
  11057. """
  11058. dealer = request.user.myBoss # type: Dealer
  11059. apiAppInfo = dealer.api_app # type: ApiAppInfo
  11060. return JsonOkResponse(payload={
  11061. 'people': apiAppInfo.people,
  11062. 'tel': apiAppInfo.tel,
  11063. 'callbackUrl': apiAppInfo.callbackUrl,
  11064. 'apiDeviceMax': apiAppInfo.apiDeviceMax
  11065. })
  11066. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11067. @permission_required(ROLE.dealer, ROLE.subaccount)
  11068. def saveApiAppInfo(request):
  11069. """
  11070. 编辑经销上API注册信息
  11071. """
  11072. def check_url(url):
  11073. return re.match(r'^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+', url)
  11074. dealer = request.user.myBoss # type: Dealer
  11075. payload = json.loads(request.body)
  11076. people = payload.get('people')
  11077. tel = payload.get('tel')
  11078. callbackUrl = payload.get('callbackUrl')
  11079. if callbackUrl and not check_url(callbackUrl):
  11080. return JsonErrorResponse(description='回调地址Url填写错误')
  11081. dealer.update_api_app(**{
  11082. 'people': people,
  11083. 'tel': tel,
  11084. 'callbackUrl': callbackUrl
  11085. })
  11086. return JsonOkResponse()
  11087. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11088. @permission_required(ROLE.dealer, ROLE.subaccount)
  11089. def getApiDevice(request):
  11090. """
  11091. 获取经销商的设备列表
  11092. """
  11093. dealerId = request.user.bossId # type: Dealer
  11094. groups = Group.get_group_ids_of_dealer(dealerId)
  11095. groupList = []
  11096. for groupId in groups:
  11097. group = Group.get_group(groupId) # type : GroupDict
  11098. devDict = Device.get_devices_by_group([groupId]) # type:Mapping[DeviceDict]
  11099. if devDict:
  11100. devs = devDict.values()
  11101. groupList.append({
  11102. 'groupName': group['groupName'],
  11103. 'devList': map(lambda _: {'title': '{}_{}'.format(_.devTypeName, _.logicalCode), 'isApi': _.isApi,
  11104. 'logicalCode': _.logicalCode}, devs)
  11105. })
  11106. return JsonOkResponse(payload={'groupList': groupList})
  11107. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11108. @permission_required(ROLE.dealer, ROLE.subaccount)
  11109. def editApiDevice(request):
  11110. """
  11111. 经销商选择api设备
  11112. """
  11113. dealer = request.user.myBoss # type: Dealer
  11114. payload = json.loads(request.body)
  11115. groupList = payload.get('groupList')
  11116. logicalCodes = []
  11117. for item in groupList:
  11118. logicalCodes += item['devList']
  11119. # 找出经销商的全部设备
  11120. groups = Group.get_group_ids_of_dealer(str(dealer.id))
  11121. devDict = Device.get_devices_by_group(groups)
  11122. allList = map(lambda _: _.logicalCode, devDict.values())
  11123. # 找出经销商操作的设备
  11124. trunOnList = map(lambda _: _['logicalCode'], filter(lambda _: _['isApi'] == True, logicalCodes))
  11125. trunOnCount = len(trunOnList)
  11126. if set(trunOnList) - set(allList):
  11127. return JsonErrorResponse(description='非法操作!!! 无法操作其他人的设备')
  11128. apiInfo = dealer.api_app # type: ApiAppInfo
  11129. apiDeviceMax = apiInfo.apiDeviceMax
  11130. if trunOnCount > apiDeviceMax:
  11131. return JsonResponse({'result': 1001, 'description': '经销商API设备配额不足,请购买API设备配额',
  11132. 'payload': {'needQuota': trunOnCount - apiDeviceMax}})
  11133. # 此编辑操作为 关闭此经销商的全部设备 然后开启经销商选中的
  11134. Device.switch_api_mode(allList, isApi=False)
  11135. Device.switch_api_mode(trunOnList, isApi=True)
  11136. return JsonOkResponse()
  11137. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11138. @permission_required(ROLE.dealer, ROLE.subaccount)
  11139. def createQuotaOrder(request):
  11140. dealer = request.user.myBoss # type: Dealer
  11141. payload = json.loads(request.body)
  11142. needQuota = payload.get('needQuota')
  11143. groupList = payload.get('groupList')
  11144. buyType = payload.get('buyType')
  11145. package = payload.get('package', {})
  11146. logicalCodes = []
  11147. if buyType == 'temporary': # 配置设备的时候临时购买
  11148. for item in groupList:
  11149. logicalCodes += item['devList']
  11150. # 找出经销商的全部设备
  11151. groups = Group.get_group_ids_of_dealer(str(dealer.id))
  11152. devDict = Device.get_devices_by_group(groups)
  11153. # 找出经销商操作的设备
  11154. trunOnList = map(lambda _: _['logicalCode'], filter(lambda _: _['isApi'] == True, logicalCodes))
  11155. trunOnCount = len(trunOnList)
  11156. if set(trunOnList) - set(map(lambda _: _.logicalCode, devDict.values())):
  11157. return JsonErrorResponse(description='非法操作!!! 无法操作其他人的设备')
  11158. apiInfo = dealer.api_app # type: ApiAppInfo
  11159. apiDeviceMax = apiInfo.apiDeviceMax
  11160. if trunOnCount - apiDeviceMax <= 0:
  11161. return JsonErrorResponse(description='参数传入有误, 请稍后重试!')
  11162. if trunOnCount - apiDeviceMax != int(needQuota):
  11163. return JsonErrorResponse(description='参数传入有误, 请稍后重试..')
  11164. payload = {
  11165. 'needQuota': needQuota,
  11166. 'trunOnList': trunOnList,
  11167. 'buyType': buyType
  11168. }
  11169. elif buyType == 'package': # 套餐购买页面过来
  11170. payload = {
  11171. 'needQuota': package.get('quota', 1),
  11172. 'trunOnList': [],
  11173. 'buyType': buyType,
  11174. 'package': package
  11175. }
  11176. else:
  11177. return JsonErrorResponse(description='参数传入错误, 请稍后从试')
  11178. # 创建订单
  11179. record = create_dealer_charge_order_for_api(dealer, **payload)
  11180. if record:
  11181. return JsonResponse({'result': 1, 'description': u'创建订单成功', 'payload':{'orderNo':record.orderNo}})
  11182. else:
  11183. return JsonErrorResponse(u'创建订单异常失败')
  11184. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11185. @permission_required(ROLE.dealer, ROLE.subaccount)
  11186. def getQuotaDiscountPackage(request):
  11187. dealer = request.user.myBoss # type: Dealer
  11188. apiInfo = dealer.api_app # type: ApiAppInfo
  11189. unitPrice = apiInfo.apiDevicePerCost
  11190. payload = {
  11191. "unitPrice": unitPrice,
  11192. "discountList": [
  11193. {
  11194. "id": 1,
  11195. "price": unitPrice * 10,
  11196. "quota": 10
  11197. },
  11198. {
  11199. "id": 2,
  11200. "price": unitPrice * 20,
  11201. "quota": 20
  11202. },
  11203. {
  11204. "id": 3,
  11205. "price": unitPrice * 40,
  11206. "quota": 40
  11207. },
  11208. {
  11209. "id": 4,
  11210. "price": unitPrice * 100,
  11211. "quota": 100
  11212. }
  11213. ]
  11214. }
  11215. return JsonOkResponse(payload=payload)
  11216. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11217. @permission_required(ROLE.dealer, ROLE.subaccount)
  11218. def getDisableAdInfo(request):
  11219. """
  11220. 获取首页的配额相关数据
  11221. """
  11222. dealer = request.user.myBoss # type: Dealer
  11223. payload = dealer.disable_ad_quota_info()
  11224. return JsonOkResponse(payload=payload)
  11225. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11226. @permission_required(ROLE.dealer, ROLE.subaccount)
  11227. def getDisableAdDevice(request):
  11228. dealerId = request.user.bossId # type: Dealer
  11229. groups = Group.get_group_ids_of_dealer(dealerId)
  11230. groupList = []
  11231. now = datetime.datetime.now()
  11232. def _filter(dev):
  11233. formart_dict = {
  11234. 'title': '{}_{}'.format(dev.devTypeName, dev.logicalCode),
  11235. 'logicalCode': dev.logicalCode,
  11236. 'expiredTime':None
  11237. }
  11238. if dev.disableADExpireDate and dev.disableADExpireDate > now:
  11239. formart_dict.update({
  11240. 'expiredTime': dev.disableADExpireDate.strftime("%Y-%m-%d %H:%M:%S")
  11241. })
  11242. return formart_dict
  11243. for groupId in groups:
  11244. group = Group.get_group(groupId) # type : GroupDict
  11245. devDict = Device.get_devices_by_group([groupId]) # type:Mapping[DeviceDict]
  11246. if devDict:
  11247. devs = devDict.values()
  11248. groupList.append({
  11249. 'groupName': group['groupName'],
  11250. 'devList': map(_filter, devs)
  11251. })
  11252. return JsonOkResponse(payload={'groupList': groupList})
  11253. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11254. @permission_required(ROLE.dealer, ROLE.subaccount)
  11255. def DisableAdDeviceRecharge(request):
  11256. payload = json.loads(request.body)
  11257. groupList = payload.get('groupList', [])
  11258. devList = []
  11259. for item in groupList:
  11260. devList += item.get('devList', [])
  11261. configuredList = filter(lambda _: _['configured'] == True, devList)
  11262. payInfo = []
  11263. total = 0
  11264. totalMoney = RMB(0)
  11265. for item in configuredList:
  11266. dev = Device.get_dev_by_l(item.get('logicalCode'))
  11267. if not dev:
  11268. continue
  11269. payInfo.append({
  11270. 'title': item.get('title'),
  11271. 'logicalCode':dev.logicalCode,
  11272. 'expireDate': dev.disableADExpireDate,
  11273. 'money': dev.owner.disable_ad_plan.disableAdCost.mongo_amount,
  11274. 'cycle': dev.owner.disable_ad_plan.cycle
  11275. })
  11276. total += 1
  11277. totalMoney += dev.owner.disable_ad_plan.disableAdCost
  11278. return JsonOkResponse(payload={'devList': payInfo, 'total':total, 'totalMoney':totalMoney.mongo_amount})
  11279. @error_tolerate(logger=logger, nil=JsonErrorResponse(u"设置失败"))
  11280. @permission_required(ROLE.dealer, ROLE.subaccount)
  11281. def createDisableAdOrder(request):
  11282. dealer = request.user.myBoss # type: Dealer
  11283. payload = json.loads(request.body)
  11284. buyType = payload.get('buyType')
  11285. devList = payload.get('devList', {})
  11286. logicalCodes = []
  11287. if buyType != 'temporary': # 配置设备的时候临时购买
  11288. return JsonErrorResponse(description='参数传入错误, 请稍后从试')
  11289. for item in devList:
  11290. logicalCodes.append(item['logicalCode'])
  11291. # 找出经销商的全部设备
  11292. devs = Device.get_devs_by_ownerId(str(dealer.id))
  11293. # 找出经销商将要操作的设备
  11294. if set(logicalCodes) - set(map(lambda _: _.logicalCode, devs)):
  11295. return JsonErrorResponse(description='非法操作!!! 无法操作其他人的设备')
  11296. # 创建订单
  11297. record = create_dealer_charge_order_for_disable_ad(dealer, devList)
  11298. if record:
  11299. return JsonResponse({'result': 1, 'description': u'创建订单成功', 'payload':{'orderNo':record.orderNo}})
  11300. else:
  11301. return JsonErrorResponse(u'创建订单异常失败')
  11302. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11303. @permission_required(ROLE.dealer, ROLE.subaccount)
  11304. def getServerFunction(request):
  11305. payload = json.loads(request.body)
  11306. lc = payload.get("logicalCode")
  11307. if isinstance(lc, list) and len(lc):
  11308. lc = lc[0]
  11309. else:
  11310. raise JsonErrorResponse(description=u"无效的设备编号")
  11311. dev = Device.get_dev_by_l(lc) # type: DeviceDict
  11312. if not dev:
  11313. return JsonResponse({'result': 0, 'description': u'未找到该设备', 'payload': {}})
  11314. setConf = dev.deviceAdapter.get_server_setting()
  11315. if setConf is None:
  11316. return JsonResponse({'result': 0, 'description': u'您的设备类型不支持此操作哦', 'payload': {}})
  11317. else:
  11318. return JsonResponse({'result': 1, 'description': u'', 'payload': setConf})
  11319. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11320. @permission_required(ROLE.dealer, ROLE.subaccount)
  11321. def setServerFunction(request):
  11322. payload = json.loads(request.body)
  11323. # 去掉多余的参数
  11324. payload.pop('groupId', None)
  11325. logicalCodes = payload.pop('logicalCode')
  11326. if len(logicalCodes) > 1:
  11327. dev = Device.get_dev_by_l(logicalCodes[0]) # type: DeviceDict
  11328. payload = {
  11329. 'operator': {
  11330. 'id': str(request.user.id),
  11331. 'role': request.user.role,
  11332. 'username': request.user.username
  11333. },
  11334. 'logicalCodes': logicalCodes,
  11335. 'payload': payload,
  11336. 'ownerId': dev.ownerId,
  11337. 'devTypeCode': dev.devTypeCode,
  11338. 'operationId': 'server_setting_{}_{}'.format(str(request.user.id), int(time.time()))
  11339. }
  11340. from taskmanager.mediator import task_caller
  11341. task_caller('batch_set_server_settings', **payload)
  11342. return JsonResponse({'result': 1, 'description': None, 'payload': {'operationId': payload['operationId']}})
  11343. else:
  11344. device = Device.get_dev_by_l(logicalCodes[0]) # type: DeviceDict
  11345. if not device:
  11346. return JsonResponse({'result': 0, 'description': u'没有找到设备', 'payload': {}})
  11347. if device.ownerId != str(request.user.bossId):
  11348. return JsonResponse({'result': 0, 'description': u'非法操作', 'payload': {}})
  11349. try:
  11350. before = device.deviceAdapter.get_server_setting()
  11351. device.deviceAdapter.set_server_setting(payload)
  11352. OperatorLog.log_dev_operation(
  11353. operator=request.user,
  11354. device=device,
  11355. operator_name='setServerSetting',
  11356. content={
  11357. 'before': before, 'after': payload
  11358. })
  11359. except InvalidParameter as e:
  11360. return JsonErrorResponse(description=e.message)
  11361. return JsonOkResponse()
  11362. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11363. @permission_required(ROLE.dealer, ROLE.subaccount)
  11364. def getDealerPreferentialRechargeTemplate(request):
  11365. ownerId = str(request.user.bossId)
  11366. pageIndex = int(request.GET.get('pageIndex', 1))
  11367. pageSize = int(request.GET.get('pageSize', 10))
  11368. templateType = str(request.GET.get('type'))
  11369. dealer = Dealer.objects(id=ownerId).first()
  11370. if dealer is None:
  11371. return JsonErrorResponse(description=u'未知错误')
  11372. if templateType == 'preferentialRechargeTemplate':
  11373. dataList = dealer.templateSet.rechargeDiscount
  11374. elif templateType == 'cardPreferentialRechargeTemplate':
  11375. dataList = dealer.templateSet.cardRechargeDiscount
  11376. else:
  11377. return JsonErrorResponse(description=u"未知错误")
  11378. payload = {
  11379. "total": len(dataList),
  11380. "dataList": dataList[(pageIndex - 1) * pageSize:pageIndex * pageSize]
  11381. }
  11382. return JsonOkResponse(payload=payload)
  11383. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11384. @permission_required(ROLE.dealer, ROLE.subaccount)
  11385. def getDealerPreferentialRechargeTemplateById(request):
  11386. ownerId = str(request.user.bossId)
  11387. templateId = request.GET.get('id', None)
  11388. templateType = str(request.GET.get('type'))
  11389. if templateId is None:
  11390. return JsonErrorResponse(description=u'未知错误')
  11391. dealer = Dealer.objects(id=ownerId).first()
  11392. if dealer is None:
  11393. return JsonErrorResponse(description=u'未知错误')
  11394. if templateType == 'preferentialRechargeTemplate':
  11395. dataList = dealer.templateSet.rechargeDiscount
  11396. elif templateType == 'cardPreferentialRechargeTemplate':
  11397. dataList = dealer.templateSet.cardRechargeDiscount
  11398. else:
  11399. return JsonErrorResponse(description=u"未知错误")
  11400. payload = [_ for _ in dataList if int(templateId) == int(_['id'])][0]
  11401. return JsonOkResponse(payload=payload)
  11402. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11403. @permission_required(ROLE.dealer, ROLE.subaccount)
  11404. def editDealerPreferentialRechargeTemplate(request):
  11405. ownerId = str(request.user.bossId)
  11406. tempData = json.loads(request.body)
  11407. templateType = tempData['type']
  11408. del tempData['type']
  11409. dealer = Dealer.objects(id=ownerId).first()
  11410. if dealer is None:
  11411. return JsonErrorResponse(description=u'未知错误')
  11412. if templateType == 'preferentialRechargeTemplate':
  11413. tempDataList = dealer.templateSet.rechargeDiscount
  11414. elif templateType == 'cardPreferentialRechargeTemplate':
  11415. tempDataList = dealer.templateSet.cardRechargeDiscount
  11416. else:
  11417. return JsonErrorResponse(description=u"未知错误")
  11418. for _ in tempDataList:
  11419. if int(_['id']) == int(tempData['id']):
  11420. tempDataList.remove(_)
  11421. tempDataList.append(tempData)
  11422. if templateType == 'preferentialRechargeTemplate':
  11423. dealer.templateSet.rechargeDiscount = tempDataList
  11424. else:
  11425. dealer.templateSet.cardRechargeDiscount = tempDataList
  11426. dealer.save()
  11427. return JsonOkResponse()
  11428. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11429. @permission_required(ROLE.dealer, ROLE.subaccount)
  11430. def addDealerPreferentialRechargeTemplate(request):
  11431. ownerId = str(request.user.bossId)
  11432. payload = json.loads(request.body)
  11433. templateType = payload['type']
  11434. dealer = Dealer.objects(id=ownerId).first()
  11435. if dealer is None:
  11436. return JsonErrorResponse(description=u'未知错误')
  11437. if templateType == 'preferentialRechargeTemplate':
  11438. tempDataList = dealer.templateSet.rechargeDiscount
  11439. elif templateType == 'cardPreferentialRechargeTemplate':
  11440. tempDataList = dealer.templateSet.cardRechargeDiscount
  11441. else:
  11442. return JsonErrorResponse(description=u"未知错误")
  11443. if len(tempDataList) == 0:
  11444. tempId = 1
  11445. else:
  11446. tempId = max(int(_['id']) for _ in tempDataList) + 1
  11447. temp = {}
  11448. templateInfo = payload.get('templateInfo', [])
  11449. templateName = payload.get('templateName', '')
  11450. if not templateInfo or templateName == '':
  11451. return JsonErrorResponse(description=u'套餐错误')
  11452. for _ in templateInfo:
  11453. _['coins'] = float(_['coins'])
  11454. _['ruleId'] = _['payAmount']
  11455. temp.update({'templateName': templateName, 'templateInfo': templateInfo, 'id': tempId})
  11456. if templateType == 'preferentialRechargeTemplate':
  11457. dealer.templateSet.rechargeDiscount.append(temp)
  11458. else:
  11459. dealer.templateSet.cardRechargeDiscount.append(temp)
  11460. dealer.save()
  11461. return JsonOkResponse()
  11462. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11463. @permission_required(ROLE.dealer, ROLE.subaccount)
  11464. def deleteDealerPreferentialRechargeTemplate(request):
  11465. ownerId = str(request.user.bossId)
  11466. payload = json.loads(request.body)
  11467. tempId = payload['id']
  11468. templateType = payload['type']
  11469. dealer = Dealer.objects(id=ownerId).first()
  11470. if dealer is None:
  11471. return JsonErrorResponse(description=u'未知错误')
  11472. if templateType == 'preferentialRechargeTemplate':
  11473. tempDataList = dealer.templateSet.rechargeDiscount
  11474. elif templateType == 'cardPreferentialRechargeTemplate':
  11475. tempDataList = dealer.templateSet.cardRechargeDiscount
  11476. else:
  11477. return JsonErrorResponse(description=u"未知错误")
  11478. for _ in tempDataList:
  11479. if int(_['id']) == int(tempId):
  11480. tempDataList.remove(_)
  11481. if templateType == 'preferentialRechargeTemplate':
  11482. dealer.templateSet.rechargeDiscount = tempDataList
  11483. else:
  11484. dealer.templateSet.cardRechargeDiscount = tempDataList
  11485. dealer.save()
  11486. return JsonOkResponse()
  11487. @error_tolerate(logger=logger, nil=JsonErrorResponse(u'未知错误'))
  11488. @permission_required(ROLE.dealer, ROLE.subaccount)
  11489. def editGroupsToPreferentialRechargeTemplate(request):
  11490. ownerId = str(request.user.bossId)
  11491. payload = json.loads(request.body)
  11492. tempId = payload['id']
  11493. templateType = payload['type']
  11494. groupIds = [_['groupId'] for _ in payload['groupId']]
  11495. dealer = Dealer.objects(id=ownerId).first()
  11496. if dealer is None:
  11497. return JsonErrorResponse(description=u'未知错误')
  11498. tempData = dict()
  11499. if templateType == 'preferentialRechargeTemplate':
  11500. tempDataList = dealer.templateSet.rechargeDiscount
  11501. elif templateType == 'cardPreferentialRechargeTemplate':
  11502. tempDataList = dealer.templateSet.cardRechargeDiscount
  11503. else:
  11504. return JsonErrorResponse(description=u"未知错误")
  11505. for _ in tempDataList:
  11506. if int(_['id']) == int(tempId):
  11507. tempData = _
  11508. break
  11509. tempRule = dict()
  11510. for _ in tempData['templateInfo']:
  11511. tempRule.update({_['payAmount']: _['coins']})
  11512. if templateType == 'preferentialRechargeTemplate':
  11513. for _ in Group.objects(id__in=groupIds):
  11514. _.ruleDict = format_dot_key(tempRule)
  11515. _.save()
  11516. else:
  11517. for _ in Group.objects(id__in=groupIds):
  11518. _.cardRuleDict = format_dot_key(tempRule)
  11519. _.save()
  11520. GroupCacheMgr.invalid_group_cache(groupIds)
  11521. return JsonOkResponse()
  11522. @permission_required(ROLE.dealer, ROLE.subaccount)
  11523. def getServiceFeePackage(request):
  11524. logicalCode = request.GET.get('logicalCode')
  11525. if not logicalCode:
  11526. raise JsonErrorResponse(description=u'无效的设备编号')
  11527. dev = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  11528. payload = dev.deviceAdapter.get_service_fee_info()
  11529. return JsonResponse({'result': 1, 'description': '', 'payload': payload})
  11530. @permission_required(ROLE.dealer, ROLE.subaccount)
  11531. def setServiceFeePackage(request):
  11532. """
  11533. 设置服务费计费参数, 暂时不支持批量
  11534. :param request:
  11535. :return:
  11536. """
  11537. payload = json.loads(request.body)
  11538. if 'billAsService' not in payload:
  11539. return JsonErrorResponse(description=u'传入参数错误')
  11540. logicalCode = payload.get("logicalCode")
  11541. try:
  11542. device = Device.get_dev_by_l(logicalCode) # type: DeviceDict
  11543. device.deviceAdapter.set_service_fee_info(payload)
  11544. except InvalidParameter as e:
  11545. return JsonErrorResponse(description=e.message)
  11546. return JsonOkResponse()
  11547. @permission_required(ROLE.dealer)
  11548. def interconnectionConfig(request):
  11549. ownerId = str(request.user.bossId)
  11550. pageIndex = int(request.GET.get('pageIndex', 1))
  11551. pageSize = int(request.GET.get('pageSize', 10))
  11552. searchKey = str(request.GET.get('searchKey', ''))
  11553. swapFlagSearch = None
  11554. if 'swapFlag' in request.GET:
  11555. if request.GET.get('swapFlag') == 'false':
  11556. swapFlagSearch = False
  11557. else:
  11558. swapFlagSearch = True
  11559. dataList = []
  11560. groupIds = Group.get_group_ids_of_dealer(ownerId)
  11561. groupList = Group.get_groups_by_group_ids(groupIds).values()
  11562. groupList = natural_sort(groupList, 'groupName', False)
  11563. for grp in groupList:
  11564. if searchKey not in grp['groupName']:
  11565. continue
  11566. if swapFlagSearch is not None and swapFlagSearch != grp.get('swapFlag', False):
  11567. continue
  11568. if 'swapFlag' not in grp:
  11569. grp['swapFlag'] = False
  11570. elif grp['swapFlag']:
  11571. swapInfo = SwapGroup.objects(groupId=grp['groupId']).first()
  11572. if swapInfo is not None:
  11573. grp['joinedTime'] = swapInfo.joinedTime.strftime('%Y-%m-%d %H:%M:%S')
  11574. dataList.append(grp)
  11575. return JsonResponse({
  11576. "result": 1,
  11577. "description": None,
  11578. 'payload': {
  11579. "total": len(dataList),
  11580. "dataList": dataList[(pageIndex - 1) * pageSize: pageIndex * pageSize]
  11581. }
  11582. })
  11583. @permission_required(ROLE.dealer)
  11584. def interconnectionDetail(request):
  11585. ownerId = str(request.user.bossId)
  11586. groupId = request.GET.get('groupId', None)
  11587. if groupId is None:
  11588. return JsonErrorResponse(description=u"缺少参数")
  11589. swapInfo = SwapGroup.objects(groupId=groupId).first()
  11590. if swapInfo is None:
  11591. return JsonOkResponse(payload={})
  11592. if ownerId != swapInfo.ownerId:
  11593. return JsonErrorResponse(description=u"参数不一致")
  11594. payload = {
  11595. 'StationLng':swapInfo.lng,
  11596. 'StationLat':swapInfo.lat,
  11597. 'BusineHours':swapInfo.BusineHours,
  11598. 'SiteGuide':swapInfo.SiteGuide,
  11599. 'Construction':swapInfo.Construction,
  11600. 'SupportOrder':swapInfo.SupportOrder,
  11601. 'Pictures':[{'PicID':pic.PicID, 'IsCover':pic.IsCover, 'Url':pic.Url, 'title':pic.Title, 'Title':pic.TitleForShow} for pic in swapInfo.Pictures],
  11602. 'MatchCars':swapInfo.MatchCars,
  11603. 'ParkInfo':swapInfo.ParkInfo,
  11604. 'StationStatus':swapInfo.StationStatus,
  11605. 'ParkNums':swapInfo.ParkNums,
  11606. 'originalAlternateFeeRemark':swapInfo.originalAlternateFeeRemark,
  11607. 'alternateFeeRemark':swapInfo.alternateFeeRemark,
  11608. 'originalDirectFeeRemark':swapInfo.originalDirectFeeRemark,
  11609. 'directFeeRemark':swapInfo.directFeeRemark,
  11610. 'PriceChargingInfo':[{'FeeTime':info.FeeTime, 'ElectricityFee':info.ElectricityFee, 'ServiceFee':info.ServiceFee} for info in swapInfo.PriceChargingInfo],
  11611. 'DiscountPriceChargingInfo':[{'FeeTime':info.DiscountTime, 'ElectricityFee':info.DiscountElectricityFee, 'ServiceFee':info.DiscountServiceFee} for info in swapInfo.DiscountPriceChargingInfo],
  11612. 'ElectricityFee':swapInfo.ElectricityFee,
  11613. 'ServiceFee':swapInfo.ServiceFee,
  11614. 'ParkFee':swapInfo.ParkFee,
  11615. 'chargeTagList':[{'tagId':tag.tagId, 'tagType':tag.tagType, 'tagDesc':tag.tagDesc, 'tagOrder':tag.tagOrder, 'tagName':tag.tagName, 'color':tag.color} for tag in swapInfo.ChargeTagList],
  11616. 'StationTel':swapInfo.StationTel,
  11617. 'ServiceTel':swapInfo.ServiceTel,
  11618. 'Payment':swapInfo.Payment,
  11619. 'Remark':swapInfo.Remark,
  11620. 'RightTag':swapInfo.RightTag,
  11621. 'StationType':swapInfo.StationType
  11622. }
  11623. if swapInfo.swapFlag:
  11624. payload.update({'joinedTime':swapInfo.joinedTime.strftime('%Y-%m-%d %H:%M:%S')})
  11625. return JsonOkResponse(payload=payload)
  11626. @permission_required(ROLE.dealer)
  11627. def uploadSwapPicture(request):
  11628. files = request.FILES.getlist('file')
  11629. groupId = request.POST.get('groupId', None)
  11630. tail = request.POST.get('tail', None)
  11631. if groupId is None:
  11632. return JsonErrorResponse(description=u"缺少参数")
  11633. if not len(files):
  11634. return JsonResponse({'result': 0, 'description': u'未找到上传的商品图片,请重新试试', 'payload': {}})
  11635. uploader = SwapGroupPicFileUploader(inputFile=request.FILES.getlist('file')[0], uploadType='swap', groupId=groupId, tail=tail)
  11636. logger.info('[uploadItemPic] %s is being used' % (repr(uploader),))
  11637. try:
  11638. outputUrl = uploader.upload()
  11639. return JsonResponse({'result': 1, 'description': '', 'payload': {'Url':outputUrl}})
  11640. except InvalidFileSize, e:
  11641. logger.info(
  11642. '%s(id=%s)\'s uploaded file reached limit' % (request.user.__class__.__name__, str(request.user.id),))
  11643. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  11644. except InvalidFileName, e:
  11645. logger.info(
  11646. '%s(id=%s)\'s uploaded file name is not legal' % (request.user.__class__.__name__, str(request.user.id),))
  11647. return JsonResponse({'result': 0, 'description': e.message, 'payload': {}})
  11648. @permission_required(ROLE.dealer)
  11649. def getFeeMode(request):
  11650. payload = request.POST
  11651. logicalCode = payload.get("logicalCode")
  11652. devObj = Device.objects.get(logicalCode=logicalCode)
  11653. if devObj.ownerId != str(request.user.id):
  11654. return JsonErrorResponse(description=u"参数错误")
  11655. feeMode = devObj.otherConf.get('feeMode', {})
  11656. timeRateList = []
  11657. shiduan = feeMode.get('shiduan', '000000000000000000000000000000000000000000000000')
  11658. for ii in range(48):
  11659. startHour = 0 + ii / 2
  11660. startMin = '00' if ii % 2 == 0 else '30'
  11661. endHour = startHour if ii % 2 == 0 else startHour + 1
  11662. endMin = '30' if ii % 2 == 0 else '00'
  11663. startTime = '%02d:%s' % (startHour, startMin)
  11664. endTime = '%02d:%s' % (endHour, endMin)
  11665. timeRateList.append({'startTime':startTime, 'endTime':endTime, 'rate':shiduan[ii]})
  11666. result = {'top_price_rate':feeMode.get('jianFee', 0),
  11667. 'top_price_service_rate':feeMode.get('jianServe', 0),
  11668. 'peak_price_rate':feeMode.get('fengFee', 0),
  11669. 'peak_price_service_rate':feeMode.get('fengServe', 0),
  11670. 'normal_price_rate':feeMode.get('pingFee', 0),
  11671. 'normal_price_service_rate':feeMode.get('pingServe', 0),
  11672. 'valley_price_rate':feeMode.get('guFee', 0),
  11673. 'valley_price_service_rate':feeMode.get('guServe', 0),
  11674. 'jishunScale':feeMode.get('jishunScale', 0),
  11675. 'timeRateList':timeRateList}
  11676. return result
  11677. @permission_required(ROLE.dealer)
  11678. def setFeeMode(request):
  11679. payload = request.POST
  11680. logicalCode = payload.get("logicalCode")
  11681. devObj = Device.objects.get(logicalCode=logicalCode)
  11682. if devObj.ownerId != str(request.user.id):
  11683. return JsonErrorResponse(description=u"参数错误")
  11684. feeMode = devObj.otherConf.get('feeMode', {})
  11685. feeMode['jianFee'] = float(request.POST.get('top_price_rate'))
  11686. feeMode['jianServe'] = float(request.POST.get('top_price_service_rate'))
  11687. feeMode['fengFee'] = float(request.POST.get('peak_price_rate'))
  11688. feeMode['fengServe'] = float(request.POST.get('peak_price_service_rate'))
  11689. feeMode['pingFee'] = float(request.POST.get('normal_price_rate'))
  11690. feeMode['pingServe'] = float(request.POST.get('normal_price_service_rate'))
  11691. feeMode['guFee'] = float(request.POST.get('valley_price_rate'))
  11692. feeMode['guServe'] = float(request.POST.get('valley_price_service_rate'))
  11693. feeMode['jishunScale'] = float(request.POST.get('jishunScale', 0))
  11694. shiduan = ''
  11695. for ii in range(48):
  11696. startHour = 0 + ii / 2
  11697. startMin = '00' if ii % 2 == 0 else '30'
  11698. endHour = startHour if ii % 2 == 0 else startHour + 1
  11699. endMin = '30' if ii % 2 == 0 else '00'
  11700. startTime = '%02d:%s' % (startHour, startMin)
  11701. endTime = '%02d:%s' % (endHour, endMin)
  11702. print startTime, endTime
  11703. harfHourValue = '0'
  11704. for conf in request.POST.get('timeRateList'):
  11705. if startTime >= conf['startTime'] and endTime <= conf['endTime']:
  11706. harfHourValue = conf['rate']
  11707. break
  11708. else:
  11709. continue
  11710. shiduan += harfHourValue
  11711. feeMode['shiduan'] = shiduan
  11712. try:
  11713. devObj.save()
  11714. except Exception, e:
  11715. return JsonResponse({"result": 2, "description": "配置失败,请重试"})
  11716. return JsonOkResponse()
  11717. @permission_required(ROLE.dealer)
  11718. def setGroupSwapFlag(request):
  11719. ownerId = str(request.user.bossId)
  11720. groupId = request.POST.get('groupId', None)
  11721. if groupId is None:
  11722. return JsonErrorResponse(description=u"缺少参数")
  11723. swapFalg = request.POST.get('swapFlag', False)
  11724. success, description, groupId = Group.update_group(groupId, swapFalg=swapFalg)
  11725. SwapGroup.get_collection().update({'groupId':groupId}, {'$set':{'swapFlag':swapFalg}})
  11726. return JsonOkResponse() if success else JsonErrorResponse(description=description,
  11727. payload={'groupId': groupId})
  11728. @permission_required(ROLE.dealer)
  11729. def saveInterconnectionDetail(request):
  11730. ownerId = str(request.user.bossId)
  11731. data = json.loads(request.body)
  11732. groupId = data.get('groupId', None)
  11733. if groupId is None:
  11734. return JsonErrorResponse(description=u"缺少参数")
  11735. group = Group.get_group(groupId)
  11736. if group is None:
  11737. return JsonErrorResponse(description=u"参数错误")
  11738. swapInfo = SwapGroup.objects(groupId=groupId).first()
  11739. if swapInfo is None:
  11740. swapInfo = SwapGroup(groupId=groupId, stationID=SwapGroup.make_stationID(groupId))
  11741. lng, lat = SwapGroup.bd09_to_gcj02(data['StationLng'], data['StationLat'])
  11742. swapInfo.ownerId = ownerId
  11743. swapInfo.swapFlag = data.get('swapFlag', False)
  11744. swapInfo.location = {'type':'Point', 'coordinates':[data['StationLng'], data['StationLat']]}
  11745. swapInfo.gcjLng = lng
  11746. swapInfo.gcjLat = lat
  11747. swapInfo.BusineHours = data['BusineHours']
  11748. swapInfo.SiteGuide = data['SiteGuide']
  11749. swapInfo.Construction = data['Construction']
  11750. swapInfo.SupportOrder = int(data['SupportOrder'])
  11751. ii = 0
  11752. picList = []
  11753. for pic in data['Pictures']:
  11754. ii += 1
  11755. picList.append(Picture(ii, pic['IsCover'], pic['Url'], pic['title'], pic['Title']))
  11756. swapInfo.Pictures = picList
  11757. swapInfo.MatchCars = data['MatchCars']
  11758. swapInfo.ParkInfo = data['ParkInfo']
  11759. swapInfo.StationStatus = data['StationStatus']
  11760. swapInfo.ParkNums = data['ParkNums']
  11761. swapInfo.originalAlternateFeeRemark = data['originalAlternateFeeRemark']
  11762. swapInfo.alternateFeeRemark = data['alternateFeeRemark']
  11763. swapInfo.originalDirectFeeRemark = data['originalDirectFeeRemark']
  11764. swapInfo.directFeeRemark = data['directFeeRemark']
  11765. swapInfo.PriceChargingInfo = [PriceCharging(info['FeeTime'], info['ElectricityFee'], info['ServiceFee']) for info in data['PriceChargingInfo']]
  11766. swapInfo.DiscountPriceChargingInfo = [DiscountPriceCharging(info['FeeTime'], info['ElectricityFee'], info['ServiceFee']) for info in data['DiscountPriceChargingInfo']]
  11767. swapInfo.ElectricityFee = data['ElectricityFee']
  11768. swapInfo.ServiceFee = data['ServiceFee']
  11769. swapInfo.ParkFee = data['ParkFee']
  11770. swapInfo.ChargeTagList = [ChargeTag(0, tag['tagType'], tag['tagDesc'], tag['tagOrder'], tag['tagName'], tag['color']) for tag in data.get('chargeTagList', [])]
  11771. swapInfo.StationTel = data['StationTel']
  11772. swapInfo.ServiceTel = data['ServiceTel']
  11773. swapInfo.Payment = data['Payment']
  11774. swapInfo.SupportOrder = data['SupportOrder']
  11775. swapInfo.Remark = data['Remark']
  11776. swapInfo.RightTag = data['RightTag']
  11777. swapInfo.StationType = data['StationType']
  11778. if swapInfo.swapFlag:
  11779. swapInfo.joinedTime = datetime.datetime.now()
  11780. try:
  11781. swapInfo.save()
  11782. except Exception, e:
  11783. return JsonResponse({"result": 2, "description": "配置失败,请重试"})
  11784. Group.update_group(group_id=groupId, swapFlag=swapInfo.swapFlag)
  11785. SwapGroup.recount_devnum(groupId)
  11786. return JsonOkResponse()
  11787. @permission_required(ROLE.dealer)
  11788. def getInterconnectionDisclaimer(request):
  11789. payload = {
  11790. 'version': '1.01',
  11791. 'content': '<p style="text-align:center;"> &nbsp;互联互通用户协议</p><p style="text-align:left;"> <br />一、【首部及导言】<br />欢迎您使用充电桩互联互通协议!<br />本系统互联互通协议遵从国家关于充电桩互联互通的协议《T/CEC中国电力企业联合会标准》,关于协议的具体规则,可以联系我们技术支持。<br />二、【协议的范围】<br />1、本协议是您与我们充电桩管理平台(以下简称我们)之间关于您使用互联互通功能服务所订立的协议。</p><p style="text-align:left;"> 2、本协议的用户,只指通过我们充电桩管理平台,管理设备的运营商组织和个人,都属于我们的用户。</p><p style="text-align:left;"> 三、【服务内容】<br /><span>1、本协议服务的设备,只有当您打开互联互通开关后,设备才会加入互联互通。关闭开关后,将会地址地址组下的互联互通功能。</span></p>\
  11792. <p style="text-align:left;"> 2、<span>互联互通主要是通过第三方的APP、小程序、H5应用,能够查询到您旗下的设备,并能够通过第三方能够启动充电,并根据账单进行结算。</span></p><p style="text-align:left;">\
  11793. <span>3、互联互通的第三方APP,包括不限于诸如:快电、小桔充电、恒大星脉等等第三方平台,而且每个第三方平台会存在不同的服务区别,包括通过第三方使用充电桩需要提取的佣金、费用结算方式、营销活动推广费用、提现费率等等,具体\
  11794. 情况,在互联互通开放时,请您和我们技术支持沟通确认。</span></p><p style="text-align:left;"> <span>四、【服务要求】</span></p><p style="text-align:left;"> <span>1、您提供的设备,包括交流桩和直流桩,能够保证设备的安全性、可靠性、可用性,以及设备本身的数据统计准确,应当尽量避免因此引起的纠纷。因此而引起的纠纷,我们要求由您负责并处理。</span>\
  11795. </p><p style="text-align:left;"> <span>2、您提供配置的设备信息,包括互联互通的信息,应当准确并符合实际,避免出现消费者对平台进行投诉,因此产生的投诉,将有您负责,并且我们将有权对不符合实际情况的互联互通进行关闭,以保障充电用户的权益。</span>\
  11796. </p><p style="text-align:left;"> <span>3、产生的一些售后处理,可能需要您和我们一起处理,我们希望您保持联系方式的畅通,以保证服务质量。如果用户或者第三方平台投诉到我们这里,我们却多次无法联系到您,我们有权强制禁用您的互联互通功能。</span></p>\
  11797. <p style="text-align:left;"> <span>五、【售后及其他】</span></p><p style="text-align:left;"> <span>1、平台的相关售后,包括您使用的后台、互联互通,由我们负责,如有疑问,可以直接联系我们。</span>\
  11798. </p><p style="text-align:left;"> <span>2、设备相关售后,诸如设备故障、设备维修等,导致的互联互通服务售后,由您负责,我们售后可能会联系您,需要您保持联系方式畅通。</span></p><p style="text-align:left;"> <span><br /></span></p>'
  11799. }
  11800. return JsonOkResponse(payload=payload)
  11801. @error_tolerate(nil=DefaultJsonErrorResponse)
  11802. @permission_required(ROLE.dealer, ROLE.subaccount)
  11803. def getCustomizePoint(request):
  11804. logicalCode = request.GET.get('logicalCode')
  11805. dev = Device.get_dev_by_l(logicalCode)
  11806. if dev is None:
  11807. return JsonErrorResponse(description=u"参数错误")
  11808. box = ActionDeviceBuilder.create_action_device(dev)
  11809. unit = box.get_customize_score_unit()
  11810. if unit is None:
  11811. return JsonResponse({'result': 0, 'description': "", 'payload': {}})
  11812. return JsonResponse({'result': 0, 'description': "", 'payload': [unit]})
  11813. @error_tolerate(nil=DefaultJsonErrorResponse)
  11814. @permission_required(ROLE.dealer, ROLE.subaccount)
  11815. def onCustomizePoint(request):
  11816. logicalCode = request.POST.get('logicalCode')
  11817. pointNum = request.POST.get('time')
  11818. portList = json.loads(request.POST.get('attachParas')).get('chargeIndex')
  11819. openId = request.user.managerialOpenId
  11820. dev = Device.get_dev_by_l(logicalCode)
  11821. if dev is None:
  11822. return JsonErrorResponse(description=u"参数错误")
  11823. box = ActionDeviceBuilder.create_action_device(dev)
  11824. address = Group.get_group(dev['groupId'])['address']
  11825. groupName = Group.get_group(dev['groupId'])['groupName']
  11826. errorList = []
  11827. errdesc = ''
  11828. for port in portList:
  11829. try:
  11830. box.start_customize_point(pointNum, openId, int(port))
  11831. UpscoreRecord(
  11832. logicalCode=dev['logicalCode'],
  11833. devNo=dev['devNo'],
  11834. ownerId=str(request.user.id),
  11835. time=datetime.datetime.now(),
  11836. score=pointNum,
  11837. address=address,
  11838. groupName=groupName,
  11839. devType=dev['devType']['name'],
  11840. type="",
  11841. remark=u'自定义上分:%s%s' % (pointNum, request.POST.get('unit'))
  11842. ).save()
  11843. except ServiceException, e:
  11844. errorList.append(port)
  11845. errdesc = ',' + e.result.get('description')
  11846. continue
  11847. except Exception, e:
  11848. errorList.append(port)
  11849. continue
  11850. if errorList:
  11851. return JsonResponse({'result': 0, 'description': u"出现上分失败" + errdesc, 'payload': {'errorList':errorList}})
  11852. return JsonResponse({'result': 0, 'description': u"上分成功", 'payload': {'errorList':errorList}})
  11853. @error_tolerate(nil=DefaultJsonErrorResponse)
  11854. @permission_required(ROLE.dealer)
  11855. def getPolicyInfos(request):
  11856. lc = request.GET.get('logicalCode')
  11857. dev = Device.get_dev_by_l(lc)
  11858. box = ActionDeviceBuilder.create_action_device(dev)
  11859. result = box.get_policy_infos()
  11860. return JsonOkResponse(payload=result)
  11861. @error_tolerate(nil=DefaultJsonErrorResponse)
  11862. @permission_required(ROLE.dealer)
  11863. def setPolicyInfos(request):
  11864. payload = json.loads(request.body)
  11865. lc = payload.get('logicalCode')
  11866. dev = Device.get_dev_by_l(lc)
  11867. box = ActionDeviceBuilder.create_action_device(dev)
  11868. try:
  11869. box.set_policy_infos(payload)
  11870. except ServiceException, e:
  11871. return JsonErrorResponse(description=e.result.get('description'))
  11872. return JsonOkResponse(description=u'计费配置保存成功')
  11873. @error_tolerate(logger = logger)
  11874. def refundOrderNotifier(request, pay_app_type):
  11875. """
  11876. 退款回调接口(经销商目前只有微信和京东聚合支付微信部分)
  11877. :param request:
  11878. :param pay_app_type:
  11879. :return:
  11880. """
  11881. assert pay_app_type in PayAppType.choices(), 'not support this pay app type({})'.format(pay_app_type)
  11882. notifier_cls = RefundManager().get_notifier(pay_app_type)
  11883. response = notifier_cls(request, lambda filter: RefundDealerRechargeRecord.get_record(**filter)).do(
  11884. refund_post_pay)
  11885. return response