1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- """
- web.device.models
- ~~~~~~~~~
- """
- import copy
- import re
- import time
- import uuid
- import logging
- import datetime
- import warnings
- import hashlib
- import math
- import arrow
- from django.utils.functional import cached_property
- from parse import parse
- from pymongo.errors import DuplicateKeyError
- from pymongo.results import UpdateResult
- from typing import List, Tuple, Dict, Set, Optional, Any, Union, TYPE_CHECKING
- from apilib.systypes import IterConstant
- import simplejson as json
- from bson.objectid import ObjectId
- from django.conf import settings
- from django.core.cache import cache, caches
- from django.utils.module_loading import import_string
- from apilib.utils_json import json_dumps, json_loads
- from apilib.utils_mongo import format_dot_key
- from apps.web.common.models import OperatorLog, MonthlyPackageTemp
- from apps.web.core import ROLE
- from apps.web.core.exceptions import RentDeviceError, NoGroupFound
- from apps.web.core.helpers import ActionDeviceBuilder
- from apps.web.core.sysparas import SysParas
- from apps.web.dealer.constant import LinkageSwitchEnum
- from apps.web.exceptions import UserServerException
- from apps.web.helpers import DeviceTypeVisitor
- from apps.web.management.models import DeviceReplacement
- from library.memcache import Client as memcacheClient
- from mongoengine import StringField, DictField, ListField, BooleanField, FloatField, DateTimeField, ValidationError, \
- IntField, PointField, EmbeddedDocumentListField, EmbeddedDocument, DoesNotExist, ObjectIdField, QuerySet, \
- NotUniqueError, LazyReferenceField, DynamicDocument, DateField, EmbeddedDocumentField, DynamicEmbeddedDocument, \
- LongField
- from mongoengine.queryset.visitor import Q
- from apilib.monetary import VirtualCoin, AccuracyRMB, Percent
- from apilib.utils import rec_update_dict, flatten
- from apps.web.constant import Const, FAULT_RECORD_STATUS, FAULT_LEVEL, SimStatus, DeviceCmdCode, DeviceOnlineStatus, \
- MQTT_TIMEOUT, skip_package_unit_verify_list, skip_package_range_verify_list, skip_package_params_verify_list, \
- support_policy_weifule, support_policy_device
- from apps.web.device.define import DeviceChannelType, SOFT_VER_NO_PULSE_RE_LIST, PULSE_DEV_TYPE_RE, BT_DEV_TYPE_RE, \
- SOFT_VER_ONLY_PULSE_RE_LIST, TCP_DEV_TYPE_RE
- from apps.web.common.errors import NotInChoices
- from apps.web.core.db import Searchable, MonetaryField, AccuracyMoneyField, VirtualCoinField
- from apps.web.core.networking import MessageSender
- from apps.web.device.utils import device_online_cache_key, device_control_cache_key, device_warning_cache_key
- from apilib.monetary import RMB
- if TYPE_CHECKING:
- from apps.web.dealer.models import Dealer, DealerDict
- from apps.web.eventer import EventBuilder
- from apps.web.core.adapter.base import SmartBox
- from apps.web.common.models import UserSearchable
- from apps.web.user.models import ConsumeRecord
- logger = logging.getLogger(__name__)
- class GroupCacheMgr(object):
- """
- 地址组
- """
- @staticmethod
- def __group_ids_of_dealer_cache_key(dealer_id):
- # type:(str)->str
- """
- 经销商拥有的地址缓存
- :type dealer_id:
- """
- return 'dealer_group_ids_{ownerId}'.format(ownerId = dealer_id)
- @staticmethod
- def __group_ids_of_partner_cache_key(partner_id):
- # type:(str)->str
- """
- 合伙人拥有的地址缓存
- :type partner_id: object
- """
- return 'partner_group_ids_{partnerId}'.format(partnerId = partner_id)
- @classmethod
- def __group_cache_key(cls, group_id):
- return 'group_{id}'.format(id = group_id)
- @classmethod
- def __many_group_cache_key(cls, group_id_list):
- return [cls.__group_cache_key(group_id) for group_id in group_id_list]
- @classmethod
- def __group_id_from_group_cache_key(cls, group_cache_key):
- # type: (str)->str
- return group_cache_key.split('_')[1]
- @staticmethod
- def __default_group_id_key(dealer_id):
- return '{}_default_group_id'.format(dealer_id)
- @classmethod
- def invalid_group_cache(cls, groupIds):
- # type: (list)->None
- cache.delete_many(cls.__many_group_cache_key(groupIds))
- @classmethod
- def set_group_cache(cls, group_id, value):
- # type: (str, GroupDict)->None
- cache.set(cls.__group_cache_key(group_id), json_dumps(value, serialize_type = True))
- @classmethod
- def get_group_cache(cls, group_id):
- # type: (str)->Union[GroupDict, None]
- cache_value = cache.get(cls.__group_cache_key(group_id))
- if cache_value:
- return GroupDict(json_loads(cache_value))
- else:
- return None
- @classmethod
- def get_many_group_cache(cls, group_id_list):
- # type: (list)->dict
- group_id_key_list = cls.__many_group_cache_key(group_id_list)
- rv = {}
- for group_cache_key, value in cache.get_many(group_id_key_list).iteritems():
- group_id = cls.__group_id_from_group_cache_key(group_cache_key)
- rv[group_id] = GroupDict(json.loads(value))
- return rv
- @classmethod
- def invalid_group_ids_of_dealer_cache(cls, dealer_id):
- # type: (str)->None
- cache.delete(cls.__group_ids_of_dealer_cache_key(dealer_id))
- @classmethod
- def set_group_ids_of_dealer_cache(cls, dealer_id, value):
- # type: (str, list)->None
- cache.set(cls.__group_ids_of_dealer_cache_key(dealer_id), value)
- @classmethod
- def get_group_ids_of_dealer_cache(cls, dealer_id):
- # type: (str)->Union[list, None]
- return cache.get(cls.__group_ids_of_dealer_cache_key(dealer_id))
- @classmethod
- def invalid_group_ids_of_partner_cache(cls, partner_id):
- # type: (str)->None
- cache.delete(cls.__group_ids_of_partner_cache_key(partner_id))
- @classmethod
- def set_group_ids_of_partner_cache(cls, partner_id, value):
- # type: (str, list)->None
- cache.set(cls.__group_ids_of_partner_cache_key(partner_id), value)
- @classmethod
- def get_group_ids_of_partner_cache(cls, partner_id):
- # type: (str)->Union[list, None]
- return cache.get(cls.__group_ids_of_partner_cache_key(partner_id))
- @classmethod
- def invalid_group_ids_of_partner_and_dealer_cache(cls, owner_id):
- # type: (str)->None
- cache.delete_many([cls.__group_ids_of_dealer_cache_key(owner_id),
- cls.__group_ids_of_partner_cache_key(owner_id)])
- @classmethod
- def get_default_group_id(cls, dealer_id):
- # type: (str)->str
- return cache.get(cls.__default_group_id_key(dealer_id))
- @classmethod
- def set_default_group_id(cls, dealer_id, group_id):
- return cache.set(cls.__default_group_id_key(dealer_id), group_id)
- class DeviceControlInfo(Searchable):
- devNo = StringField(verbose_name = u"设备编号", min_length = 1, unique = True)
- value = StringField(verbose_name = u'设备控制信息', default = '')
- meta = {
- 'collection': 'device_control_info',
- 'db_alias': 'logdata'
- }
- @staticmethod
- def get(devNo):
- try:
- obj = DeviceControlInfo.objects.get(devNo = devNo)
- result = json.loads(obj.value)
- return result
- except DoesNotExist, e:
- pass
- return {}
- @staticmethod
- def set(devNo, valueDict):
- try:
- value = json_dumps(valueDict)
- DeviceControlInfo.get_collection().update({'devNo': devNo}, {'$set': {'devNo': devNo, 'value': value}},
- upsert = True)
- except Exception, e:
- logger.info('set device=%s json e=%s' % (devNo, e))
- @staticmethod
- def delete(devNo):
- try:
- DeviceControlInfo.get_collection().remove({'devNo': devNo})
- except Exception, e:
- logger.info('remove device=%s control info e=%s' % (devNo, e))
- class GroupLinkageSwitch(DynamicEmbeddedDocument):
- """
- 设备组开关项
- """
- chargeInsurance = BooleanField(default=False, verbose_name=u"充电险开关")
- def to_dict(self):
- return {"chargeInsurance": self.chargeInsurance}
- class Group(Searchable):
- ownerId = StringField(verbose_name = "所有者", default = "")
- groupName = StringField(verbose_name = "名称", default = "")
- address = StringField(verbose_name = "地址", default = "")
- districtId = StringField(verbose_name = "地域", default = "")
- addressType = StringField(verbose_name = "类型", default = "")
- ruleDict = DictField(verbose_name = "充值规则", default = Const.DEFAULT_DISCOUNT_RULE)
- cardRuleDict = DictField(verbose_name = "卡充值规则", default = {})
- partnerList = ListField(verbose_name = "合伙人", default = [])
- isDefault = BooleanField(verbose_name = "是否默认地址", default = True)
- isFree = BooleanField(verbose_name = "是否供免费使用", default = False)
- # 功能形按钮
- popPriceDescriptionButton = BooleanField(verbose_name = "扫码后是否弹出计费规则", default = False)
- beforeCharge = BooleanField(verbose_name = "强制充值", default = False)
- dateTimeAdded = DateTimeField(default = datetime.datetime.now, verbose_name = '添加进来的时间')
- dateTimeUpdated = DateTimeField(default = datetime.datetime.now, verbose_name = '更新时间')
- country = StringField(verbose_name = '镇村', default = '')
- town = StringField(verbose_name = '镇区', default = '')
- village = StringField(verbose_name = '村居委会', default = '')
- monthlyPackage = LazyReferenceField(verbose_name = "包月套餐", document_type = MonthlyPackageTemp)
- currencyGroup = StringField(verbose_name = u"地址标签", default = '')
- maxVCard = IntField(verbose_name = u"可发售的虚拟卡的数量", default = 9999)
- otherConf = DictField(verbose_name = u'用于扩充记录', default = {'elecFee': 1.0, 'devElec': 0.2})
- linkageSwitch = EmbeddedDocumentField(document_type=GroupLinkageSwitch, verbose_name="开关", default=GroupLinkageSwitch)
-
- swapFlag = BooleanField(verbose_name = "互联互通标记", default = False)
-
- meta = {
- "collection": "Group",
- "db_alias": "default",
- 'indexes': [
- {
- 'fields': ['ownerId', 'groupName'],
- 'unique': True
- }
- ],
- }
- CacheMgr = GroupCacheMgr
- def __repr__(self):
- return '<Group id=%s>' % (self.id,)
- @property
- def groupId(self):
- """
- 兼容GroupDict接口
- :return:
- """
- return str(self.id)
- @property
- def monthlyRule(self):
- if self.monthlyPackage:
- package = self.monthlyPackage.fetch() # type: MonthlyPackageTemp
- else:
- from apps.web.dealer.models import Dealer
- dealer = Dealer.objects.get(id = self.ownerId)
- package = dealer.defaultMonthlyPackage # type: MonthlyPackageTemp
- if package.saleable:
- return package
- return None
- @monthlyRule.setter
- def monthlyRule(self, package):
- self.update(monthlyPackage = package)
- # 覆写. 需要对ruleDict参数进行一次转换
- def update(self, **kwargs):
- if 'ruleDict' in kwargs:
- rule_dict = kwargs.pop('ruleDict')
- kwargs.update({'ruleDict': format_dot_key(rule_dict)})
- if 'cardRuleDict' in kwargs:
- card_rule_dict = kwargs.pop('cardRuleDict')
- kwargs.update({'cardRuleDict': format_dot_key(card_rule_dict)})
- update_result = super(Group, self).update(full_result = True, **kwargs) # type: UpdateResult
- created = bool(update_result.upserted_id)
- updated = bool((not update_result.upserted_id) and update_result.matched_count and update_result.modified_count)
- if updated:
- self.CacheMgr.invalid_group_cache([str(self.id)])
- return {'created': created, 'updated': updated, 'groupId': update_result.upserted_id} if created else {
- 'created': created, 'updated': updated, 'groupId': str(self.id)
- }
- def delete(self, signal_kwargs = None, **write_concern):
- super(Group, self).delete(signal_kwargs, **write_concern)
- self.CacheMgr.invalid_group_cache([str(self.id)])
- @property
- def cached(self):
- return self.get_group(str(self.id))
- @property
- def format_rule_dict(self):
- return format_dot_key(self.ruleDict, to_dot = True)
- @property
- def format_card_dict(self):
- return format_dot_key(self.cardRuleDict, to_dot = True)
- @classmethod
- def __update_group(cls, group, **update):
- # type: (Group, Dict)->str
- """
- 实现比较别扭,利用以下几个事实:
- 如果是添加一个地址, old_if_default == new_if_default, old_partner_list == new_partner_list
- 如果更新一个地址,但是isDefault不更新, old_if_default == new_if_default
- 如果更新一个地址,但是partnerList不更新,old_partner_list == new_partner_list
- 注意利用update等接口,mongoengine不用更新model。这里也不想reload,直接利用传入参数来判断
- :param group:
- :param update:
- :return:
- """
- old_if_default = group.isDefault
- old_partner_list = group.partnerList
- new_if_default = update.get(Group.isDefault.name, old_if_default)
- new_partner_list = update.get(Group.partnerList.name, old_partner_list)
- update_result = group.update(upsert = True, **update) # type: dict
- try:
- group_id = update_result['groupId']
- if (update_result['created'] and new_if_default) or (
- update_result['updated'] and new_if_default and new_if_default != old_if_default):
- objs = Group.objects(ownerId = group.ownerId, id__ne = group_id, isDefault = True).filter()
- for obj in objs:
- try:
- obj.update(isDefault = False)
- except Exception as e:
- # 当添加第一个组的时候,会取不到旧的组
- logger.debug('adding first group %s' % e)
- return group_id
- finally:
- if update_result['created']:
- cls.CacheMgr.invalid_group_ids_of_dealer_cache(group.ownerId)
- for partner in new_partner_list:
- cls.CacheMgr.invalid_group_ids_of_partner_cache(partner['id'])
- else:
- if new_if_default and new_if_default != old_if_default:
- cls.CacheMgr.set_default_group_id(group.ownerId, str(group.id))
- old_partner_ids = set([partner['id'] for partner in old_partner_list])
- new_partner_ids = set([partner['id'] for partner in new_partner_list])
- need_invalid_partner_ids = old_partner_ids ^ new_partner_ids
- for partner_id in need_invalid_partner_ids:
- cls.CacheMgr.invalid_group_ids_of_partner_cache(partner_id)
- @classmethod
- def update_group(cls, group_id, **payload):
- group = Group.objects(id=str(group_id)).first()
- if not group:
- logger.debug('failed to get group %s' % (group_id,))
- return False, u'地址不存在,请更新后重试', group_id
- if 'ownerId' in payload:
- ownerId = payload.pop('ownerId')
- if ownerId != group.ownerId:
- logger.error('set ownerId<{}> != groupOwnerId<{}>'.format(ownerId, group.ownerId))
- return False, u'非经销商所属地址,请联系客服', group_id
- try:
- group_id = Group.__update_group(group, **payload)
- return True, 'success', group_id
- except NoGroupFound, e:
- logger.exception('group is not exist. groupId = %s, dealerId = %s' % (group_id, group.ownerId))
- return False, u'组不存在,请更新后再试', group_id
- except Exception as e:
- logger.exception(
- 'save group error. exception = %s, groupId = %s, dealerId=%s' % (e, group_id, group.ownerId))
- return False, u'更新失败,请重试', group_id
- @classmethod
- def add_group(cls, ownerId, name, districtId, address, addressType, isDefault, discountRuleDict, discountCardRuleDict, country, tag, beforeCharge):
- objs = cls.objects(ownerId=ownerId) # type: QuerySet
- if objs.count() >= 2000:
- return False, u'最多只能保存2000个地址', None
- group = objs.filter(groupName=name).first()
- if group:
- return False, u'相同名称的地址已经存在', None
- try:
- update = {
- 'districtId': districtId,
- 'address': address,
- 'addressType': addressType,
- 'isDefault': isDefault,
- 'ruleDict': discountRuleDict,
- 'cardRuleDict': discountCardRuleDict,
- 'country': country,
- 'tag': tag,
- 'beforeCharge': beforeCharge
- }
- group = cls(
- ownerId=ownerId,
- groupName=name
- )
- group_id = cls.__update_group(group, **update)
- return True, 'success', group_id
- except Exception as e:
- logger.exception('add address error=%s' % e)
- return False, u'保存地址错误', None
- @classmethod
- def delete_Group(cls, ownerId, groupId):
- try:
- group = cls.objects(id = str(groupId)).first() # type: Group
- if not group:
- return False
- else:
- group.delete()
- cls.CacheMgr.invalid_group_ids_of_dealer_cache(ownerId)
- for partner in group.partnerList:
- cls.CacheMgr.invalid_group_ids_of_partner_cache(partner['id'])
- return True
- except Exception as e:
- logger.exception(e)
- return False
- @classmethod
- def __cache_and_get_group(cls, groupId):
- # type: (str)->Union[GroupDict, None]
- try:
- group = cls.objects(id = ObjectId(groupId)).first() # type: Group
- if not group:
- return None
- partnerDict = {}
- for partner in group.partnerList:
- partnerDict[partner['id']] = partner
- newRuleDict = format_dot_key(group['ruleDict'], to_dot = True)
- newCardRuleDict = format_dot_key(group["cardRuleDict"], to_dot = True)
- value = GroupDict({
- 'groupId': str(group.id),
- 'address': group.address,
- 'districtId': group.districtId,
- 'addressType': group.addressType,
- 'isDefault': group.isDefault,
- 'groupName': group.groupName,
- 'ruleDict': newRuleDict,
- 'cardRuleDict': newCardRuleDict,
- 'partnerDict': partnerDict,
- 'ownerId': group.ownerId,
- 'isFree': group.isFree,
- 'beforeCharge': group.beforeCharge,
- 'country': group.country,
- 'town': group.town,
- 'village': group.village,
- 'dateTimeAdded': group.dateTimeAdded,
- 'currencyGroup': group.currencyGroup,
- 'maxVCard': group.maxVCard,
- 'linkageSwitch': group.linkageSwitch.to_dict(),
- 'swapFlag': group.swapFlag,
- 'popPriceDescriptionButton': group.popPriceDescriptionButton,
- "otherConf": group.otherConf
- })
- cls.CacheMgr.set_group_cache(group_id = groupId, value = value)
- return value
- except Exception as e:
- logger.exception('get group = %s, error = %s' % (groupId, e))
- return None
- @classmethod
- def get_group_ids_of_partner(cls, partner_id):
- partner_group_list = cls.CacheMgr.get_group_ids_of_partner_cache(partner_id = partner_id)
- if partner_group_list:
- return partner_group_list
- partner_group_list = []
- try:
- rcds = Group.get_collection().find({'partnerList.id': partner_id})
- for rcd in rcds:
- partner_group_list.append(str(rcd['_id']))
- cls.CacheMgr.set_group_ids_of_partner_cache(partner_id, partner_group_list)
- except Exception, e:
- logger.exception('get partner group list error=%s' % e)
- return partner_group_list
- # 添加搜索(先筛选缓存,再找数据库)
- @classmethod
- def search_group_ids_of_partner(cls, partner_id, searchKey = None):
- partner_group_list = cls.CacheMgr.get_group_ids_of_partner_cache(partner_id = partner_id)
- if partner_group_list:
- if searchKey:
- for item in cls.get_groups_by_group_ids(partner_group_list).values():
- if searchKey.upper() not in item[u'groupName'].upper():
- partner_group_list.remove(item[u'groupId'])
- return partner_group_list
- partner_group_list = []
- try:
- rcds = Group.get_collection().find({u'partnerList.id': partner_id})
- for rcd in rcds:
- if searchKey.upper() in rcd[u'groupName'].upper():
- partner_group_list.append(str(rcd[u'_id']))
- except Exception, e:
- logger.exception('get partner group list error=%s' % e)
- return partner_group_list
- @classmethod
- def get_group_ids_of_dealer(cls, dealer_id):
- dealer_group_list = cls.CacheMgr.get_group_ids_of_dealer_cache(dealer_id)
- if dealer_group_list:
- assert isinstance(dealer_group_list, list), 'adrList has to be a list, %s was given, ownerId=%s' % (
- dealer_group_list, dealer_id)
- return dealer_group_list
- dealer_group_list = []
- try:
- objs = Group.objects.filter(ownerId = dealer_id)
- for obj in objs:
- dealer_group_list.append(str(obj.id))
- if dealer_group_list:
- cls.CacheMgr.set_group_ids_of_dealer_cache(dealer_id = dealer_id, value = dealer_group_list)
- else:
- logger.debug('groups of dealer<id={}> is zero.'.format(dealer_id))
- except Exception as e:
- logger.exception('get group list error=%s' % e)
- return dealer_group_list
- # 添加搜索(先筛选缓存,再找数据库)
- @classmethod
- def search_group_ids_of_dealer(cls, dealer_id, searchKey = None):
- dealer_group_list = cls.CacheMgr.get_group_ids_of_dealer_cache(dealer_id)
- if dealer_group_list is not None:
- if searchKey:
- for item in cls.get_groups_by_group_ids(dealer_group_list).values():
- if searchKey.upper() not in item['groupName'].upper():
- dealer_group_list.remove(item['groupId'])
- assert isinstance(dealer_group_list, list), 'adrList has to be a list, %s was given, ownerId=%s' % (
- dealer_group_list, dealer_id)
- return dealer_group_list
- dealer_group_list = []
- try:
- objs = Group.objects.filter(ownerId = dealer_id, groupName__contains = searchKey)
- for obj in objs:
- dealer_group_list.append(str(obj.id))
- except Exception, e:
- logger.exception('get group list error=%s' % e)
- return dealer_group_list
- @classmethod
- def get_group_ids_of_dealer_and_partner(cls, ownerId):
- return cls.get_group_ids_of_dealer(ownerId) + cls.get_group_ids_of_partner(ownerId)
- @classmethod
- def get_groups_by_group_ids(cls, groupIds):
- # type: (list)->dict
- value_dict = cls.CacheMgr.get_many_group_cache(group_id_list = groupIds)
- left_group_ids = list(set(groupIds) - set(value_dict.keys()))
- for group_id in left_group_ids:
- group_dict = cls.__cache_and_get_group(group_id)
- if group_dict:
- value_dict[group_id] = group_dict
- return value_dict
- @classmethod
- def get_groups_of_dealer(cls, dealerId):
- return cls.get_groups_by_group_ids(cls.get_group_ids_of_dealer(dealerId)).values()
- @classmethod
- def get_dealer_group(cls, dealerId, **kwargs):
- group = cls.objects.filter(ownerId = dealerId, **kwargs).first()
- return group
- @classmethod
- def get_group(cls, groupId):
- # type: (str)->GroupDict
- """
- 没有找到组返回None
- """
- if not groupId: return None
- group_dict = cls.CacheMgr.get_group_cache(groupId)
- if group_dict:
- return group_dict
- else:
- return cls.__cache_and_get_group(groupId)
- @classmethod
- def get_default_group_id(cls, dealer_id):
- group_id = cls.CacheMgr.get_default_group_id(dealer_id)
- if not group_id:
- default_group = Group.objects(ownerId = dealer_id, isDefault = True).first()
- if default_group:
- group_id = str(default_group.id)
- cls.CacheMgr.set_default_group_id(dealer_id, group_id)
- return group_id
- @classmethod
- def get_default_group(cls, dealer_id):
- default_group_id = cls.get_default_group_id(dealer_id)
- if not default_group_id:
- return None
- return cls.get_group(default_group_id)
- @classmethod
- def get_groupName_by_logicalCode(cls, logicalCode):
- groupId = Device.objects(logicalCode = logicalCode).first().groupId
- if groupId != '':
- return Group.get_group(groupId)['groupName']
- else:
- return None
- @classmethod
- def get_group_ids_without_partner(cls, ownerId):
- gs = cls.objects(ownerId = ownerId)
- return [str(_.id) for _ in gs if _.partnerList is None or _.partnerList == []]
- @classmethod
- def get_all_partner_ids(cls, dealerId):
- groups = cls.objects.filter(ownerId = dealerId)
- partners = set()
- for _group in groups:
- if _group.partnerList:
- for _partner in _group.partnerList:
- partners.add(_partner["id"])
- return partners
- @classmethod
- def get_lawful_partner_ids(cls, dealerId):
- """获取经销商的所有 有效的合伙人Id"""
- groups = cls.objects.filter(ownerId = dealerId)
- partners = list()
- for _group in groups:
- if not _group.partnerList:
- continue
- for _partner in _group.partnerList:
- if float(_partner["percent"]) <= 0:
- continue
- partners.append(_partner["id"])
- return set(partners)
- @classmethod
- def check_virtual_card_number(cls, groupId):
- from apps.web.user.models import UserVirtualCard
- vCard = UserVirtualCard.objects.filter(
- groupIds__in = [groupId],
- expiredTime__gt = datetime.datetime.now()
- )
- group = cls.objects.get(id = groupId)
- return group.maxVCard > vCard.count()
- @classmethod
- def invalid_group_cache(cls, groupIds):
- cls.CacheMgr.invalid_group_cache(groupIds)
- @classmethod
- def is_currency_mode_group(cls, groupId1, groupId2):
- # type: (str,str) -> bool
- if groupId1 == groupId2:
- return True
- group1 = cls.get_group(groupId1)
- group2 = cls.get_group(groupId2)
- if not all([group1, group2]): # 没有组
- return False
- dealerId1 = group1.get('ownerId')
- dealerId2 = group2.get('ownerId')
- if dealerId1 != dealerId2: # 不是一个经销商
- return False
- from apps.web.dealer.models import Dealer
- dealer = Dealer.objects.filter(id = dealerId1).first()
- if not dealer:
- return False
- currency_mode = dealer.currency_mode
- if currency_mode == 'allYes':
- return True
- elif currency_mode == 'allNo':
- return False
- elif currency_mode == 'asGroup':
- currencyGroup1 = group1.get('currencyGroup') # 此处默认为""
- currencyGroup2 = group2.get('currencyGroup')
- if currencyGroup1 == currencyGroup2: # 在同一个通用规则下
- return True
- else:
- return False
- elif currency_mode == '': # 默认不通用
- return False
- else:
- pass
- def get_linkage_switch(self):
- return {
- LinkageSwitchEnum.CHARGE_INSURANCE: self.linkageSwitch.chargeInsurance
- }
- def turn_on(self, category):
- """
- 打开保险的开关
- """
- if category == LinkageSwitchEnum.CHARGE_INSURANCE:
- self.linkageSwitch.chargeInsurance = True
- self.update(linkageSwitch__chargeInsurance=self.linkageSwitch.chargeInsurance)
- self.invalid_group_cache([str(self.id)])
- def turn_off(self, category):
- """
- 关闭保险的开关
- """
- if category == LinkageSwitchEnum.CHARGE_INSURANCE:
- self.linkageSwitch.chargeInsurance = False
- self.update(linkageSwitch__chargeInsurance=self.linkageSwitch.chargeInsurance)
- self.invalid_group_cache([str(self.id)])
- class DeviceDefaultSetting(Searchable):
- """默认值修改,如默认清洗套餐等, 方便配置管理"""
- devType = StringField(verbose_name = "设备类型", unique = True)
- packages = ListField(DictField(), verbose_name = "套餐", default = [])
- meta = {"collection": "DeviceDefaultSetting", "db_alias": "default"}
- class MajorDeviceType(Searchable):
- name = StringField(verbose_name = u'主类型名称', unique = True)
- createdTime = DateTimeField(default = datetime.datetime.now, verbose_name = u'添加进来的时间')
- search_fields = ('name',)
- meta = {'collection': 'major_device_type', 'db_alias': 'default'}
- def __repr__(self): return '<MajorDeviceType name=%s>' % (self.name,)
- def to_dict(self):
- return {
- 'name': self.name,
- }
- class BillAsServiceFeature(dict):
- @property
- def support(self):
- return self.get('support', False)
- @property
- def on(self):
- if not self.support:
- return False
- return self.get('on', False)
- @property
- def elec_charge(self):
- return RMB(self.get('elecCharge', 0))
- @property
- def service_charge(self):
- return RMB(self.get('serviceCharge', 0))
- @property
- def charge_unit(self):
- if self.support:
- return {
- 'elecCharge': self.elec_charge,
- 'serviceCharge': self.service_charge
- }
- else:
- return None
- def current_elec_fee(self, consumeMoney):
- return RMB(float(consumeMoney) / float(self.elec_charge + self.service_charge) * float(self.elec_charge))
- def current_service_fee(self, consumeMoney):
- return RMB(float(consumeMoney) / float(self.elec_charge + self.service_charge) * float(self.service_charge))
- class DeviceType(Searchable):
- name = StringField(verbose_name = u'设备类型名称(经销商,代理商,厂商看到的名称)')
- alias = StringField(verbose_name = u'设备类型别名(扫码用户看到的类型)')
- code = StringField(verbose_name = '设备编码')
- online = BooleanField(verbose_name = '是否为在线设备')
- package = ListField(DictField(), verbose_name = '套餐', default = [])
- # : 有部分设备,如售货机,套餐的时间属性,并无意义,通过此字段可以跳过对时间的处理
- timeBased = BooleanField(verbose_name = '计量是否以时间为基准', default = True)
- stock = BooleanField(verbose_name = '是否库存', default = False)
- instructions = StringField(default = '', verbose_name = '使用说明')
- dateTimeAdded = DateTimeField(default = datetime.datetime.now, verbose_name = '添加进来的时间')
- unit = StringField(verbose_name = '消费单位', default = u'分钟') # 消费单位,多少钱**包/分钟/升/度
- payableWhileBusy = BooleanField(verbose_name = u'是否支持端口正在使用时追加充值', default = False)
- displayCardCharge = BooleanField(verbose_name = u'是否支持套餐页面显示充卡入口', default = False)
- #: 每次注册累加,通过权重来排序
- popularity = IntField(verbose_name = '展示权重', default = 0)
- agentId = StringField(verbose_name = '所属代理商')
- managerId = StringField(verbose_name = '所属厂商')
- supportDiagnostics = BooleanField(verbose_name = u'是否支持自主调测', default = False)
- supportVirtualCard = BooleanField(verbose_name = u'是否支持虚拟卡的使用', default = True)
- supportIcCardcharge = BooleanField(verbose_name = u'是否支持IC卡的充值', default = True)
- majorDeviceType = StringField(verbose_name = u'主类型名称', null = False)
- autoRefundEnable = BooleanField(verbose_name = u'是否支持自动退款', default = True)
- finishedMessageTemplateDict = DictField(verbose_name = u'结束推送信息模板字典', default = {})
- finishedReasonDict = DictField(verbose_name = u'结束原因类型字典', default = {})
- servicesButtonDict = DictField(verbose_name = u'正在服务显示按钮字典', default = {})
- features = DictField(verbose_name = u'设备类型特性', default = {})
- dailyRent = DictField(verbose_name=u"设备类型的日租特性", default={})
-
- extraInfo = DictField(verbose_name=u"特定设备类型的特殊自定义信息", default={})
- meta = {'collection': 'DeviceType', 'db_alias': 'default', 'unique_together': {'name', 'agentId'}}
- def __repr__(self):
- return '<DeviceType(code=%s)>' % (self.code,)
- @classmethod
- def all(cls, agentId):
- return [_.to_dict() for _ in cls.objects(agentId = str(agentId)).all()]
- @classmethod
- def most_popular(cls):
- return cls.objects().order_by('-popularity').first()
- def to_dict(self):
- result = {
- 'id': str(self.id),
- 'name': self.name,
- 'alias': self.alias or self.name,
- 'code': self.code,
- 'online': self.online,
- 'package': self.package,
- 'timeBased': self.timeBased,
- 'stock': self.stock,
- 'unit': self.unit,
- 'instructions': self.instructions,
- 'payableWhileBusy': self.payableWhileBusy,
- 'majorDeviceType': self.majorDeviceType,
- 'supportDiagnostics': self.supportDiagnostics,
- 'supportVirtualCard': self.supportVirtualCard,
- 'features': self.features,
- 'autoRefundEnable': self.autoRefundEnable,
- 'displayCardCharge': self.displayCardCharge,
- 'extraInfo': dict()
- }
- for _k, _v in self.extraInfo.items():
- result['extraInfo'].update({_k: _v})
-
- return result
-
- @property
- def dict_for_register_device(self):
- return {
- 'id': str(self.id),
- 'name': self.name,
- 'code': self.code,
- 'online': self.online,
- 'timeBased': self.timeBased,
- 'stock': self.stock,
- 'unit': self.unit,
- 'instructions': self.instructions,
- 'payableWhileBusy': self.payableWhileBusy,
- 'majorDeviceType': self.majorDeviceType,
- 'supportDiagnostics': self.supportDiagnostics,
- 'supportVirtualCard': self.supportVirtualCard,
- 'features': self.features,
- 'autoRefundEnable': self.autoRefundEnable,
- 'displayCardCharge': self.displayCardCharge
- }
- @classmethod
- def get_by_ids(cls, ids):
- return cls.objects.filter(id__in = ids)
- @classmethod
- def get_by_id(cls, id_):
- try:
- return cls.objects.filter(id = id_).first()
- except ValidationError:
- logger.exception('')
- return None
- @classmethod
- def get_services_button(cls, id):
- return cls.objects(id = id).first().servicesButtonDict
- @property
- def supportRent(self):
- """
- 设备类型是否支持租售
- :return:
- """
- return bool(self.dailyRent)
- @property
- def rentTerm(self):
- """
- 设备类型的租期
- :return:
- """
- if not self.supportRent: raise RentDeviceError(u"该设备类型不支持出租")
- return self.dailyRent["rentTerm"]
- @property
- def rentMoney(self):
- """
- 该设备类型的单日租金
- :return:
- """
- if not self.supportRent: raise RentDeviceError(u"该设备类型不支持出租")
- return self.dailyRent["rentMoney"]
- @property
- def maxWaitForActive(self):
- if not self.supportRent: raise RentDeviceError(u"该设备类型不支持出租")
- return self.dailyRent["maxWaitForActive"]
- @property
- def bill_as_service_feature(self):
- # type: ()->BillAsServiceFeature
- return BillAsServiceFeature(self.features.get('billAsService', {}))
- @classmethod
- def is_pulse_device_type(cls, device_type_code):
- if not device_type_code:
- return False
- if device_type_code in [Const.DEVICE_TYPE_CODE_HP_GATE, Const.DEVICE_TYPE_CODE_QUICK_CHARGE]:
- return False
- if PULSE_DEV_TYPE_RE.match(device_type_code):
- return True
- else:
- return False
- @classmethod
- def is_bt_device_type(cls, device_type_code):
- if not device_type_code:
- return False
- if BT_DEV_TYPE_RE.match(device_type_code):
- return True
- else:
- return False
- @classmethod
- def find_candidate(cls, devObj, dealer):
- # type: (Device, Dealer)->Tuple[List, List]
- def is_only_pulse_soft_version(softVer):
- for item in SOFT_VER_ONLY_PULSE_RE_LIST:
- if item.match(softVer):
- return True
- else:
- return False
- def is_hw_support_pulse(device):
- support = True
- if device.softVer.startswith('v6.'):
- if device.hwVer in ['2gsck', 'pureuart', 'flb', '4gcat1dual']:
- support = False
- elif device.mf == 'Quectel':
- pass
- else:
- for item in SOFT_VER_NO_PULSE_RE_LIST:
- if item.match(device.softVer):
- support = False
- break
- return support
- def handle_bt(devObj, dealer):
- # type: (Device, Dealer)->Tuple[List, List]
- recommend, all = [], []
- lastObj = Device.objects(__raw__ = {
- 'ownerId': str(dealer.id),
- 'logicalCode': {'$regex': '^[^B]'}
- }).order_by('-dateTimeUpdated').first()
- if lastObj and lastObj.devType and lastObj.devType.get('id') and lastObj.devType.get('code'):
- if DeviceType.is_bt_device_type(lastObj.devType.get('code')):
- lastDevType = lastObj.devType
- else:
- lastDevType = None
- else:
- lastDevType = None
- last_id_equal_list = []
- last_type_equal_list = []
- bt_list = []
- try:
- devTypes = DeviceTypeVisitor().visit(dealer)
- except Exception as e:
- logger.warning('dealer<id={}> exception in device type visitor.'.format(str(dealer.id)))
- devTypes = []
- for devType in devTypes:
- if not DeviceType.is_bt_device_type(devType.code):
- continue
- if lastDevType:
- if str(devType.id) == lastDevType.get('id') and str(devType.code) == lastDevType.get('code'):
- last_id_equal_list.append(devType.to_dict())
- continue
- elif str(devType.code) == lastDevType.get('code'):
- last_type_equal_list.append(devType.to_dict())
- continue
- bt_list.append(devType.to_dict())
- if last_id_equal_list:
- recommend = last_id_equal_list
- all.extend(recommend)
- all.extend(last_type_equal_list)
- else:
- recommend = last_type_equal_list
- all.extend(recommend)
- all.extend(bt_list)
- return recommend, all
- def handle_pulse_driver_code(devObj, dealer):
- # type: (Device, Dealer)->Tuple[List, List]
- hw_support_pulse = is_hw_support_pulse(device = devObj)
- recommend, all = [], []
- if not hw_support_pulse:
- return recommend, all
- lastObj = Device.objects(ownerId = str(dealer.id), driverCode = devObj.driverCode).order_by(
- '-dateTimeUpdated').first()
- if lastObj and lastObj.devType and lastObj.devType.get('id') and lastObj.devType.get('code'):
- if DeviceType.is_pulse_device_type(lastObj.devType.get('code')):
- lastDevType = lastObj.devType
- else:
- lastDevType = None
- else:
- lastDevType = None
- last_id_equal_list = []
- last_type_equal_list = []
- pulse_list = []
- try:
- devTypes = DeviceTypeVisitor().visit(dealer)
- except Exception as e:
- logger.warning('dealer<id={}> exception in device type visitor.'.format(str(dealer.id)))
- devTypes = []
- for devType in devTypes:
- if not DeviceType.is_pulse_device_type(devType.code):
- continue
- if lastDevType:
- if str(devType.id) == lastDevType.get('id') and str(devType.code) == lastDevType.get('code'):
- last_id_equal_list.append(devType.to_dict())
- continue
- elif str(devType.code) == lastDevType.get('code'):
- last_type_equal_list.append(devType.to_dict())
- continue
- pulse_list.append(devType.to_dict())
- if last_id_equal_list:
- recommend = last_id_equal_list
- all.extend(recommend)
- all.extend(last_type_equal_list)
- else:
- recommend = last_type_equal_list
- all.extend(recommend)
- all.extend(pulse_list)
- return recommend, all
- def handle_not_pulse_driver_code(devObj, dealer):
- hw_support_pulse = is_hw_support_pulse(device = devObj)
- supportDevTypes = DeviceTypeDriverRelation.support_device_type_list(devObj.driverCode)
- if (not supportDevTypes) and (not hw_support_pulse):
- logger.warning('driver code {} is not registered.'.format(devObj.driverCode))
- return [], []
- lastObj = Device.objects(ownerId = str(dealer.id), driverCode = devObj.driverCode).order_by(
- '-dateTimeUpdated').first()
- if lastObj and lastObj.devType and lastObj.devType.get('id') and lastObj.devType.get('code'):
- lastDevType = lastObj.devType
- lastDevTypeCode = lastDevType.get('code')
- if not lastDevTypeCode:
- lastDevType = None
- else:
- if DeviceType.is_pulse_device_type(lastDevTypeCode):
- if not hw_support_pulse:
- lastDevType = None
- else:
- if lastDevTypeCode not in supportDevTypes:
- lastDevType = None
- else:
- lastDevType = None
- recommend, all = [], []
- pulse_list = []
- equal_list = []
- no_pulse_list = []
- last_id_equal_list = []
- last_type_equal_list = []
- try:
- devTypes = DeviceTypeVisitor().visit(dealer)
- except Exception as e:
- logger.warning('dealer<id={}> exception in device type visitor.'.format(str(dealer.id)))
- devTypes = []
- for devType in devTypes:
- if lastDevType:
- if str(devType.id) == lastDevType.get('id') and devType.code == lastDevType.get('code'):
- last_id_equal_list.append(devType.to_dict())
- continue
- elif str(devType.code) == lastDevType.get('code'):
- last_type_equal_list.append(devType.to_dict())
- continue
- if str(devType.code) not in supportDevTypes:
- if DeviceType.is_pulse_device_type(str(devType.code)):
- if hw_support_pulse:
- pulse_list.append(devType.to_dict())
- continue
- else:
- continue
- else:
- if devType.code == devObj.driverCode:
- equal_list.append(devType.to_dict())
- else:
- no_pulse_list.append(devType.to_dict())
- if last_id_equal_list:
- recommend = last_id_equal_list
- all.extend(recommend)
- all.extend(last_type_equal_list)
- else:
- recommend = last_type_equal_list
- all.extend(recommend)
- all.extend(equal_list)
- all.extend(no_pulse_list)
- all.extend(pulse_list)
- return recommend, all
- def handle_no_driver_code(devObj, dealer):
- # type: (Device, Dealer)->Tuple[List, List]
- recommend, all = [], []
- if devObj.softVer and is_only_pulse_soft_version(devObj.softVer):
- only_pulse = True
- else:
- only_pulse = False
- try:
- devTypes = DeviceTypeVisitor().visit(dealer)
- except Exception as e:
- logger.warning('dealer<id={}> exception in device type visitor.'.format(str(dealer.id)))
- devTypes = []
- for devType in devTypes:
- if only_pulse:
- if DeviceType.is_pulse_device_type(devType.code):
- all.append(devType.to_dict())
- else:
- all.append(devType.to_dict())
- return recommend, all
- def handle_tcp_device(devObj, dealer):
- lastObj = Device.objects(ownerId = str(dealer.id), driverCode = devObj.driverCode).order_by(
- '-dateTimeUpdated').first()
- if lastObj and lastObj.devType and lastObj.devType.get('id') and lastObj.devType.get('code'):
- lastDevType = lastObj.devType
- else:
- lastDevType = None
- recommend, all = [], []
- last_id_equal_list = []
- last_type_equal_list = []
- match_list = []
- match_re = re.compile('^{}[0-9]{}$'.format(devObj.driverCode[0:2], devObj.driverCode[3:]))
- try:
- devTypes = DeviceTypeVisitor().visit(dealer)
- except Exception as e:
- logger.warning('dealer<id={}> exception in device type visitor.'.format(str(dealer.id)))
- devTypes = []
- for devType in devTypes:
- if not match_re.match(devType.code):
- continue
- if lastDevType:
- if str(devType.id) == lastDevType.get('id') and match_re.match(devType.code):
- last_id_equal_list.append(devType.to_dict())
- continue
- elif str(devType.code) == lastDevType.get('code') and match_re.match(devType.code):
- last_type_equal_list.append(devType.to_dict())
- continue
- match_list.append(devType.to_dict())
- if last_id_equal_list:
- recommend = last_id_equal_list
- all.extend(recommend)
- all.extend(last_type_equal_list)
- else:
- recommend = last_type_equal_list
- all.extend(recommend)
- all.extend(match_list)
- return recommend, all
- if Device.utils_is_bluetooth(devObj.logicalCode):
- return handle_bt(devObj, dealer)
- elif devObj.driverCode:
- if TCP_DEV_TYPE_RE.match(devObj.driverCode):
- return handle_tcp_device(devObj, dealer)
- elif devObj.driverCode in ['000000', '999999']:
- # 没有驱动版本, 这个无法注册, 必须先处理问题
- return [], []
- elif devObj.driverCode in ['100000', '100120']:
- # 仅支持脉冲的驱动版本
- return handle_pulse_driver_code(devObj, dealer)
- else:
- if devObj.softVer and is_only_pulse_soft_version(devObj.softVer):
- # 只支持脉冲的软件版本
- return handle_pulse_driver_code(devObj, dealer)
- else:
- return handle_not_pulse_driver_code(devObj, dealer)
- else:
- if devObj.softVer and is_only_pulse_soft_version(devObj.softVer): # 只支持脉冲的软件版本
- return handle_pulse_driver_code(devObj, dealer)
- else:
- return handle_no_driver_code(devObj, dealer)
- class DeviceTypeDriverRelation(DynamicDocument):
- driverCode = StringField(required = True, null = False)
- devTypeCode = StringField(required = True, null = False)
- meta = {
- 'collection': 'device_type_driver_relation',
- 'db_alias': 'default',
- "indexes": [
- 'driverCode',
- {'fields': ['driverCode', 'devTypeCode'], 'unique': True}
- ],
- }
- @classmethod
- def support_device_type_list(cls, driverCode):
- return [str(obj.devTypeCode) for obj in cls.objects(driverCode = driverCode).all()]
- class DeviceCacheMgr(object):
- LOGICAL_CODE_KEY = 'logicalCode{}'
- DEVNO_UNDER_GROUP_KEY = '{groupId}_devList'
- @classmethod
- def __l_cache_key(cls, logicalCode):
- return cls.LOGICAL_CODE_KEY.format(logicalCode)
- @classmethod
- def delete_l_cache(cls, logicalCode):
- cache.delete(cls.__l_cache_key(logicalCode))
- @classmethod
- def update_l_cache(cls, devNo, logicalCode):
- cache.set(cls.__l_cache_key(logicalCode), str(devNo))
- @classmethod
- def get_dev_no_from_l_cache(cls, logicalCode):
- return cache.get(cls.__l_cache_key(logicalCode))
- @classmethod
- def __dev_no_list_of_group_cache_key(cls, group_id):
- # type:(str)->str
- return cls.DEVNO_UNDER_GROUP_KEY.format(groupId = group_id)
- @classmethod
- def set_dev_no_list_of_group_cache(cls, group_id, dev_no_list):
- # type: (str, list)->None
- cache.set(cls.__dev_no_list_of_group_cache_key(group_id = group_id), dev_no_list)
- @classmethod
- def get_dev_no_list_of_group_cache(cls, group_id):
- return cache.get(cls.__dev_no_list_of_group_cache_key(group_id))
- @classmethod
- def delete_dev_no_list_of_group_cache(cls, group_id):
- cache.delete(cls.__dev_no_list_of_group_cache_key(group_id = group_id))
- @classmethod
- def get_many_dev_no_list_of_group_cache(cls, group_id_list):
- return {
- parse(cls.DEVNO_UNDER_GROUP_KEY, key).named['groupId']: items
- for key, items in
- cache.get_many([cls.__dev_no_list_of_group_cache_key(_) for _ in group_id_list]).iteritems()
- }
- @classmethod
- def delete_many_dev_no_list_of_group_cache(cls, group_id_list):
- # type: (List[str])->None
- cache.delete_many([cls.__dev_no_list_of_group_cache_key(group_id = groupId) for groupId in group_id_list])
- @classmethod
- def delete_device_cache(cls, dev_no):
- cache.delete(dev_no)
- @classmethod
- def delete_many_device_cache(cls, dev_no_list):
- cache.delete_many(dev_no_list)
- @staticmethod
- def update_device_cache(devNo, devValue):
- cache.set(devNo, devValue)
- @classmethod
- def get_many_device_cache(cls, dev_no_list):
- return cache.get_many(dev_no_list)
- @classmethod
- def get_device_cache(cls, dev_no):
- return cache.get(dev_no)
- class DeviceRegisterLog(EmbeddedDocument):
- operation = StringField(verbose_name = u'注册行为(register,unregister)')
- ownerId = ObjectIdField(verbose_name = u'经销商ID')
- dateTimeAdded = DateTimeField(verbose_name = u'设备注册时间', default = lambda: datetime.datetime.now())
- operator = StringField(verbose_name = u'操作员', default = '')
- extra = DictField(verbose_name = u'额外信息', default = {})
- class DailyRent(EmbeddedDocument):
- """
- 设备日租相关的特性
- """
- # 与设备相关的
- active = BooleanField(verbose_name=u"是否激活", default=False)
- # 租金与租期与设备类型相互绑定 租金的单位是元 租期的单位是天
- rentMoney = MonetaryField(verbose_name=u"单日租金")
- rentTerm = IntField(verbose_name=u"租期")
- # 激活的截至时间 超过这个时间系统会自动激活
- # 设备被标记为出租设备的日期
- rentDate = DateTimeField(verbose_name=u"出租日期")
- # 设备的截至激活日期 超过这个时间 设备将会自动激活
- lastActiveDate = DateTimeField(verbose_name=u"激活截至日期")
- # 设备的实际激活时间
- activeDate = DateTimeField(verbose_name=u"激活日期")
- # 结算相关
- lastRentDate = DateField(verbose_name=u"最后结算的日期 结算到了哪一天")
- class Device(Searchable):
- devNo = StringField(verbose_name = u"设备编号", min_length = 1, unique = True)
- logicalCode = StringField(verbose_name = u"逻辑编码", default = None)
- devType = DictField(verbose_name = "设备类型", default = {})
- maxCoins = IntField(verbose_name = "最大投币数", default = 4)
- groupId = StringField(verbose_name = "地址ID", default = "")
- districtId = StringField(verbose_name = "地域", default = "")
- ownerId = StringField(verbose_name = "所有者", default = "")
- groupNumber = StringField(verbose_name = "设备组内编号", default = "")
- server = StringField(verbose_name = "server", default = "120.27.251.159:1883")
- server1 = StringField(verbose_name = "IP1", default = "")
- mf = StringField(verbose_name = "厂商", default = "")
- softVer = StringField(verbose_name = "软件版本", default = "")
- hwVer = StringField(verbose_name = "固件版本", default = "")
- cycle = IntField(verbose_name = "心跳间隔", default = Const.DEV_CYCLE_DEFAULT)
- washConfig = DictField(verbose_name = "设备配置", default = {})
- tempWashConfig = DictField(verbose_name = "临时设备配置", default = {})
- trapSwtich = IntField(verbose_name = "trap开关", default = 1)
- heartSwitch = StringField(verbose_name = "心跳开关", default = "")
- remarks = StringField(verbose_name = "备注", default = "")
- signal = IntField(verbose_name = "信号", default = 0)
- pulseWidth1 = IntField(verbose_name = "脉冲宽度", default = 40)
- pulseInterval1 = IntField(verbose_name = "脉冲间隔", default = 500)
- battery = IntField(verbose_name = "待机电平", default = 0)
- isFault = BooleanField(verbose_name = "是否故障停用", default = False)
- isDND = BooleanField(verbose_name = u'是否勿扰模式', default = False)
- isDNDTimeInterval = ListField(verbose_name = u'勿扰模式时间区间', default = [])
- dateTimeAdded = StringField(default = lambda: datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- verbose_name = '设备添加进来的时间')
- # TODO: 这个名字不太合适
- dateTimeUpdated = DateTimeField(default = lambda: datetime.datetime.now(),
- verbose_name = '经销商注册时间, 其他操作不能按照字段名来更新, 只能在注册的时候更新该时间')
- location = PointField(default = None, verbose_name = '设备经纬度')
- expireDate = DateTimeField(default = None, verbose_name = '流量卡费用截止时间') # 废弃掉
- simExpireDate = DateTimeField(default = None, verbose_name = 'SIM卡费用过期时间(数据来自运营商)')
- simActiveDate = DateTimeField(default = None, verbose_name = 'SIM卡激活时间(数据来自运营商)')
- simActiveFirstTime = DateTimeField(default = None, verbose_name = 'SIM卡激活时间(数据来自设备上报事件)')
- simStatus = StringField(default = SimStatus.Updated,
- verbose_name = 'sim卡的状态') # updated:表示已经更新了 ;chargedUnupdated充值了,但是未更新时间;illegal 非法卡
- simChargeAuto = BooleanField(default = False, verbose_name = u'sim卡自动充值与否')
- simSource = StringField(default = '', verbose_name = 'sim卡商') # jieyang/hezhou/qiben
- serviceState = StringField(default = Const.ServiceState.Normal.name, verbose_name = '服务状态Const.ServiceState')
- instructions = StringField(default = '', verbose_name = '设备自定义使用说明', max_length = 100)
- autoRefundLeftMoney = BooleanField(verbose_name = '是否支持设备自动退款', default = False)
- imsi = StringField(default = '', verbose_name = 'imsi')
- iccid = StringField(default = '', verbose_name = 'iccid')
- iccidHistory = ListField(field = StringField(), verbose_name = u'SIM卡换卡记录', default = [])
- otherConf = DictField(verbose_name = u'各种设备其他配置', default = {})
- driverCode = StringField(default = '', verbose_name = 'driverCode')
- driverVersion = StringField(default = '', verbose_name = 'driverVersion')
- mcuVersion = StringField(default = '', verbose_name = 'mcuVersion')
- coreVer = StringField(default = '', verbose_name = u'核心版本')
- boardValid = IntField(verbose_name = u'主板检测电压有效值(0 - 低电平有效, 1 - 高电平有效, 2 - 不做检测)', default = 2)
- # boardVolt = IntField(verbose_name=u'主板检测电压(0 - 低电平, 1 - 高电平)', default=0)
- annualTrafficCost = MonetaryField(default = Const.PLATFORM_DEFAULT_TRAFFIC_COST, verbose_name = '该字段废弃')
- trafficCardCost = MonetaryField(verbose_name = "流量卡的真实成本", default = None)
- dateTimeBinded = DateTimeField(verbose_name = u'设备绑定时间', default = None)
- debug = StringField(verbose_name = u'调试标记', default = '')
- registerLog = EmbeddedDocumentListField(document_type = DeviceRegisterLog, verbose_name = u'设备(解)注册日志')
- stockDetailDict = DictField(verbose_name = u'库存详情', default = {})
- nodeDict = DictField(verbose_name = u'节点字典', default = {}) # {'1':devNo}
- gatewayNode = StringField(verbose_name = u'网关节点 devNo', default = '')
- isRent = BooleanField(verbose_name=u"设备是否出租", default=False)
- dailyRent = EmbeddedDocumentField(document_type=DailyRent, verbose_name=u"设备出租的相关信息")
- binder = StringField(verbose_name = u'绑定者标识', default = '')
- isApi = BooleanField(verbose_name=u"是否未API设备", default=None)
- disableADExpireDate = DateTimeField(verbose_name=u'纯净版有效期', default=None)
- policyTemp = DictField(verbose_name=u'计费模板', default={})
- meta = {
- 'collection': 'Device',
- 'db_alias': 'default',
- # 'shard_key':('devNo',)
- }
- search_fields = ('devNo', 'logicalCode')
- __mgr_cache = caches['devmgr']
- __base_cache_mgr = DeviceCacheMgr
- def __str__(self):
- return '{}<logicalCode={} devNo={}>'.format(self.__class__.__name__, self.logicalCode, self.devNo)
- @property
- def devTypeCode(self):
- return self.devType.get('code', '')
- @property
- def devTypeName(self):
- return self.devType.get('name', '')
- @property
- def devTypeFeatures(self):
- return self.devType.get('features', {})
- @property
- def bill_as_service_feature(self):
- # type: ()->BillAsServiceFeature
- return BillAsServiceFeature(self.devTypeFeatures.get('billAsService', {}))
- def rent(self):
- """
- 将设备标记为出租类型 标记前必须是已经注册的设备
- 除了激活信息外 其余所有出租信息均已在此添加
- :return:
- """
- if self.isRent: raise RentDeviceError(u"设备已经出租,请勿重复操作!")
- # 出租日期
- rentDate = datetime.datetime.now()
- devType = DeviceType.objects.get(id=self.devType["id"]) # type: DeviceType
- # 添加激活 的相关信息
- dailyRent = DailyRent(
- active=False,
- rentMoney=RMB(devType.rentMoney),
- rentTerm=int(devType.rentTerm),
- rentDate=rentDate,
- lastActiveDate=rentDate + datetime.timedelta(days=devType.maxWaitForActive),
- )
- # 兼容之前的没有isRent的设备
- result = self.__class__.objects.filter(
- Q(id=self.id),
- Q(isRent=False) | Q(isRent=None)
- ).update(
- isRent=True,
- dailyRent=dailyRent
- )
- if not result:
- raise RentDeviceError(u"操作失败")
- # TODO 禁用设别(如何禁用)
- def active_rent(self):
- """
- 激活出租的设备 设备激活后
- 从激活的当天开始收取日租费用
- 激活的设备不能再次激活
- """
- if self.dailyRent.active:
- raise RentDeviceError(u"请勿重复激活设备")
- # 更正激活状态和日期
- self.__class__.objects.filter(
- id=self.id,
- dailyRent__active=False
- ).update(
- dailyRent__activeDate=datetime.datetime.now(),
- dailyRent__active=True
- )
- @property
- def rentMoney(self):
- """
- 设备的租金
- """
- return RMB(self.dailyRent.rentMoney)
- def __hash__(self):
- return hash(self.devNo)
- @classmethod
- def __fill_up_online_info(cls, device, online_cache_info):
- # type: (dict, dict)->dict
- device.update({
- 'online': DeviceOnlineStatus.DEV_STATUS_OFFLINE,
- 'offTime': 0,
- 'signal': 0,
- 'updateTime': 0
- })
- try:
- # 蓝牙或者特殊的调试标记的模块始终在线
- if cls.utils_is_bluetooth(device[cls.logicalCode.name]) or device.get('debug', '') == 'fake_online':
- device.update({
- 'online': DeviceOnlineStatus.DEV_STATUS_ONLINE,
- 'updateTime': long(time.time() * 1000)
- })
- return device
- except Exception as e:
- pass
- if online_cache_info:
- online_info = json.loads(online_cache_info)
- if online_info['online'] == DeviceOnlineStatus.DEV_STATUS_ONLINE:
- cycle = device['cycle'] if device['cycle'] else Const.DEV_CYCLE_DEFAULT
- if (long(time.time() * 1000) - long(
- online_info['updateTime'])) > Const.DEVICE_ONLINE_CHECK_TIMES * cycle * 1000:
- device.update(
- {
- 'online': DeviceOnlineStatus.DEV_STATUS_OFFLINE,
- 'updateTime': long(online_info['updateTime']),
- 'offTime': Const.DEVICE_ONLINE_CHECK_TIMES * cycle * 1000 + long(online_info['updateTime'])
- }
- )
- else:
- device.update(
- {
- 'online': DeviceOnlineStatus.DEV_STATUS_ONLINE,
- 'updateTime': long(online_info['updateTime'])
- }
- )
- elif online_info['online'] == DeviceOnlineStatus.DEV_STATUS_OFFLINE:
- device.update(
- {
- 'online': DeviceOnlineStatus.DEV_STATUS_OFFLINE,
- 'offTime': long(online_info['offTime'])
- }
- )
- device.update({'signal': online_info.get('signal', 0)})
- return device
- @classmethod
- def __fill_up_control_info(cls, device, control_cache_info):
- # type: (dict, dict)->dict
- # TODO zjl 将设备的控制信息与故障信息拆开
- device.update({
- 'status': Const.DEV_WORK_STATUS_IDLE,
- 'statusInfo': '',
- })
- if control_cache_info:
- if 'status' not in control_cache_info or 'usePorts' in control_cache_info:
- try:
- ports_cache_info = control_cache_info
- if 'ports' in control_cache_info:
- ports_cache_info = control_cache_info['ports']
- for key, value in ports_cache_info.iteritems():
- if str(key).isdigit():
- # 如果有isStart并且为false, 说明该端口已经结束
- if 'isStart' in value:
- if not value['isStart']:
- continue
- # 没有isStart或者isStart为True, 还需要使用status和finishedTime校正
- # 在没有收到结束事件的时候, 端口也有一个预估的结束时间, 超过这个时间, 也认为结束
- if 'status' in value:
- if 'finishedTime' in value:
- if value['finishedTime'] > int(time.time()):
- device.update({'status': Const.DEV_WORK_STATUS_WORKING})
- break
- else:
- if value['status'] == Const.DEV_WORK_STATUS_WORKING:
- device.update({'status': Const.DEV_WORK_STATUS_WORKING})
- break
- # 如果都没有, 则认为端口空闲
- except Exception as e:
- logger.exception(e)
- device.update({'status': Const.DEV_WORK_STATUS_IDLE})
- else:
- if control_cache_info['status'] == Const.DEV_WORK_STATUS_WORKING:
- if control_cache_info.get('finishedTime', 0) < int(time.time()):
- device.update({'status': Const.DEV_WORK_STATUS_IDLE})
- else:
- device.update({'status': Const.DEV_WORK_STATUS_WORKING})
- # elif control_cache_info['status'] == Const.DEV_WORK_STATUS_FAULT:
- # device.update(
- # {'status': Const.DEV_WORK_STATUS_FAULT,
- # 'statusInfo': control_cache_info.get('statusInfo', u'故障')})
- else:
- device.update({'status': control_cache_info['status']})
- else:
- device.update({'status': Const.DEV_WORK_STATUS_IDLE})
- return device
- @classmethod
- def __fill_up_warning_info(cls, device, warning_cache_info):
- """标记设备是否处于告警状态"""
- warning_cache_info = warning_cache_info or dict()
- for _part, _warning in warning_cache_info.items():
- if _warning.get("warningStatus", False):
- warning = True
- break
- else:
- warning = False
- device["deviceWarning"] = warning
- return device
- @classmethod
- def __fill_up_status_info(cls, device, online_cache_info, service_cache_info, warning_cache_info):
- # type: (dict, dict, dict, dict)->dict
- device = cls.__fill_up_online_info(device, online_cache_info)
- device = cls.__fill_up_control_info(device, service_cache_info)
- device = cls.__fill_up_warning_info(device, warning_cache_info)
- return device
- @classmethod
- def utils_is_expired(cls, device):
- # type:(Union[Device, DeviceDict])->bool
- sim_status = device.simStatus
- if sim_status == SimStatus.Charged:
- return False
- if sim_status == SimStatus.Illegal:
- return True
- # 没有拿到sim卡信息的,可能是才上线,运营商都没有数据。还有一种情况,是换卡(我们家的别人家的)
- sim_expire_date = device.fixedSimExpireDate
- if not sim_expire_date:
- return False
- # 10天内必须充值,不让用
- return datetime.datetime.now() >= sim_expire_date
- @classmethod
- def utils_is_expired_in_this_month(cls, device): # type:(Union[Device, DeviceDict])->bool
- sim_status = device.simStatus
- if sim_status == SimStatus.Charged:
- return False
- if sim_status == SimStatus.Illegal:
- return True
- sim_expire_date = device.fixedSimExpireDate # type: datetime.datetime
- if not sim_expire_date:
- return False
- now = datetime.datetime.now()
- return now.year == sim_expire_date.year and now.month == sim_expire_date.month
- @classmethod
- def utils_is_registered(cls, device):
- # type: (Union[Device, DeviceDict])->bool
- owner_id = device.ownerId
- if owner_id and owner_id != '':
- return True
- else:
- return False
- @classmethod
- def utils_is_bluetooth(cls, logicalCode):
- # type: (str)->bool
- if logicalCode.startswith('B'):
- return True
- else:
- return False
- @classmethod
- def utils_channel_type(cls, device):
- # type: (Union[Device, DeviceDict])->str
- if cls.utils_is_bluetooth(device.logicalCode):
- return DeviceChannelType.Channel_BT
- core_ver = device.coreVer
- if not core_ver:
- return DeviceChannelType.Channel_UNKNOWN
- if 'ASR1802' in core_ver or 'RDA8910' in core_ver:
- if device.mf == 'vivestone_mesh_gate':
- return DeviceChannelType.Channel_4G_GATE
- else:
- return DeviceChannelType.Channel_4G
- if 'LuaRTOS' in core_ver:
- return DeviceChannelType.Channel_WIFI
- if '8955' in core_ver:
- return DeviceChannelType.Channel_2G
- return DeviceChannelType.Channel_UNKNOWN
- @classmethod
- def utils_major_type(cls, device):
- # type: (Union[Device, DeviceDict])->str
- if not cls.utils_is_registered(device):
- return ''
- dev_type = device.devType
- majorDeviceType = dev_type.get('majorDeviceType', None)
- if not majorDeviceType:
- majorDeviceType = device.devType.get('name', None)
- if not majorDeviceType:
- majorDeviceType = u'自助设备'
- return majorDeviceType
- @property
- def is_expire(self):
- return self.utils_is_expired(self)
- @property
- def is_expire_in_this_month(self):
- return self.utils_is_expired_in_this_month(self)
- @classmethod
- def get_sim_expire_date(cls, device):
- # type: (Union[Device, DeviceDict])->Optional[datetime]
- if cls.utils_is_bluetooth(device.logicalCode):
- return None
- if device.simExpireDate:
- expire_date = device.simExpireDate
- elif device.expireDate:
- expire_date = device.expireDate
- else:
- expire_date = None
- if not expire_date:
- return None
- else:
- if device.simStatus == SimStatus.Updated:
- sim_card = SIMCard.objects(iccid = device.iccid).first() # type: SIMCard
- if sim_card and sim_card.channel == '58':
- return expire_date.replace(day = 10)
- return expire_date.replace(day = Const.SIM_CARD_FORBIDDEN_DAY)
- @property
- def fixedSimExpireDate(self):
- return self.get_sim_expire_date(self)
- def is_authorized_to_dealer(self, dealer_id):
- return self.ownerId == dealer_id
- @property
- def channelType(self):
- return self.utils_channel_type(self)
- @property
- def is_registered(self):
- return self.utils_is_registered(self)
- @property
- def majorDeviceType(self):
- return self.utils_major_type(self)
- @classmethod
- def invalid_l_cache(cls, logicalCode):
- cls.__base_cache_mgr.delete_l_cache(logicalCode)
- @classmethod
- def update_l_cache(cls, devNo, logicalCode):
- cls.__base_cache_mgr.update_l_cache(devNo, logicalCode)
- @classmethod
- def invalid_device_cache(cls, devNo):
- cls.__base_cache_mgr.delete_device_cache(devNo)
- @classmethod
- def invalid_many_device_cache(cls, dev_no_list):
- if dev_no_list:
- cls.__base_cache_mgr.delete_many_device_cache(dev_no_list)
- @classmethod
- def __update_device_cache(cls, devNo, devValue):
- cls.__base_cache_mgr.update_device_cache(devNo, json_dumps(data = devValue, serialize_type = True))
- @classmethod
- def __get_device_cache(cls, dev_no):
- cache_info = cls.__base_cache_mgr.get_device_cache(dev_no)
- if not cache_info:
- return None
- return json_loads(cache_info)
- @classmethod
- def get_and_update_device_cache(cls, dev_no, **kwargs):
- # type: (str, Dict)->None
- dev_cache = cls.__get_device_cache(dev_no)
- if not dev_cache:
- return None
- dev_cache.update(**kwargs)
- cls.__update_device_cache(dev_no, dev_cache)
- @classmethod
- def update_online_cache(cls, devNo, online, signal = None,updateTime = None):
- online_key = device_online_cache_key(devNo)
- if not signal:
- online_now_cache = cls.__mgr_cache.get(online_key)
- if online_now_cache:
- online_now_cache = json.loads(online_now_cache)
- if 'signal' in online_now_cache:
- signal = online_now_cache['signal']
- else:
- signal = 0
- else:
- signal = 0
- online_set_cache = {
- 'online': online,
- 'signal': signal,
- 'updateTime': long(time.time() * 1000) if not updateTime else updateTime
- }
- if not online:
- online_set_cache.update({'offTime': time.time()})
- cls.__mgr_cache.set(online_key, json.dumps(online_set_cache))
- return online_set_cache
- @classmethod
- def _get_many_device_status_cache(cls, devNoList):
- cacheKeys = []
- for devNo in devNoList:
- cacheKeys.append(device_online_cache_key(devNo))
- cacheKeys.append(device_control_cache_key(devNo))
- cacheKeys.append(device_warning_cache_key(devNo))
- return cls.__mgr_cache.get_many(cacheKeys)
- @classmethod
- def get_many_device_status_cache(cls, deviceDict):
- # type: (Dict[str, Dict])->Dict[str, Dict]
- result = {}
- all_cache_info = Device._get_many_device_status_cache(deviceDict.keys())
- for devNo, device_info in deviceDict.iteritems():
- result[devNo] = cls.__fill_up_status_info(
- device_info,
- all_cache_info.get(device_online_cache_key(devNo), None),
- all_cache_info.get(device_control_cache_key(devNo), None),
- all_cache_info.get(device_warning_cache_key(devNo), None))
- return result
- @classmethod
- def get_device_status_cache(cls, device):
- # type: (DeviceDict)->DeviceDict
- online_key = device_online_cache_key(device.devNo)
- control_key = device_control_cache_key(device.devNo)
- warning_key = device_warning_cache_key(device.devNo)
- cacheKeys = [online_key, control_key, warning_key]
- cache_info = cls.__mgr_cache.get_many(cacheKeys)
- control_cache_info = cache_info.get(control_key, None)
- if control_cache_info is None:
- logger.debug('oh,memcached missed,devNo=%s' % device.devNo)
- cache_info[control_key] = DeviceControlInfo.get(device.devNo)
- Device.__mgr_cache.set(control_key, cache_info[control_key])
- cls.__fill_up_status_info(
- device,
- cache_info.get(device_online_cache_key(device.devNo), None),
- cache_info.get(device_control_cache_key(device.devNo), None),
- cache_info.get(device_warning_cache_key(device.devNo), None))
- return device
- @staticmethod
- def error_start_times_cache_key(devNo, port):
- return "est_{devNo}_{port}".format(devNo = devNo, port = port)
- @classmethod
- def get_error_start_times(cls, devNo, port):
- cacheKey = Device.error_start_times_cache_key(devNo, port)
- return Device.__mgr_cache.get(cacheKey, 0)
- @classmethod
- def set_error_start_times(cls, devNo, port, value, timeout = None):
- cacheKey = Device.error_start_times_cache_key(devNo, port)
- Device.__mgr_cache.set(cacheKey, value, timeout)
- @classmethod
- def delete_error_start_times(cls, devNo, port):
- cacheKey = Device.error_start_times_cache_key(devNo, port)
- Device.__mgr_cache.delete(cacheKey)
- @classmethod
- def update_dev_control_cache(cls, devNo, newValue):
- """
- 更新设备操作信息.分update和overwrite两种方式,overwrite方式是重写,比如某个端口开始充电,就需要把以前的数据清理掉
- 递归地更新端口信息。
- 如果要更新某个端口的某个字段,该端口其余的信息是保留的,如果要清空用下方的clear_port_control_cache
- :param devNo:
- :param newValue:
- :return:
- """
- key = device_control_cache_key(devNo)
- oldValue = Device.__mgr_cache.get(key)
- if oldValue is None:
- logger.debug('oh,memcached missed,devNo=%s' % devNo)
- oldValue = DeviceControlInfo.get(devNo)
- if not oldValue:
- Device.__mgr_cache.set(key, newValue)
- DeviceControlInfo.set(devNo, newValue)
- return
- if isinstance(oldValue, dict):
- #: 老接口是直接替换 {'port': {}}, 此例不会在递归更新种更新该端口为{}
- if not newValue.values():
- warnings.warn("deprecated, use clear_dev_control_cache instead!", DeprecationWarning)
- return Device.clear_port_control_cache(devNo, newValue.keys()[0])
- else:
- oldValue = rec_update_dict(oldValue, newValue)
- Device.__mgr_cache.set(key, oldValue, 24 * 3600)
- DeviceControlInfo.set(devNo, oldValue)
- #: 获取设备操作信息
- @classmethod
- def get_dev_control_cache(cls, devNo):
- key = device_control_cache_key(devNo)
- result = Device.__mgr_cache.get(key, {})
- if not result:
- logger.debug('oh, memcached missed, devNo=%s' % devNo)
- result = DeviceControlInfo.get(devNo)
- if result:
- Device.__mgr_cache.set(key, result)
- logger.debug('device<devNo={}> control info is: {}'.format(devNo, str(result)))
- return result
- @classmethod
- def get_dev_warning_cache(cls, devNo):
- """获取设备的全部告警信息"""
- key = device_warning_cache_key(devNo)
- result = cls.__mgr_cache.get(key, dict())
- return result
- @classmethod
- def get_part_warning_cache(cls, devNo, part):
- """获取设备部件的告警信息"""
- key = device_warning_cache_key(devNo)
- result = cls.__mgr_cache.get(key, dict())
- partCache = result.get(part, dict())
- return partCache
- @classmethod
- def update_dev_warning_cache(cls, devNo, warningData):
- """更新或新增设备的部件告警信息"""
- key = device_warning_cache_key(devNo)
- oldValue = cls.__mgr_cache.get(key, dict()) # type: dict
- oldValue.update(warningData)
- cls.__mgr_cache.set(key, oldValue)
- @classmethod
- def clear_dev_warning_cache(cls, devNo):
- """清除设备的全部故障"""
- key = device_warning_cache_key(devNo)
- cls.__mgr_cache.set(key, {})
- @classmethod
- def clear_part_warning_cache(cls, devNo, part):
- """清除设备部件告警信息"""
- key = device_warning_cache_key(devNo)
- oldValue = cls.__mgr_cache.get(key, dict()) # type: dict
- partCache = oldValue.get(part)
- if not partCache:
- return
- oldValue.update({part: {}})
- cls.__mgr_cache.set(key, oldValue)
- @classmethod
- def get_port_control_cache(cls, devNo, port):
- _cache_info = cls.get_dev_control_cache(devNo)
- if not _cache_info:
- return {}
- else:
- return _cache_info.get(port, {})
- @classmethod
- def get_many_dev_control_cache(cls, devNoList):
- keyList = [device_control_cache_key(devNo) for devNo in devNoList]
- return Device.__mgr_cache.get_many(keyList, {})
- @classmethod
- def clear_port_control_cache(cls, devNo, port):
- key = device_control_cache_key(devNo)
- oldValue = cls.__mgr_cache.get(key)
- if not oldValue:
- logger.debug('oh,memcached missed,devNo=%s' % devNo)
- oldValue = DeviceControlInfo.get(devNo)
- if not oldValue:
- return {}
- port_cache = {}
- try:
- port_cache = oldValue.get(str(port), {})
- oldValue[str(port)] = {}
- cls.__mgr_cache.set(key, oldValue)
- DeviceControlInfo.set(devNo, oldValue)
- except Exception as e:
- logger.exception(e)
- finally:
- return port_cache
- @classmethod
- def invalid_device_control_cache(cls, devNo):
- DeviceControlInfo.delete(devNo)
- return cls.__mgr_cache.delete(device_control_cache_key(devNo))
- @classmethod
- def get_devNo_by_logicalCode(cls, logicalCode):
- # type: (str)->Optional[str]
- if not logicalCode:
- return None
- devNo = Device.__base_cache_mgr.get_dev_no_from_l_cache(logicalCode)
- if devNo is None:
- try:
- dev = Device.get_collection().find_one({'logicalCode': logicalCode})
- if dev is None:
- return None
- devNo = dev['devNo']
- Device.__base_cache_mgr.update_l_cache(devNo, logicalCode)
- return devNo
- except Exception as e:
- logger.exception('get dev by logicalCode error=%s' % e)
- return devNo
- @classmethod
- def get_logicalCode_by_devNo(cls, devNo):
- try:
- dev = Device.get_dev(devNo) # type: DeviceDict
- if not dev:
- return None
- else:
- return dev.logicalCode
- except Exception as e:
- logger.exception('get logical code failure. dev = %s; error = %s' % (devNo, e))
- return None
- @classmethod
- def get_logicalCode_by_groupId(cls, groupId):
- # type:(str) -> list
- devMap = cls.get_devices_by_group([groupId])
- return [_d.logicalCode for _d in devMap.values() if _d]
- @classmethod
- def __load_dev_no_list_of_group_cache(cls, groupId):
- try:
- objs = Device.objects.filter(groupId = groupId)
- tmpList = [obj.devNo for obj in objs]
- cls.__base_cache_mgr.set_dev_no_list_of_group_cache(groupId, tmpList)
- return tmpList
- except Exception as e:
- logger.exception('load to memcache error=%s,groupId=%s' % (e, groupId))
- return []
- @classmethod
- def __get_dev_no_list_by_group(cls, group_id_list):
- # type: (List[str])->Dict
- result = {}
- valueDict = cls.__base_cache_mgr.get_many_dev_no_list_of_group_cache(group_id_list)
- for group_id, dev_no_list in valueDict.items():
- result[group_id] = dev_no_list
- leftIds = list(set(group_id_list) - set(valueDict.keys()))
- for group_id in leftIds:
- dev_no_list = Device.__load_dev_no_list_of_group_cache(group_id)
- result[group_id] = dev_no_list
- return result
- @classmethod
- def invalid_group_device_list_cache(cls, group_id_list):
- cls.__base_cache_mgr.delete_many_dev_no_list_of_group_cache(group_id_list)
- @classmethod
- def get_device_count_by_group(cls, group_id_list):
- # type: (List[str])->Dict
- value_dict = cls.__get_dev_no_list_by_group(group_id_list)
- return {
- group_id: len(dev_no_list) for group_id, dev_no_list in value_dict.items()
- }
- @classmethod
- def get_devNos_by_group(cls, group_id_list):
- # type: (List[str])->List
- assert isinstance(group_id_list, list), u'groupIds应为list'
- value_dict = cls.__get_dev_no_list_by_group(group_id_list)
- result = []
- for dev_no_list in value_dict.values():
- result.extend(dev_no_list)
- return result
- @staticmethod
- def protected_fields():
- # type:()->list
- """
- 返回不向外公开的字段
- :return:
- """
- return [
- 'mf',
- 'iccid',
- 'server',
- 'imsi',
- 'hwVer',
- 'softVer',
- 'ownerId',
- 'driverCode',
- 'driverVersion',
- 'instructions',
- 'otherConf'
- ]
- @classmethod
- def get_dev_by_nos(cls, devNoList, verbose = False, base_only = False):
- # type:(List[str], Optional[bool], Optional[bool])->(Optional[Dict[str, DeviceDict]])
- """
- :param devNoList: 设备号列表
- :param verbose: 是否显示更详细的信息,如设备所在的组名称
- :return:
- """
- assert isinstance(devNoList, list), u'devNoList应为list'
- def complete(device, verbose = False):
- if not verbose:
- return device
- else:
- groupInfo = Group.get_group(groupId = device['groupId'])
- device['groupInfo'] = groupInfo
- return device
- result = {}
- try:
- all_device_cache_info = Device.__base_cache_mgr.get_many_device_cache(devNoList)
- all_service_cache_info = None
- if not base_only:
- all_service_cache_info = Device._get_many_device_status_cache(devNoList)
- for devNo, device_cache_info in all_device_cache_info.items():
- device_value = complete(json_loads(str(device_cache_info)), verbose = verbose)
- if not base_only:
- device_value = cls.__fill_up_status_info(
- device_value,
- all_service_cache_info.get(device_online_cache_key(devNo), None),
- all_service_cache_info.get(device_control_cache_key(devNo), None),
- all_service_cache_info.get(device_warning_cache_key(devNo), None))
- result[devNo] = DeviceDict(device_value)
- leftDevNoList = set(devNoList) - set(all_device_cache_info.keys())
- for devNo in leftDevNoList:
- logger.debug('device<devNo={}> cache miss.'.format(devNo))
- try:
- obj = Device.objects.get(devNo = devNo) # type: Device
- device_value = {
- 'id': str(obj.id),
- 'devNo': obj.devNo,
- 'server': str(obj.server),
- 'groupNumber': obj.groupNumber,
- 'ownerId': obj.ownerId,
- 'groupId': obj.groupId,
- 'remarks': obj.remarks,
- 'logicalCode': obj.logicalCode,
- 'washConfig': obj.washConfig,
- 'tempWashConfig': obj.tempWashConfig,
- 'devType': obj.devType,
- 'majorDeviceType': obj.majorDeviceType,
- 'isFault': obj.isFault,
- 'isDND': obj.isDND,
- 'isRent': obj.isRent,
- 'isDNDTimeInterval': obj.isDNDTimeInterval,
- 'serviceState': obj.serviceState,
- 'simExpireDate': obj.simExpireDate,
- 'expireDate': obj.expireDate,
- 'simStatus': obj.simStatus,
- 'lbs': obj.lbsFlag,
- 'lat': obj.lat,
- 'lng': obj.lng,
- 'instructions': obj.instructions,
- 'dateTimeAdded': obj.dateTimeAdded,
- 'mf': obj.mf,
- 'softVer': obj.softVer,
- 'hwVer': obj.hwVer,
- 'cycle': obj.cycle,
- 'trapSwtich': obj.trapSwtich,
- 'heartSwitch': obj.heartSwitch,
- 'pulseWidth1': obj.pulseWidth1,
- 'pulseInterval1': obj.pulseInterval1,
- 'battery': obj.battery,
- 'iccid': obj.iccid,
- 'imsi': obj.imsi,
- 'otherConf': obj.otherConf,
- 'driverCode': obj.driverCode,
- 'driverVersion': obj.driverVersion,
- 'coreVer': obj.coreVer,
- 'quantity': getattr(obj, 'quantity', 0),
- 'consumptionQuantity': getattr(obj, 'consumptionQuantity', 0),
- 'debug': obj.debug,
- 'boardValid': obj.boardValid,
- 'disableDevice': getattr(obj, 'otherConf', {}).get('disableDevice', False),
- 'isApi': obj.isApi,
- 'disableADExpireDate': obj.disableADExpireDate,
- 'policyTemp': obj.policyTemp
- }
- if hasattr(obj, 'priceDescription'):
- device_value.update({'priceDescription': obj.priceDescription})
- if obj.logicalCode:
- cls.__update_device_cache(devNo, device_value)
- device_value = complete(device_value, verbose = verbose)
- if not base_only:
- device_value = cls.__fill_up_status_info(
- device_value,
- all_service_cache_info.get(device_online_cache_key(devNo), None),
- all_service_cache_info.get(device_control_cache_key(devNo), None),
- all_service_cache_info.get(device_warning_cache_key(devNo), None)
- )
- result[devNo] = DeviceDict(device_value)
- except Exception as e:
- logger.info('get dev by nos(devNo=%s) error=%s' % (devNo, e))
- continue
- except memcacheClient.MemcachedKeyCharacterError as e:
- logger.exception('invalid memcache key, input=%s error=%s' % (devNoList, e))
- return None
- except Exception as e:
- logger.exception('get_dev_by_nos input=%s error=%s' % (devNoList, e))
- return None
- return result
- @staticmethod
- def get_devices_by_group(groupIds, verbose = False):
- devNoList = Device.get_devNos_by_group(groupIds)
- devDict = Device.get_dev_by_nos(devNoList, verbose)
- return devDict
- @staticmethod
- def all():
- """ 获取所有经销商的设备列表"""
- Dealer = import_string('apps.web.dealer.models.Dealer')
- dealerIds = [str(d.id) for d in Dealer.objects]
- groupIds = flatten([Group.get_group_ids_of_dealer(dealerId) for dealerId in dealerIds])
- return [v for k, v in Device.get_devices_by_group(list(groupIds)).items()]
- @staticmethod
- def get_dev(devNo):
- # type: (str)->Optional[DeviceDict]
- """
- :param devNo:
- :return:
- """
- if (devNo is None) or not (devNo.strip()):
- return None
- devDict = Device.get_dev_by_nos([devNo], base_only = True)
- if (devDict is None) or (devNo not in devDict):
- return None
- return devDict[devNo]
- @staticmethod
- def get_dev_by_logicalCode(logicalCode):
- # type: (str)->DeviceDict
- return Device.get_dev(Device.get_devNo_by_logicalCode(logicalCode))
- get_dev_by_l = get_dev_by_logicalCode
- @classmethod
- def get_devs_by_ownerId(cls, ownerId):
- return Device.get_devices_by_group(Group.get_group_ids_of_dealer(ownerId)).values()
- @classmethod
- def register_device(cls, dealer, devNo, logicalCode, groupId, districtId, groupNumber, remarks, rawWashConfigs,
- devType, agentId=None, policyTemp=None):
- """
- ..20171218
- #: 整改
- 0: 去掉更新devNo, logicalCode字段,该2个字段的对应关系在`预注册`阶段已经插入封闭后期不可更改保持数据的一致性。
- 1: 当缓存找不到该设备时报错,确保无垃圾信息入库
- :param dealer:
- :param devNo:
- :param logicalCode:
- :param groupId:
- :param districtId:
- :param groupNumber:
- :param remarks:
- :param rawWashConfigs:
- :param devType: DeviceType
- :return:
- """
- # 检测套餐单位是否一致
- def check_package_unit(typeCode, package):
- if typeCode in skip_package_unit_verify_list:
- return True
- dic = map(lambda x: {'unit': x.get('unit')}, package)
- res = reduce(lambda x, y: x if x == y else None, dic)
- if res is None:
- return False
- else:
- return True
- # 检查套餐单位参数的范围
- def check_params_range(typeCode, package):
- if typeCode in skip_package_range_verify_list:
- return None
- dic = map(lambda x: [x.get('time')], package)
- res = reduce(lambda x, y: x + y, dic)
- result = None
- for item in res:
- l = str(item).split(".")
- if len(l) > 1 and len(l[1]) > 2:
- result = (res.index(item) // 3) + 1
- break
- return result
- def check_params(typeCode, package):
- if typeCode in skip_package_params_verify_list:
- return True
- lis = map(lambda x: [x.get('time'), x.get('price'), x.get('coins')], package)
- res = reduce(lambda x, y: x + y, lis)
- for i in res:
- if i is None or float(i) < 0:
- return False
- return True
- # 添加sn排序顺序
- for item in rawWashConfigs:
- item["sn"] = rawWashConfigs.index(item)
- # 组装washConfig
- washConfigs = {}
- policyTemps = {}
- devType_dict = devType.to_dict()
- devType_dict.pop('package', None)
- if not check_params(devType_dict["code"], rawWashConfigs):
- return False, u'请完整的填写套餐中的所有参数'
- if not check_package_unit(devType_dict["code"], rawWashConfigs):
- return False, u'提交失败,设备套餐用户获得参数单位不一致'
- f = check_params_range(devType_dict["code"], rawWashConfigs)
- if f:
- return False, u'设备第%s个套餐 用户获得参数应为小数点后两位' % f
- if devType_dict["code"] in support_policy_weifule:
- try:
- from apps.web.core.models import DriverAdapter
- adapter = DriverAdapter.get_driver_adapter(devType['code'], None)
- if adapter.support_device_package:
- washConfigs, policyTemps = adapter.reg_model(dealer, rawWashConfigs, policyTemp, devType)
- except Exception as e:
- return False, e.result['description']
- elif devType_dict["code"] in support_policy_device:
- try:
- from apps.web.core.models import DriverAdapter
- adapter = DriverAdapter.get_driver_adapter(devType['code'], None)
- if adapter.support_device_package:
- washConfigs, policyTemps = adapter.reg_model(dealer, rawWashConfigs, policyTemp, devType)
- except Exception as e:
- return False, e.result['description']
- elif devType_dict["code"] in [Const.DEVICE_TYPE_CODE_WASHCAR_LANGUANG]:
- devType_dict.update({'displayCardCharge': True})
- elif devType_dict["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]:
- ii = 0
- for config in rawWashConfigs:
- ii += 1
- # 注意,为了兼容设备类型里套餐的name字段,已统一更改description 为 name
- washConfigs[str(ii)] = {}
- if 'switch' in config:
- washConfigs[str(ii)].update({'switch': config['switch']})
- if 'billingMethod' in config:
- washConfigs[str(ii)].update({'billingMethod': config['billingMethod']})
- if 'price' in config:
- washConfigs[str(ii)].update({'price': round(float(config['price']), 2) or 0})
- if 'coins' in config:
- washConfigs[str(ii)].update({'coins': round(float(config['coins']), 2) or 0})
- if 'time' in config:
- washConfigs[str(ii)].update({'time': config['time'] or 0})
- if 'name' in config:
- washConfigs[str(ii)].update({'name': config['name'] or '套餐{}'.format(ii)})
- if 'unit' in config:
- washConfigs[str(ii)].update({'unit': config['unit']})
- if 'sn' in config:
- washConfigs[str(ii)].update({'sn': config['sn']})
- if 'autoStop' in config:
- washConfigs[str(ii)].update({'autoStop': config['autoStop']})
- if 'autoRefund' in config:
- washConfigs[str(ii)].update({'autoRefund': config['autoRefund']})
- if 'minAfterStartCoins' in config:
- washConfigs[str(ii)].update({'minAfterStartCoins': config['minAfterStartCoins']})
- if 'minFee' in config:
- washConfigs[str(ii)].update({'minFee': config['minFee']})
- else:
- if devType_dict["code"] == Const.DEVICE_TYPE_CODE_HP_GATE: # 霍珀的阶梯套餐适配
- ii = 0
- tempPackage = {}
- for step in rawWashConfigs:
- ii += 1
- tempPackage[str(ii)] = {
- "maxHour": step.get("maxHour", 24),
- "price": step.get("price"),
- "unit": step.get("unit", u"小时"),
- "sn": step.get("sn")
- }
- washConfigs[str(1)] = tempPackage
- else:
- ii = 0
- for config in rawWashConfigs:
- ii += 1
- # 注意,为了兼容设备类型里套餐的name字段,已统一更改description 为 name
- washConfigs[str(ii)] = {
- 'coins': float(config['coins']),
- 'name': config['name'],
- 'time': float(config.get('time', 0)),
- 'price': float(config['price']),
- 'description': config.get('description', ''),
- 'imgList': config.get('imgList', []),
- 'unit': config.get('unit', u'分钟'),
- 'sn': config.get('sn')
- }
- if config.get('pulse'):
- washConfigs[str(ii)].update({
- 'pulse': float(config.get('pulse')),
- })
- if config.get('basePrice'):
- washConfigs[str(ii)].update({
- 'basePrice': float(config.get('basePrice')),
- })
- if config.get('billingMethod'):
- washConfigs[str(ii)].update({
- 'billingMethod': config.get('billingMethod'),
- })
- # 添加默认套餐到经销商下辖
- dealer.defaultWashConfig[str(devType['id'])] = rawWashConfigs
- dealer.save()
- try:
- traffic_cost = Device.objects.get(devNo=devNo).trafficCardCost
- updateDict = {
- 'ownerId': str(dealer.id),
- 'groupId': groupId,
- 'districtId': districtId,
- 'groupNumber': str(groupNumber),
- 'washConfig': washConfigs,
- 'remarks': remarks,
- 'devType': devType_dict,
- 'isFault': False,
- 'isApi': False,
- 'dateTimeAdded': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- 'dateTimeUpdated': datetime.datetime.now(),
- 'otherConf': {}
- }
- if policyTemp:
- updateDict.update({'policyTemp': policyTemps})
- # 设备如果已经注册过, 就有流量卡成本, 并且始终以这个为准
- if not traffic_cost:
- if dealer.trafficCardCost:
- updateDict.update({'trafficCardCost': dealer.trafficCardCost})
- else:
- from apps.web.agent.models import Agent
- agent = Agent.objects(id=dealer.agentId).get() # type: Agent
- updateDict.update({'trafficCardCost': agent.trafficCardCost})
- if devType_dict['code'] == Const.DEVICE_TYPE_CODE_TISSUE: # 适配的代码,如果是纸巾机,就需要初始化记录库存情况
- updateDict.update({'consumptionQuantity': 0, 'quantity': 0})
- cls.objects(devNo=devNo, logicalCode=logicalCode).update_one(upsert=False, **updateDict)
- content = {
- 'logicalCode': logicalCode,
- 'devNo': devNo,
- 'devTypeCode': devType_dict['code']
- }
- if agentId:
- content.update({'agentId': agentId})
- OperatorLog.log(user=dealer, level=OperatorLog.LogLevel.INFO, operator_name='register device',
- content=content)
-
- except Exception as e:
- logger.exception(
- 'set cache error=%s, when registering device (devNo=%s), ownerId=%s' % (e, devNo, str(dealer.id)))
- return False, u'注册设备失败,请重试'
- finally:
- # 失效缓存
- cls.invalid_device_cache(devNo)
- cls.invalid_group_device_list_cache([groupId])
- return True, 'success'
- @classmethod
- def get_elec_static_time(cls, devNo):
- device = cls.objects(devNo = devNo).first()
- deviceType = DeviceType.objects(id = device.devType['id']).first()
- return deviceType.features.get('elecStaticTime', 900)
- @property
- def lbsFlag(self):
- if self.location:
- return True
- else:
- return False
- @property
- def lbs(self):
- return self.lbsFlag
- @property
- def lat(self):
- if self.location:
- return self.location['coordinates'][1]
- else:
- return 360
- @property
- def lng(self):
- if self.location:
- return self.location['coordinates'][0]
- else:
- return 360
- @staticmethod
- def testSignal(logicalCode):
- devNo = Device.get_devNo_by_logicalCode(logicalCode)
- if devNo is None:
- return u'设备不存在', 0
- device = Device.get_dev(devNo) # type: DeviceDict
- if not device:
- return u'设备不存在', 0
- if not device.online:
- return u'设备掉线,无法获取网络信号情况', 0
- result = MessageSender.send(device, DeviceCmdCode.GET_DEVINFO, {'IMEI': devNo}, timeout = MQTT_TIMEOUT.SHORT)
- if result['rst'] != 0:
- return 'OK', 0
- else:
- return 'OK', int(result.get('signal', 0))
- @classmethod
- def un_register(cls, dev, force=False, operator=None):
- # type: (DeviceDict, bool, str)->None
- if not dev.is_registered:
- logger.debug('dev<no={}> is not registered.'.format(dev.devNo))
- return
- # 出租设备只有系统管理员能够解绑
- if dev.isRent and not force:
- logger.debug("dev <{}> is rent, not allow to unregiste!")
- raise RentDeviceError(u"租用设备无法解绑")
- try:
- emptyValue = {
- 'groupId': Device.groupId.default,
- 'districtId': Device.districtId.default,
- 'devType': Device.devType.default,
- 'groupNumber': Device.groupNumber.default,
- 'washConfig': Device.washConfig.default,
- 'tempWashConfig': Device.tempWashConfig.default,
- 'remarks': Device.remarks.default,
- 'instructions': Device.instructions.default,
- 'otherConf': Device.otherConf.default,
- 'ownerId': '',
- 'policyTemp': Device.policyTemp.default,
- }
- OperatorLog.log(user=dev.owner, level=OperatorLog.LogLevel.INFO,
- operator_name='unregister device' if not force else 'force unregister device',
- content=dict(dev.my_obj.to_mongo()))
- Device.objects(devNo=dev.devNo).update_one(**emptyValue)
- finally:
- Device.invalid_group_device_list_cache([dev.groupId])
- Device.invalid_device_cache(dev.devNo)
- @staticmethod
- def filter(dealerId, searchKey, online = '', expireStatus = '', equipmentGroupId = ''):
- def cmp_group_devName(x, y):
- # type: (Dict, Dict)->int
- if x['groupId'] > y['groupId']:
- return 1
- elif x['groupId'] == y['groupId']:
- if x['online'] < y['online']:
- return -1
- elif x['online'] > y['online']:
- return 1
- else:
- if x['id'] < y['id']:
- return -1
- else:
- return 0
- else:
- return -1
- def match_expire_status(dev, expire_status):
- # type:(DeviceDict, str)->bool
- if expire_status not in ['normal', 'expire', 'toExpire']:
- return True
- if expire_status == 'normal':
- if (not dev.is_expired) and (not dev.is_to_expired):
- return True
- else:
- return False
- if expire_status == 'expire':
- if dev.is_expired:
- return True
- else:
- return False
- if expire_status == 'toExpire':
- if dev.is_to_expired:
- return True
- else:
- return False
- if online == '' or online == 'all':
- onlineList = [0, 1]
- elif online == '1':
- onlineList = [1]
- elif online == '0':
- onlineList = [0]
- else:
- onlineList = []
- groupIds = [equipmentGroupId]
- partnerGroupList = Group.get_group_ids_of_partner(dealerId)
- if equipmentGroupId == 'all' or equipmentGroupId == '':
- groupIds = Group.get_group_ids_of_dealer(dealerId)
- groupIds.extend(partnerGroupList)
- groupDict = Group.get_groups_by_group_ids(groupIds)
- devNoList = Device.get_devNos_by_group(groupIds)
- devs = Device.get_dev_by_nos(devNoList).values()
- devList = []
- for dev in devs: # type: DeviceDict
- try:
- if dev.online not in onlineList:
- continue
- if not match_expire_status(dev, expireStatus):
- continue
- group = groupDict.get(dev['groupId'])
- if any(map(lambda _: searchKey in _, (dev['devNo'],
- dev['remarks'],
- dev['logicalCode'],
- group['groupName'],
- group['address']))):
- item = {
- 'id': dev.devNo,
- 'logicalCode': dev.logicalCode,
- 'name': group['groupName'],
- 'groupId': group['groupId'],
- 'type': dev.devType['name'],
- 'typeId': dev.devType['id'],
- 'online': dev.online,
- 'timeBased': dev.devType.get('timeBased', True),
- 'isManager': False if dev['groupId'] in partnerGroupList else True,
- 'serviceState': dev.get('serviceState', Const.ServiceState.Normal.name),
- 'consumptionQuantity': dev.get('consumptionQuantity', 0),
- 'quantity': dev.get('quantity', 0),
- 'devType': {'code': dev.devType.get('code', '99999')},
- 'expireDate': dev.formatSimExpireDate,
- 'simStatus': dev.simStatus
- }
- devList.append(item)
- except Exception, e:
- logger.exception(
- '[Device.filter] has some error=%s dealerId=%s, searchKey=%s' % (e, dealerId, searchKey))
- continue
- devList.sort(cmp = cmp_group_devName)
- return groupIds, devList
- @staticmethod
- def tree_filter(dealerId = None, agentId = None, managerId = None, searchKey = None, pageIndex = 1, pageSize = 10,
- **kwargs):
- # type: (Optional[str], Optional[str], Optional[str], Optional[str], int, int, **Any)->Tuple[int, List[dict]]
- """
- 分层获取设备列表
- :param dealerId:
- :param agentId:
- :param managerId:
- :param searchKey:
- :param pageIndex:
- :param pageSize:
- :return:
- """
- online = kwargs.get('online', None)
- registered = kwargs.get('registered', None)
- Agent = import_string('apps.web.agent.models.Agent')
- Dealer = import_string('apps.web.dealer.models.Dealer')
- Manager = import_string('apps.web.management.models.Manager')
- shadow = kwargs.get('shadow', False)
- dealerMap = {}
- agentMap = {}
- managerMap = {}
- #: 显示没有注册的设备
- if not registered and registered is not None:
- devices = Device.objects(Q(ownerId__exists = 0) | Q(ownerId = "")).search(searchKey)
- else:
- #: 如果没有任何厂商代理商经销商,显示所有的设备
- if dealerId is not None:
- dealerFilter = Q(id = ObjectId(dealerId))
- else:
- dealerFilter = Q()
- if agentId is not None:
- agentIds = [agentId]
- dealerFilter &= Q(agentId__in = agentIds)
- else:
- if managerId is not None:
- agentQuery = Q(managerId = managerId)
- else:
- managerMap = {
- str(d['_id']): d for d in
- Manager.get_collection().find({}, {'_id': 1, 'nickname': 1, 'username': 1, 'domain': 1})
- }
- agentQuery = Q(managerId__in = managerMap.keys())
- agentMap = {
- str(d['_id']): d
- for d in Agent.get_collection().find(agentQuery.to_query(Agent),
- {'_id': 1, 'username': 1, 'nickname': 1, 'managerId': 1})
- }
- dealerFilter &= Q(agentId__in = agentMap.keys())
- dealerMap = {
- str(d['_id']): d
- for d in Dealer.get_collection().find(dealerFilter.to_query(Dealer),
- {'_id': 1, 'nickname': 1, 'username': 1, 'agentId': 1})
- }
- dealerIds = dealerMap.keys()
- devices = Device.objects(ownerId__in = dealerIds).search(searchKey)
- total = devices.count()
- devNos = []
- groupIds = []
- for d in devices.paginate(pageIndex, pageSize):
- devNos.append(d['devNo'])
- if d['groupId']:
- groupIds.append(d['groupId'])
- devs = Device.get_dev_by_nos(devNos)
- groups = Group.get_groups_by_group_ids(groupIds)
- def device_filter(devices):
- if online is not None:
- for dev in devices: # type: DeviceDict
- if str(dev.online) == str(online):
- yield dev
- else:
- for dev in devices:
- yield dev
- items = []
- for dev in device_filter(devs.values()): # type: DeviceDict
- group = groups.get(dev.groupId, {})
- item = {
- 'logicalCode': dev.logicalCode,
- 'devNo': dev.devNo,
- 'createdTime': dev['dateTimeAdded'],
- 'groupId': dev.groupId,
- 'groupName': group.get('groupName'),
- 'address': group.get('address'),
- 'online': dev.online,
- 'signal': dev.signal,
- 'lastOffTime': dev.offTime,
- 'simExpireDate': dev.fixedSimExpireDate,
- 'simStatus': dev.simStatus,
- 'server': dev.server,
- 'devType': dev.devType,
- 'driverCode': dev.get('driverCode', ''),
- 'driverVersion': dev.get('driverVersion', ''),
- 'cycle': dev['cycle'],
- 'pulseInterval1': dev['pulseInterval1'],
- 'battery': dev['battery'],
- 'imsi': dev['imsi'],
- 'iccid': dev['iccid'],
- 'remarks': dev['remarks'],
- 'registered': dev.is_registered,
- 'softVer': dev['softVer'],
- 'coreVer': dev['coreVer'],
- "disableDevice": dev.get("otherConf", {}).get("disableDevice", False),
- 'hwVer': dev.hwVer,
- 'supportPG': dev.support_power_graph
- }
- if dev['ownerId']:
- if dev['ownerId'] in dealerMap:
- dealer = dealerMap[dev['ownerId']]
- else:
- dealer = Dealer.get_collection().find_one({'_id': ObjectId(dev['ownerId'])},
- {'_id': 1, 'nickname': 1, 'username': 1, 'agentId': 1})
- dealerMap[dev['ownerId']] = dealer
- if dealer['agentId'] not in agentMap:
- agent = Agent.get_collection().find_one({'_id': ObjectId(dealer['agentId'])},
- {'_id': 1, 'username': 1, 'nickname': 1, 'managerId': 1})
- if not agent:
- logger.error(
- 'no agent. dealerId = {}, agentId = {}'.format(dealer['_id'], str(dealer['agentId'])))
- continue
- agentMap[dealer['agentId']] = agent
- agent = agentMap[dealer['agentId']]
- if agent['managerId'] in managerMap:
- manager = managerMap[agent['managerId']]
- else:
- manager = Manager.get_collection().find_one({'_id': ObjectId(agent['managerId'])},
- {'_id': 1, 'nickname': 1, 'username': 1, 'domain': 1})
- managerMap[agent['managerId']] = manager
- if manager['domain'] != settings.MY_DOMAIN:
- logger.debug('manager<id={},domain={}> not belong to me.'.format(manager['_id'], manager['domain']))
- continue
- item['manager'] = {
- 'id': manager.get('_id'),
- 'username': '******' if shadow else manager.get('username', ''),
- 'nickname': manager.get('nickname', '')
- }
- item['agent'] = {
- 'id': agent.get('_id'),
- 'username': '******' if shadow else agent.get('username', ''),
- 'nickname': agent.get('nickname', '')
- }
- item['dealer'] = {
- 'id': dealer.get('_id'),
- 'username': '******' if shadow else dealer.get('username', ''),
- 'nickname': dealer.get('nickname', '')
- }
- else:
- item['manager'] = {
- 'id': '',
- 'username': '',
- 'nickname': ''
- }
- item['agent'] = {
- 'id': '',
- 'username': '',
- 'nickname': ''
- }
- item['dealer'] = {
- 'id': '',
- 'username': '',
- 'nickname': ''
- }
- # 添加续费记录的相关信息
- from apps.web.dealer.models import DealerRechargeRecord
- DRRS = DealerRechargeRecord.objects.filter(dealerId = str(item['dealer']['id']), status = "Paid").order_by(
- '-finishedTime')
- item[u'chargeRecord'] = []
- for DRR in DRRS:
- for res in DRR.items:
- if res.get(u'devNo') == dev.devNo:
- res[u'orderNo'] = DRR.orderNo
- res[u'nickname'] = DRR.nickname
- res[u'finishedTime'] = DRR.finishedTime
- item[u'chargeRecord'].append(res)
- items.append(item)
- return total, items
- @staticmethod
- def accurate_filter(logicalCode, shadow):
- Agent = import_string('apps.web.agent.models.Agent')
- Dealer = import_string('apps.web.dealer.models.Dealer')
- Manager = import_string('apps.web.management.models.Manager')
- dev = Device.get_dev_by_logicalCode(logicalCode) # type: DeviceDict
- if not dev:
- return
- if dev.get("groupId"):
- group = Group.get_group(dev.get("groupId"))
- else:
- group = dict()
- item = {
- 'logicalCode': dev.logicalCode,
- 'devNo': dev.devNo,
- 'createdTime': dev['dateTimeAdded'],
- 'groupId': dev.groupId,
- 'groupName': group.get('groupName'),
- 'address': group.get('address'),
- 'online': dev.online,
- 'signal': dev.signal,
- 'lastOffTime': dev.offTime,
- 'simExpireDate': dev.fixedSimExpireDate,
- 'server': dev.server,
- 'devType': dev.devType,
- 'driverCode': dev.get('driverCode', ''),
- 'driverVersion': dev.get('driverVersion', ''),
- 'cycle': dev['cycle'],
- 'pulseInterval1': dev['pulseInterval1'],
- 'battery': dev['battery'],
- 'imsi': dev['imsi'],
- 'iccid': dev['iccid'],
- 'remarks': dev['remarks'],
- 'registered': dev.is_registered,
- 'softVer': dev['softVer'],
- 'coreVer': dev['coreVer'],
- 'hwVer': dev.hwVer,
- 'supportPG': dev.support_power_graph
- }
- if dev.get("ownerId"):
- try:
- dealer = Dealer.get_collection().find_one({'_id': ObjectId(dev['ownerId'])},
- {'_id': 1, 'nickname': 1, 'username': 1, "agentId": 1})
- agent = Agent.get_collection().find_one({'_id': ObjectId(dealer['agentId'])},
- {'_id': 1, 'username': 1, 'nickname': 1, "managerId": 1})
- manager = Manager.get_collection().find_one({'_id': ObjectId(agent['managerId'])},
- {'_id': 1, 'nickname': 1, 'username': 1, 'domain': 1})
- item['manager'] = {
- 'id': manager.get('_id'),
- 'username': manager.get('username', '') if shadow is False else '******',
- 'nickname': manager.get('nickname', '')
- }
- item['agent'] = {
- 'id': agent.get('_id'),
- 'username': agent.get('username', '') if shadow is False else '******',
- 'nickname': agent.get('nickname', '')
- }
- item['dealer'] = {
- 'id': dealer.get('_id'),
- 'username': dealer.get('username', '') if shadow is False else '******',
- 'nickname': dealer.get('nickname', '')
- }
- except Exception as e:
- item['manager'] = {
- 'id': '',
- 'username': '',
- 'nickname': ''
- }
- item['agent'] = {
- 'id': '',
- 'username': '',
- 'nickname': ''
- }
- item['dealer'] = {
- 'id': '',
- 'username': '',
- 'nickname': ''
- }
- else:
- item['manager'] = {
- 'id': '',
- 'username': '',
- 'nickname': ''
- }
- item['agent'] = {
- 'id': '',
- 'username': '',
- 'nickname': ''
- }
- item['dealer'] = {
- 'id': '',
- 'username': '',
- 'nickname': ''
- }
- # 添加续费记录的相关信息
- from apps.web.dealer.models import DealerRechargeRecord
- DRRS = DealerRechargeRecord.objects.filter(dealerId = str(item['dealer']['id']), status = "Paid").order_by(
- '-finishedTime')
- item[u'chargeRecord'] = []
- for DRR in DRRS:
- for res in DRR.items:
- if res.get('devNo') == dev.devNo:
- res[u'orderNo'] = DRR.orderNo
- res[u'nickname'] = DRR.nickname
- res[u'finishedTime'] = DRR.finishedTime
- item[u'chargeRecord'].append(res)
- return item
- @classmethod
- def update_field(cls, dev_no, update = False, **valueDict):
- try:
- cls.get_collection().update_one({'devNo': dev_no}, {'$set': valueDict})
- if update:
- cls.get_and_update_device_cache(dev_no, **valueDict)
- else:
- cls.invalid_device_cache(dev_no)
- except Exception as e:
- logger.exception('update dev error=%s' % e)
- return False
- return True
- def is_auto_refund(self):
- return self.autoRefundLeftMoney
- @staticmethod
- def get_dev_no_from_request(request):
- devNo = request.GET.get('devNo', None)
- if not devNo:
- logicalCode = request.GET.get('logicalCode', None)
- if logicalCode:
- devNo = Device.get_devNo_by_logicalCode(logicalCode)
- return devNo
- @staticmethod
- def update_port_control_cache(devNo, portInfo, updateType = 'update'):
- #: 两种方式update,以及overwrite
- oldValue = Device.get_dev_control_cache(devNo)
- port = str(portInfo['port'])
- if port in oldValue and updateType == 'update':
- oldValue[port].update(portInfo)
- else:
- oldValue[port] = portInfo
- Device.update_dev_control_cache(devNo, oldValue)
- return oldValue[port]
- @staticmethod
- def modify_port_control_cache(devNo, port, portInfo):
- key = device_control_cache_key(devNo)
- oldValue = Device.__mgr_cache.get(key)
- if oldValue is None:
- logger.debug('oh,memcached missed,devNo=%s' % devNo)
- oldValue = DeviceControlInfo.get(devNo)
- if not isinstance(oldValue, dict):
- logger.warning('control cache old value is not dict. value = {}'.format(oldValue))
- oldValue = None
- if not oldValue or str(port) not in oldValue:
- new_value = {str(port): portInfo}
- Device.__mgr_cache.set(key, new_value)
- DeviceControlInfo.set(devNo, new_value)
- else:
- oldValue[str(port)].update(portInfo)
- Device.__mgr_cache.set(key, oldValue)
- DeviceControlInfo.set(devNo, oldValue)
- @staticmethod
- def overwrite_port_control_cache(devNo, port, portInfo):
- key = device_control_cache_key(devNo)
- oldValue = Device.__mgr_cache.get(key)
- if oldValue is None:
- logger.debug('oh,memcached missed,devNo=%s' % devNo)
- oldValue = DeviceControlInfo.get(devNo)
- if not isinstance(oldValue, dict):
- logger.warning('control cache old value is not dict. value = {}'.format(oldValue))
- oldValue = None
- if not oldValue:
- new_value = {str(port): portInfo}
- Device.__mgr_cache.set(key, new_value)
- DeviceControlInfo.set(devNo, new_value)
- else:
- oldValue[str(port)] = portInfo
- Device.__mgr_cache.set(key, oldValue)
- DeviceControlInfo.set(devNo, oldValue)
- @classmethod
- def generate_sim_expire_query(cls, expire_start_date, expire_end_date,
- dealer_id = None, sim_source = None, sim_status = None):
- query = {'ownerId': dealer_id} if dealer_id else {'ownerId': {'$nin': [None, '']}}
- if expire_start_date and expire_end_date:
- query.update({
- '$or': [
- {
- 'simExpireDate': {
- '$lt': expire_end_date,
- '$gte': expire_start_date
- }
- },
- {
- 'expireDate': {
- '$lt': expire_end_date,
- '$gte': expire_start_date
- },
- 'simExpireDate': None
- },
- ]
- })
- elif expire_start_date:
- query.update({
- '$or': [
- {
- 'simExpireDate': {
- '$gte': expire_start_date
- }
- },
- {
- 'expireDate': {
- '$gte': expire_start_date
- },
- 'simExpireDate': None
- },
- ]
- })
- elif expire_end_date:
- query.update({
- '$or': [
- {
- 'simExpireDate': {
- '$lt': expire_end_date
- }
- },
- {
- 'expireDate': {
- '$lt': expire_end_date
- },
- 'simExpireDate': None
- },
- ]
- })
- query.update({
- 'logicalCode': {'$regex': '^[^B]'},
- })
- if sim_source:
- query.update({'simSource': sim_source})
- if sim_status:
- query.update({'simStatus': {'$in': [sim_status, None]}})
- return query
- @classmethod
- def check_sim_expire_notify(cls, device):
- # type: (Optional[Device, DeviceDict])->bool
- if not device.fixedSimExpireDate:
- return False
- if device.simStatus != SimStatus.Updated:
- return False
- now = arrow.now()
- first_day = now.replace(day = 1, hour = 0, minute = 0, second = 0, microsecond = 0) # type: arrow
- last_day = first_day.shift(months = 1).shift(days = -1) # type: arrow
- if device.fixedSimExpireDate >= first_day.naive:
- return True
- else:
- return False
- @property
- def sim_expire_notify(self):
- return self.check_sim_expire_notify(self)
- def set_fault(self):
- updated = self.update(isFault = True)
- assert updated, 'set %r fault failed' % (self,)
- Device.invalid_device_cache(self.devNo)
- @property
- def cached(self):
- return Device.get_dev(self.devNo)
- @staticmethod
- # 计算设备的使用率
- def calc_dev_usage(devNo):
- ctrInfo = Device.get_dev_control_cache(devNo)
- usage = 0
- if ctrInfo is not None and ctrInfo:
- portCount, busyCount = 0, 0
- for k, v in ctrInfo.items():
- if str(k).isdigit():
- portCount += 1
- if v.has_key('status') and v['status'] == Const.DEV_WORK_STATUS_WORKING:
- busyCount += 1
- else:
- continue
- if portCount:
- usage = float(busyCount) / portCount * 100.0
- else:
- serviceInfo = Device.get_dev_control_cache(devNo)
- if serviceInfo is not None and serviceInfo.has_key('status') and serviceInfo[
- 'status'] == Const.DEV_WORK_STATUS_WORKING:
- if not serviceInfo.has_key('finishedTime'):
- return 0
- if time.time() > serviceInfo['finishedTime']:
- return 0
- return 100.0
- return float(usage)
- @classmethod
- def invalid_all_cache(cls, device):
- # type:(Optional[DeviceDict, Device])->None
- cls.__base_cache_mgr.delete_device_cache(device.devNo)
- cls.__base_cache_mgr.delete_l_cache(device.logicalCode)
- cls.invalid_group_device_list_cache([device.groupId])
- cls.invalid_device_control_cache(device.devNo)
- @classmethod
- def replace(cls, old_lc, new_lc, operator):
- # type:(str, str, UserSearchable)->None
- old_device = Device.objects(logicalCode = old_lc).first() # type: Optional[Device]
- new_device = Device.objects(logicalCode = new_lc).first() # type: Optional[Device]
- if not old_device:
- raise UserServerException(u'旧设备({})不存在'.format(old_lc))
- if not new_device:
- raise UserServerException(u'新设备({})不存在'.format(new_lc))
- if (old_device.ownerId != new_device.ownerId) and new_device.ownerId:
- raise UserServerException(u'设备注册经销商不一致,不允许替换')
- record = DeviceReplacement(
- oldLogicalCode = old_lc,
- newLogicalCode = new_lc,
- oldDevice = dict(old_device.to_mongo()),
- newDevice = dict(new_device.to_mongo()),
- replaceType = 'replace'
- ).save()
- OperatorLog.log(user = operator,
- level = OperatorLog.LogLevel.CRITICAL,
- operator_name = u'换绑设备',
- content = {
- 'ref_id': record.id
- })
- try:
- old_device.delete()
- update_dict = {
- 'logicalCode': old_device.logicalCode,
- 'ownerId': old_device.ownerId,
- 'groupId': old_device.groupId,
- 'districtId': old_device.districtId,
- 'groupNumber': old_device.groupNumber,
- 'washConfig': old_device.washConfig,
- 'tempWashConfig': old_device.tempWashConfig,
- 'remarks': old_device.remarks,
- 'instructions': old_device.instructions,
- 'isFault': old_device.isFault,
- 'autoRefundLeftMoney': old_device.autoRefundLeftMoney,
- 'devType': old_device.devType,
- 'dateTimeUpdated': datetime.datetime.now(),
- 'iccidHistory': old_device.iccidHistory,
- 'otherConf': old_device.otherConf,
- 'registerLog': old_device.registerLog,
- 'serviceState': old_device.serviceState,
- 'trafficCardCost': old_device.trafficCardCost,
- 'stockDetailDict': old_device.stockDetailDict
- }
- if old_device.location:
- update_dict['location'] = old_device.location
- updated = new_device.update(**update_dict)
- if not updated:
- raise UserServerException(u'未更新成功,请重试')
- finally:
- Device.invalid_all_cache(old_device)
- Device.invalid_all_cache(new_device)
- @classmethod
- def swap(cls, left_lc, right_lc, operator):
- # type:(str,str,UserSearchable)->None
- left_device = Device.objects(logicalCode = left_lc).first() # type: Optional[Device]
- right_device = Device.objects(logicalCode = right_lc).first() # type: Optional[Device]
- if not left_device:
- raise UserServerException(u'设备({})不存在'.format(left_lc))
- if not right_device:
- raise UserServerException(u'设备({})不存在'.format(right_lc))
- if left_device.ownerId != right_device.ownerId:
- raise UserServerException(u'不同经销商设备不能交换二维码')
- raw_left_device = dict(left_device.to_mongo()) # type: Dict
- raw_right_device = dict(right_device.to_mongo()) # type: Dict
- record = DeviceReplacement(
- oldLogicalCode = left_lc,
- newLogicalCode = right_lc,
- oldDevice = raw_left_device,
- newDevice = raw_right_device,
- replaceType = 'swap'
- ).save()
- OperatorLog.log(user = operator,
- level = OperatorLog.LogLevel.CRITICAL,
- operator_name = u'互换设备',
- content = {
- 'ref_id': record.id
- })
- try:
- map(lambda _: _.delete(), [left_device, right_device])
- raw_left_device['logicalCode'] = right_lc
- Device(**raw_left_device).save()
- raw_right_device['logicalCode'] = left_lc
- Device(**raw_right_device).save()
- finally:
- Device.invalid_all_cache(left_device)
- Device.invalid_all_cache(right_device)
- @classmethod
- def rollback_replacement(cls, replacement_id):
- replacement = DeviceReplacement.objects(id = replacement_id).first() # type: Optional[DeviceReplacement]
- if not replacement:
- raise Exception(u'无此调换记录')
- raw_old_device = replacement.oldDevice # type: dict
- raw_new_device = replacement.newDevice # type: dict
- devices = Device.objects(devNo__in = [raw_old_device['devNo'], raw_new_device['devNo']])
- map(lambda _: _.delete(), devices)
- old_device = Device(**raw_old_device).save()
- new_device = Device(**raw_new_device).save()
- updated = replacement.update(revokedTime = datetime.datetime.now())
- if not updated:
- logger.error('cannot update %r' % (replacement,))
- Device.invalid_all_cache(old_device)
- Device.invalid_all_cache(new_device)
- @classmethod
- def bind(cls, devNo, logicalCode, operator = None):
- # type:(str, str, UserSearchable)->None
- document = {
- 'logicalCode': logicalCode,
- 'devNo': devNo,
- 'dateTimeBinded': datetime.datetime.now(),
- 'binder': operator.identity_id if operator else ''
- }
- try:
- Device.get_collection().insert_one(copy.deepcopy(document))
- except DuplicateKeyError:
- result = Device.get_collection().update_one(
- filter = {'devNo': devNo, 'logicalCode': {'$in': [None, '']}},
- update = {'$set': document},
- upsert = False)
- if result.matched_count <= 0:
- raise UserServerException(u'IMEI({})已经绑定'.format(devNo))
- elif result.modified_count <= 0:
- raise UserServerException(u'绑定失败,请重试')
- Device.__base_cache_mgr.update_l_cache(devNo, logicalCode)
- Device.get_dev(devNo)
- try:
- CheckDevice.get_collection().update_one({'imei': devNo},
- {'$set':
- {
- 'imei': devNo,
- 'logicalCode': logicalCode,
- 'bindTime': datetime.datetime.now()
- }
- },
- upsert = True)
- except Exception, e:
- logger.exception(e)
- @classmethod
- def unbind(cls, dev, operator = None):
- # type: (DeviceDict, UserSearchable)->None
- if not dev:
- raise UserServerException(u'该设备不存在,无须解绑')
- if dev.is_registered:
- raise UserServerException(u'设备已经注册,无法解绑')
- device = dev.my_obj # type: Device
- if not device:
- raise UserServerException(u'该设备不存在,无须解绑')
- if operator:
- if operator.identity_id != device.binder:
- raise UserServerException(u'不是您绑定的设备,您无法进行解绑定')
- device.delete()
- Device.invalid_all_cache(dev)
- try:
- CheckDevice.get_collection().delete_one({'imei': dev.devNo})
- except:
- pass
- @classmethod
- def get_sim_expire_notify_devices(cls, dealer_id = None, extra_filter = None,
- fields = {'_id': 0, 'logicalCode': 1, 'ownerId': 1}):
- now = arrow.now()
- this_month_first_day = now.replace(day = 1, hour = 0, minute = 0, second = 0, microsecond = 0) # type: arrow
- next_month_first_day = this_month_first_day.shift(months = 1) # type: arrow
- query = cls.generate_sim_expire_query(expire_start_date = this_month_first_day.naive,
- expire_end_date = next_month_first_day.naive,
- dealer_id = dealer_id,
- sim_status = SimStatus.Updated)
- if extra_filter:
- query.update(extra_filter)
- devices = Device.get_collection().find(query, fields)
- return list(devices)
- @classmethod
- def set_debug_flag(cls, devNo, flag = ''):
- Device.get_collection().update({'devNo': devNo}, {'$set': {'debug': flag}}, upsert = False)
- Device.invalid_device_cache(devNo)
- @staticmethod
- def bolai_get_node_dev(cls, gatewayDevNo, nodeIndex):
- devObj = Device.objects.get(devNo = gatewayDevNo)
- nodeDevNo = devObj.nodeDict.get(nodeIndex, None)
- if not nodeDevNo:
- return None
- devObj = Device.objects.get(devNo = nodeDevNo)
- return devObj
- @classmethod
- def switch_api_mode(cls, logicalCode, isApi):
- # type:(Union[str, unicode, list], bool) -> bool
- if isinstance(logicalCode, list):
- logicalCodes = logicalCode
- elif isinstance(logicalCode, (str, unicode)):
- logicalCodes = [logicalCode]
- else:
- return
- if not logicalCodes:
- return
- devs = Device.objects.filter(logicalCode__in=logicalCodes)
- if devs:
- result = devs.update(isApi=isApi)
- Device.invalid_many_device_cache(map(lambda _: _.devNo, devs))
- return result
- @classmethod
- def check_and_update_tcpip_info(cls,dev,devPort,serverIp,serverPort):
- if not dev.network_address:
- devObj = Device.objects.get(devNo = dev['devNo'])
- devObj.otherConf['devPort'] = devPort
- devObj.server = serverIp + ':' + str(serverPort)
- devObj.save()
- Device.invalid_device_cache(dev['devNo'])
-
- oldServer,oldPort,oldLabel = dev.network_address
-
- if 'devPort' not in dev.otherConf or dev.otherConf['devPort'] != devPort or oldLabel != 'car-tcp-ip' or oldServer != serverIp or oldPort != serverPort:
- devObj = Device.objects.get(devNo = dev['devNo'])
- devObj.otherConf['devPort'] = devPort
- devObj.server = serverIp + ':' + str(serverPort)
- devObj.save()
- Device.invalid_device_cache(dev['devNo'])
- @property
- def owner(self):
- # type:()->Dealer
- if hasattr(self, '__owner__'):
- return getattr(self, '__owner__')
- if not self.ownerId:
- return None
- Dealer = import_string('apps.web.dealer.models.Dealer')
- dealer = Dealer.objects(id = self.ownerId).first()
- if dealer:
- setattr(self, '__owner__', dealer)
- return dealer
- @owner.setter
- def owner(self, value):
- setattr(self, '__owner__', value)
- class DeviceDict(dict):
- """
- 设备的缓存表示. 注意不能直接當作字典進行json編碼
- """
- @property
- def id(self):
- if "id" not in self.v:
- Device.invalid_device_cache(self.devNo)
- _id = Device.get_dev(self.devNo).get("id")
- else:
- _id = self["id"]
- return _id
- @property
- def cycle(self):
- return self['cycle']
- @property
- def majorDeviceType(self):
- return self['majorDeviceType']
- @property
- def status(self):
- return self['status']
- @property
- def need_fetch_online(self):
- if self.online == DeviceOnlineStatus.DEV_STATUS_ONLINE:
- return True
- # 如果离线,但是在2个小时内有上线记录,也需要去检查下状态
- if self.lastUpdateOnlineTime > 0:
- elapse_time = (long(time.time() * 1000) - long(self['updateTime']))
- if elapse_time < 2 * 60 * 60 * 1000:
- return True
- return False
- @property
- def statusInfo(self):
- return self['statusInfo']
- @property
- def online(self):
- return self['online']
- @property
- def offTime(self):
- # type: ()->long
- return self['offTime']
- @property
- def lastUpdateOnlineTime(self):
- # type: ()->long
- return self['updateTime']
- @property
- def signal(self):
- # type: ()->int
- return self['signal']
- @property
- def devNo(self):
- return self['devNo']
- @property
- def logicalCode(self):
- return self['logicalCode']
- @property
- def groupId(self):
- return self.get('groupId', Device.groupId.default)
- @property
- def group(self): # type:() -> GroupDict
- if hasattr(self, '__group__'):
- return getattr(self, '__group__')
- group = Group.get_group(self.groupId)
- if group:
- setattr(self, '__group__', group)
- return group
- @property
- def is_registered(self):
- # type:()->bool
- return Device.utils_is_registered(self)
- @property
- def is_expired(self):
- # type:()->bool
- return Device.utils_is_expired(self)
- @property
- def is_to_expired(self):
- expire_date = self.fixedSimExpireDate
- if not expire_date:
- return False
- now = arrow.now()
- start_date = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0).naive
- end_date = now.replace(day=(Const.SIM_CARD_FORBIDDEN_DAY + 1), hour=0, minute=0, second=0,
- microsecond=0).naive
- if (expire_date > start_date) and (expire_date < end_date):
- return True
- else:
- return False
- @property
- def channelType(self):
- return Device.utils_channel_type(self)
- @property
- def coreVer(self):
- return self.get('coreVer', '')
- @property
- def softVer(self):
- return self.get('softVer', '')
- @property
- def mf(self):
- return self.get('mf', '')
- @property
- def ownerId(self):
- return self.get('ownerId', Device.ownerId.default)
- @property
- def simExpireDate(self):
- sim_expire_date = self.get('simExpireDate', Device.simExpireDate.default)
- if not sim_expire_date:
- return sim_expire_date
- if isinstance(sim_expire_date, basestring):
- return datetime.datetime.strptime(sim_expire_date, Const.DATE_FMT)
- else:
- return sim_expire_date
- @property
- def formatSimExpireDate(self):
- # type: ()->basestring
- if Device.utils_is_bluetooth(self.logicalCode):
- return '-'
- expire_date = self.fixedSimExpireDate
- if expire_date:
- return expire_date.strftime(Const.DATE_FMT)
- else:
- return u'待更新'
- @property
- def expireDate(self):
- return self.get('expireDate', Device.expireDate.default)
- @property
- def sim_expire_notify(self):
- return Device.check_sim_expire_notify(self)
- @property
- def fixedSimExpireDate(self):
- return Device.get_sim_expire_date(self)
- @property
- def simStatus(self):
- return self.get('simStatus', SimStatus.Updated)
- @property
- def devType(self):
- # type: ()->Dict
- return self.get('devType', {})
- @property
- def devTypeId(self):
- return self.devType.get('id')
- @property
- def devTypeName(self):
- return self.devType.get('name')
- @property
- def devTypeCode(self):
- # type: ()->str
- return self.devType.get('code')
- @property
- def devTypeFeatures(self):
- return self.devType.get('features', {})
- @property
- def is_online_type(self):
- # type: ()->bool
- return self.devType.get('online', None)
- @property
- def hwVer(self):
- return self.get('hwVer', '')
- @property
- def iccid(self):
- return self.get('iccid', '')
- @property
- def imsi(self):
- return self.get('imsi', '')
- @property
- def server(self):
- return self.get('server', Device.server.default)
- @property
- def network_address(self):
- host, port = self.server.split(':')
- host = SysParas.get_private_ip(str(host))
- if int(port) < 30000:
- return host, port, 'mqtt'
- elif int(port) < 50000:
- return host, port, 'tcpip'
- else:
- return host, port, 'car-tcp-ip'
- @property
- def lbs(self):
- return self['lbs']
- @property
- def lat(self):
- return self['lat']
- @property
- def lng(self):
- return self['lng']
- @property
- def debug(self):
- return self.get('debug', '')
- @property
- def groupNumber(self):
- return self.get('groupNumber', '')
- @property
- def otherConf(self):
- return self.get('otherConf', {})
- @property
- def support_reliable(self):
- tokens = self.driverVersion.split('.')
- if tokens[0] >= 'v5':
- if 'start_device_realiable' in self.deviceAdapter.__class__.__dict__:
- return True
- else:
- return False
- else:
- return False
- @property
- def support_sid_topic(self):
- try:
- tokens = self.softVer.split('.')
- if len(tokens) == 3:
- mainVersion = int(str(tokens[0]).replace("v", ""))
- if 7 <= mainVersion < 40:
- logger.debug('version is: {}; sidTopic = False'.format(self.softVer))
- return False
- if int(tokens[2]) >= int(Const.TOPIC_WITH_SID_VERSION):
- logger.debug('version is: {}; sidTopic = True'.format(self.softVer))
- return True
- logger.debug('version is: {}; sidTopic = False'.format(self.softVer))
- return False
- except Exception as e:
- logger.debug('exception. version is: {}; sidTopic = False'.format(self.softVer))
- logger.exception(e)
- return False
- @property
- def ban(self):
- return self.get('disableDevice', False)
- @property
- def driverCode(self):
- return self.get('driverCode', '000000')
- @property
- def driverVersion(self):
- return self.get('driverVersion', '0.0.0')
- @property
- def support_power_graph(self):
- return self.get('otherConf', dict()).get('supportPG', False)
- @property
- def is_auto_refund(self):
- try:
- return self.my_obj.is_auto_refund()
- except Exception as e:
- logger.exception(e)
- return False
- @property
- def is_DND_now(self):
- if self.get('isDND', False) is False:
- return False
- DNDRange = self.get('isDNDTimeInterval', [])
- nowTime = datetime.datetime.now().strftime('%H:%M:%S')
- for _ in DNDRange:
- if _.get('isDNDStartTime') <= nowTime <= _.get('isDNDEndTime'):
- return True
- return False
- @property
- def is_fault(self):
- return self["isFault"]
- @property
- def is_warning(self):
- return self["deviceWarning"]
- @property
- def isRent(self):
- return self.get("isRent", False)
- @property
- def isApi(self):
- return self.get("isApi")
- @property
- def disableADExpireDate(self):
- return self.get("disableADExpireDate")
- @property
- def bill_as_service_feature(self):
- # type:()-> BillAsServiceFeature
- return BillAsServiceFeature(self.devTypeFeatures.get('billAsService', {}))
- @property
- def policyTemp(self):
- return self.get("policyTemp", {})
- @property
- def priceDescription(self):
- if self.get('priceDescription'):
- priceDescription = self['priceDescription']
- priceDescription = priceDescription.replace('\n', '<br>')
- priceDescription = priceDescription.replace(' ', ' ')
- return priceDescription
- elif self.policyTemp and not self.get('priceDescription'):
- forApps = self.policyTemp.get('forApps', {})
- policyType = forApps.get('policyType')
- if policyType == 'time':
- prices = forApps.get('rule', {}).get('prices', [])
- text = '计费模式: 按功率计费' + '<br>'
- lastStep = 0
- for price in prices:
- text += '<b>{}</b>-<b>{}</b>瓦, <b>{}</b>元/小时 <br>'.format(lastStep, price['power'], price['price'])
- lastStep = price['power']
- return text
- elif policyType == 'elec':
- price = forApps.get('rule', {}).get('price')
- text = '计费模式: 按电量计费' + '<br>'
- if price:
- text += '单价: <b>{}</b>元/度 <br>'.format(price)
- return text
- else:
- # 保留一个按次计费
- pass
- else:
- pass
- @property
- def identity_info(self):
- return {
- 'devNo': self.devNo,
- 'logicalCode': self.logicalCode,
- 'devTypeName': self.devTypeName,
- 'devTypeCode': self.devTypeCode,
- 'groupId': self.groupId,
- 'groupName': self.group.groupName,
- 'groupNumber': self.groupNumber,
- 'address': self.group.address
- }
- @cached_property
- def deviceAdapter(self): # type:()->SmartBox
- return ActionDeviceBuilder.create_action_device(self)
- @cached_property
- def eventer(self): # type: ()->EventBuilder
- return ActionDeviceBuilder.create_eventer_by_adapter(self.deviceAdapter)
- @cached_property
- def parts(self):
- return Part.objects.filter(logicalCode=self.logicalCode)
- @cached_property
- def owner(self): # type:()->Dealer
- cls = import_string('apps.web.dealer.models.Dealer')
- dealer = cls.objects(id=self.ownerId).first()
- return dealer
- @cached_property
- def my_obj(self): # type:() -> Device
- return Device.objects(devNo=self.devNo).first()
- @cached_property
- def dealer(self): # type:() -> DealerDict
- cls = import_string('apps.web.dealer.models.Dealer')
- dealer = cls.get_dealer(self.ownerId)
- return dealer
- @property
- def v(self):
- return dict(self)
- def __repr__(self):
- return 'DeviceDict<logicalCode={} devNo={}>'.format(self.logicalCode, self.devNo)
- def __update_status(self):
- Device.get_device_status_cache(self)
- def __getitem__(self, k):
- if k in self:
- return super(DeviceDict, self).__getitem__(k)
- if k in ['online', 'status', 'signal', 'offTime', 'statusInfo', 'updateTime', 'offTime', 'deviceWarning']:
- assert 'logicalCode' in self, 'must has logicalCode field'
- self.__update_status()
- elif k == 'majorDeviceType':
- self['majorDeviceType'] = Device.utils_major_type(self)
- elif k in ['lbs', 'lat', 'lng']:
- location = self.get('location', None)
- lbs = True
- if not location:
- lat = 360
- lng = 360
- lbs = False
- else:
- try:
- lat = location['coordinates'][1]
- except (KeyError, IndexError):
- lat = 360
- lbs = False
- try:
- lng = location['coordinates'][0]
- except (KeyError, IndexError):
- lng = 360
- lbs = False
- self.update({'lbs': lbs, 'lat': lat, 'lng': lng})
- return super(DeviceDict, self).__getitem__(k)
- def set_online(self, signal=None):
- """
- 设置设备在线,填充updateTime
- 设置设备离线,填充offTime
- :param signal:
- :return:
- """
- new_online_info = Device.update_online_cache(self.devNo, DeviceOnlineStatus.DEV_STATUS_ONLINE, signal)
- self.update(new_online_info)
- def set_offline(self):
- new_online_info = Device.update_online_cache(self.devNo, DeviceOnlineStatus.DEV_STATUS_OFFLINE)
- self.update(new_online_info)
- def is_authorized_to_dealer(self, dealer_id):
- return self.ownerId == dealer_id
- def package(self, packageId, isTemporary=False):
- if isTemporary:
- washConfig = self.get('tempWashConfig', {})
- else:
- washConfig = self.get('washConfig', {})
- package = washConfig.get(packageId)
- if package:
- package['packageId'] = packageId
- package['isTemporary'] = isTemporary
- return package
- def update_device_obj(self, **kwargs):
- if len(kwargs.keys()) <= 0:
- return
- Device.get_collection().update_one({
- 'devNo': self.devNo
- }, {
- '$set': kwargs
- })
- Device.invalid_device_cache(self.devNo)
- try:
- delattr(self, '__my_obj__')
- except Exception as e:
- pass
- def update_other_conf(self, **kwargs):
- _set = {}
- for key, value in kwargs.iteritems():
- _set['otherConf.{}'.format(key)] = value
- self.update_device_obj(**_set)
- def get_other_conf_item(self, item_name, default=None):
- return self.my_obj.otherConf.get(item_name, default)
- def support_dev_type_features(self, feature_name):
- return self.devTypeFeatures.get(feature_name, False)
- def is_port_can_use(self, port):
- # TODO 追加是否能够续充的特性
- canAdd = self.support_dev_type_features("canAdd")
- return self.deviceAdapter.is_port_can_use(port, canAdd)
- class FeedBack(Searchable):
- ownerId = StringField(verbose_name = u"所有者", default = "")
- openId = StringField(verbose_name = u"微信ID", default = "")
- nickname = StringField(verbose_name = u"名称", max_length = 255, default = "")
- description = StringField(verbose_name = u"投诉内容", max_length = 255, default = "")
- status = IntField(verbose_name = u"处理状态", default = Const.FeedBackResult.UNTREATED) # 为0:未处理,1:已处理,2:驳回
- feedType = StringField(verbose_name = u"反馈类型(故障,订单投诉)", default = "refund")
- createTime = StringField(verbose_name = u"创建时间",
- default = lambda: datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
- dealTime = StringField(verbose_name = u"处理时间", default = "")
- phone = StringField(verbose_name = u"联系电话", default = "")
- devTypeName = StringField(verbose_name = u"设备类型", default = "")
- dealerRemark = StringField(verbose_name = u"经销商回复", default = "")
- imgList = ListField(verbose_name = u'图片列表(往往作用户说明作用)', default = [])
- dealerImgList = ListField(verbose_name = u'经销商回复图片', default = [])
- isRead = BooleanField(verbose_name = u'消息已读', default = False)
- detailInfo = DictField(verbose_name = u'各投诉类型详细信息', default = None)
- devNo = StringField(verbose_name = u"设备编号", default = None)
- logicalCode = StringField(verbose_name = u"逻辑编码", default = None)
- groupId = StringField(verbose_name = u"逻辑编码", default = None)
- groupNumber = StringField(verbose_name = u"设备组内编号", default = None)
- groupName = StringField(verbose_name = u"设备组内编号", default = None)
- address = StringField(verbose_name = u"设备组内编号", default = None)
- consumeRecordOrderNo = StringField(default = None)
- coins = VirtualCoinField(verbose_name = u"操作数目,比如退几个币", default = None)
- resultDesc = StringField(verbose_name = u"处理描述", default = None)
- meta = {"collection": "FeedBacks", "db_alias": "logdata"}
- search_fields = (
- 'nickname', 'description', 'detailInfo.logicalCode', 'detailInfo.groupNumber', 'detailInfo.groupName')
- @property
- def detail(self):
- rv = {
- 'ownerId': self.ownerId,
- 'nickname': self.nickname,
- 'description': self.description,
- 'status': self.status,
- 'feedType': self.feed_type,
- 'createTime': self.createTime,
- 'dealTime': self.dealTime,
- 'phone': self.phone,
- 'dealerRemark': self.dealerRemark,
- 'imgList': self.imgList,
- 'dealerImgList': self.dealerImgList,
- 'isRead': self.isRead,
- 'detailInfo': {}
- }
- if self.openId:
- rv['openId'] = self.openId
- if self.detailInfo:
- rv['detailInfo'].update(self.detailInfo)
- else:
- if self.consumeRecordOrderNo:
- rv['detailInfo'].update({
- 'orderNo': self.consumeRecordOrderNo
- })
- if 'orderNo' in rv['detailInfo']:
- order_no = rv['detailInfo'].get('orderNo')
- if order_no:
- from apps.web.user.models import ConsumeRecord
- order = ConsumeRecord.objects.filter(ownerId=self.ownerId, orderNo = order_no).first() # type: ConsumeRecord
- rv['detailInfo'].update(order.info_for_feedback)
- if 'coins' not in rv['detailInfo'] and self.coins:
- rv['detailInfo']['coins'] = self.coins
- if self.logicalCode:
- rv['detailInfo'].update({
- 'logicalCode': self.logicalCode,
- 'devTypeName': self.devTypeName,
- 'groupNumber': self.groupNumber,
- 'groupName': self.groupName,
- 'address': self.address,
- })
- rv['detailInfo'].pop('devNo', None)
- rv['detailInfo'].pop('devTypeCode', None)
- return rv
- @property
- def feed_type(self):
- if self.consumeRecordOrderNo:
- return 'netpay'
- if self.feedType in ['refund', 'upper']:
- return 'other'
- else:
- return self.feedType
- @property
- def summary(self):
- rv = {
- 'id': str(self.id),
- 'nickname': self.nickname,
- 'feedType': self.feed_type,
- 'status': self.status,
- 'description': self.description,
- 'dealerRemark': self.dealerRemark,
- 'createTime': self.createTime,
- 'detailInfo': {}
- }
- if self.logicalCode:
- rv['detailInfo'].update({
- 'logicalCode': self.logicalCode,
- 'devTypeName': self.devTypeName,
- 'groupName': self.groupName
- })
- elif self.detailInfo and 'logicalCode' in self.detailInfo:
- rv['detailInfo'].update({
- 'logicalCode': self.detailInfo.get('logicalCode'),
- 'devTypeName': self.detailInfo.get('devTypeName'),
- 'groupName': self.detailInfo.get('groupName')
- })
- return rv
- @classmethod
- def get_unhandled_count(cls, **kwargs): # type:(Dict[str, Any])->int
- return cls.objects(status = Const.FeedBackResult.UNTREATED, **kwargs).count()
- @property
- def message_type(self):
- # type: ()->basestring
- mapping = {
- 'fault': u'设备故障',
- 'refund': u'退币申请',
- 'upper': u'申请上分'
- }
- return mapping.get(self.feedType, u'报告老板')
- def set_handled(self, **kwargs):
- return self.update(status = Const.FeedBackResult.TREATED, isRead = False, **kwargs)
- def set_rejected(self, **kwargs):
- return self.update(status = Const.FeedBackResult.REJECTED, isRead = False, **kwargs)
- def handle(self, action, **kwargs):
- if action == 'reject':
- self.set_rejected(**kwargs)
- else:
- self.set_handled(**kwargs)
- @property
- def my_logicalCode(self):
- if self.detailInfo and 'logicalCode' in self.detailInfo:
- return self.detailInfo['logicalCode']
- else:
- return self.logicalCode
- @property
- def my_group_id(self):
- if self.groupId:
- return self.groupId
- else:
- if self.detailInfo:
- return self.detailInfo.get('groupId', None)
- else:
- return None
- class GroupDict(dict):
- """
- 组的缓存表示
- """
- def __repr__(self):
- return '<GroupDict id=%s>' % (self.get('groupId', 'unknown'),)
- @property
- def v(self):
- return dict(self)
- @property
- def ownerId(self):
- return self['ownerId']
- @property
- def owner(self):
- # type:()->Dealer
- if hasattr(self, '__owner__'):
- return getattr(self, '__owner__')
- Dealer = import_string('apps.web.dealer.models.Dealer')
- dealer = Dealer.objects(id=self.ownerId).first()
- if dealer:
- setattr(self, '__owner__', dealer)
- return dealer
- @property
- def object(self): # type() -> Group
- group = getattr(self, '__object__', None)
- if not group:
- group = Group.objects.get(id=self.id)
- setattr(self, '__object__', group)
- return group
- @property
- def id(self):
- return ObjectId(self['groupId'])
- @property
- def groupId(self):
- return self['groupId']
- @property
- def groupName(self):
- return self.get('groupName')
- @property
- def address(self):
- return self.get('address', '')
- @property
- def partners(self):
- return self.partnersDict.values()
-
- @property
- def otherConf(self):
- return self.get("otherConf", dict())
- @property
- def elecFee(self):
- return RMB(self.otherConf.get("elecFee", 0))
-
- @property
- def partnersDict(self):
- return self.get("partnerDict", {})
- @property
- def ruleDict(self): # type:() -> dict
- return self.get("ruleDict", dict())
- def rule_is_accepted(self, ruleId): # type:(str) -> bool
- return ruleId in self.ruleDict
- def get_accepted_rule(self, ruleId): # type:(str) -> str
- return self.ruleDict.get("ruleId")
- @property
- def occupied_numbers(self):
- # type: ()->Set[str]
- return set(
- [
- _['groupNumber'] for _ in Device.get_collection().find(
- {'groupId': self.get('groupId')}, {'groupNumber': 1, '_id': 0})
- ]
- )
- @property
- def is_free(self):
- return self.get('isFree', False)
- @property
- def card_rule_list(self):
- rule_list = []
- if not self.get("cardRuleDict"):
- Dealer = import_string('apps.web.dealer.models.Dealer')
- dealer = Dealer.objects.get(id = self.ownerId)
- card_rule_dict = dealer.format_card_discount
- else:
- card_rule_dict = self.get("cardRuleDict")
- for k, v in card_rule_dict.items():
- rule_list.append({'payAmount': k, 'coins': v})
- return rule_list
- @property
- def recharge_rule_list(self):
- ruleDict = self.get('ruleDict', {})
- res = [
- {
- "id": ruleId,
- "payAmount": float(ruleId),
- "coins": float(coins),
- } for ruleId, coins in ruleDict.items()
- ]
- # 优惠充值界面套餐排序(根据金币)升序显示
- res = sorted(res, key = lambda x: x['coins'])
- return res
- @property
- def currencyGroup(self):
- if 'currencyGroup' not in self:
- Group.CacheMgr.invalid_group_cache([self.groupId])
- group = Group.get_group(self.groupId) # type: GroupDict
- self.update(group.v)
- return self.get('currencyGroup')
- @property
- def identity_info(self):
- return {
- 'groupId': self.groupId,
- 'groupName': self.groupName,
- 'address': self.address
- }
- @property
- def popPriceDescriptionButton(self):
- return self.get('popPriceDescriptionButton', False)
- @property
- def totalShare(self): # type:() -> Percent
- return sum([Percent(_['percent']) for _ in self.partners if _.get("isActive")], Percent(0))
- @property
- def hasPayElecFee(self):
- return bool(filter(lambda x: x.get("payElecFee"), self.partners))
- def remove_partner(self, partnerId):
- """
- 组内移除合伙人
- """
- self.partnersDict.pop(partnerId, None)
- result = self.object.update(partnerList=self.partnersDict.values())
- self.object.invalid_group_cache([str(self.id)])
- self.object.__class__.CacheMgr.invalid_group_ids_of_partner_cache(partnerId)
- return result
- def update_partner(self, partnerId, ratio, payElecFee, isActive):
- """
- 更新合伙人信息
- """
- totalShare = self.totalShare
- curShare = Percent(self.partnersDict.get(partnerId, dict()).get("percent", 0))
- # 地址组的参数校验
- if totalShare - curShare + Percent(ratio) > Percent(100):
- raise ValueError("分成比例设置错误")
- if payElecFee and self.hasPayElecFee:
- raise ValueError("该地址已有电费承担方,请勿重复设置")
- partnersDict = self.partnersDict
- if partnerId in partnersDict:
- partnersDict[partnerId].update({
- 'percent': ratio,
- 'id': partnerId,
- 'payElecFee': payElecFee,
- 'isActive': isActive
- })
- else:
- partnersDict[partnerId] = {
- 'percent': ratio,
- 'id': partnerId,
- 'payElecFee': payElecFee,
- 'isActive': isActive
- }
- result = self.object.update(partnerList=partnersDict.values())
- self.object.__class__.CacheMgr.invalid_group_ids_of_partner_cache(partnerId)
- self.object.invalid_group_cache([str(self.id)])
- return result
- class RequestBodyDict(dict):
- def __init__(self, *args, **kwargs):
- dict.__init__(self, *args, **kwargs)
- self.__dict__ = self
- def __repr__(self):
- return '<RequestBodyDict>'
- class CheckDevice(Searchable):
- logicalCode = StringField(verbose_name = u'设备逻辑码')
- imei = StringField(verbose_name = u'设备电子标签', unique = True)
- testTime = DateTimeField(verbose_name = u'开始测试时间')
- testResult = IntField(verbose_name = u'测试结果', default = 0)
- testResultDesc = StringField(verbose_name = u'测试结果描述', default = '')
- bindTime = DateTimeField(verbose_name = u'绑定时间')
- label = StringField(verbose_name = u'设备标记', default = '')
- checkSuit = DictField(verbose_name = u'测试套件', default = {})
- # 生产是先上线测试, 在挑一个模块测试, 到客户那里一些关键信息没有, 先记录下来
- server = StringField(verbose_name = "server")
- imsi = StringField(default = '', verbose_name = 'imsi')
- iccid = StringField(default = '', verbose_name = 'iccid')
- softVer = StringField(verbose_name = "软件版本", default = "")
- mf = StringField(verbose_name = "固件版本", default = "")
- coreVer = StringField(default = '', verbose_name = u'核心版本')
- driverCode = StringField(default = '', verbose_name = 'driverCode')
- driverVersion = StringField(default = '', verbose_name = 'driverVersion')
- meta = {"collection": "check_devices", "db_alias": "logdata"}
- class StockRecord(Searchable):
- token = StringField(verbose_name = 'unique token', default = lambda: str(uuid.uuid4()))
- logicCode = StringField(verbose_name = '设备逻辑码')
- imei = StringField(verbose_name = '设备电子标签')
- stockType = StringField(verbose_name = '操作方式', default = '') # 新增、消耗
- stockTime = StringField(verbose_name = '库存变动时间', default = '')
- number = IntField(verbose_name = '数目', default = 0)
- more = StringField(verbose_name = '备注', default = '')
- meta = {
- "collection": "StockRecord",
- "db_alias": "logdata",
- 'indexes': ['logicCode', 'imei', 'stockType', 'stockTime', 'number', 'more'],
- # 'shard_key':('logicalCode',)
- }
- def __repr__(self): return '<StockRecord id=%s>' % (self.id,)
- class FaultRecord(Searchable):
- """
- 告警记录
- """
- logicalCode = StringField(verbose_name = u'设备逻辑码')
- imei = StringField(verbose_name = u'设备电子标签')
- portNo = IntField(verbose_name = u'端口号', default = 0)
- groupName = StringField(verbose_name = u'地址名称', default = '')
- address = StringField(verbose_name = u'地址', default = '')
- faultCode = StringField(verbose_name = u'故障码', default = '') # 告警的恢复是通过故障码 +故障源匹配,然后进行恢复
- title = StringField(verbose_name = u'标题', default = "")
- description = StringField(verbose_name = u'故障描述', default = '')
- dealerId = ObjectIdField(verbose_name = u'经销商ID')
- createdTime = DateTimeField(verbose_name = u'收到时间', default = datetime.datetime.now)
- status = StringField(verbose_name = u'状态', choices = FAULT_RECORD_STATUS.choices(),
- default = FAULT_RECORD_STATUS.INIT)
- count = IntField(default = 0)
- more = StringField(verbose_name = u'其他信息', default = '')
- detail = DictField(verbose_name = u'详情')
- level = StringField(verbose_name = u'告警状态', choices = FAULT_LEVEL.choices(), default = FAULT_LEVEL.NORMAL)
- alarmEventId = StringField(verbose_name = "告警ID", default = "")
- dealedTime = DateTimeField(verbose_name = u'处理时间', default = datetime.datetime.now)
- dealedDetail = StringField(verbose_name = u'处理信息', default = '')
- meta = {
- "collection": "FaultRecord",
- "db_alias": "logdata",
- 'ordering': ['-createdTime']
- # "shard_key":("imei",)
- }
- def set_status(self, status, **kwargs):
- choices = FAULT_RECORD_STATUS.choices()
- if status not in choices:
- raise NotInChoices('%s not in %s' % (status, choices))
- else:
- return self.update(status = status, **kwargs)
- def to_dict(self):
- return {
- 'id': str(self.id),
- 'logicalCode': self.logicalCode,
- # 'imei': self.imei,
- # 'faultCode': self.faultCode,
- 'description': self.description,
- 'title': self.title or self.logicalCode + u' 告警',
- 'createdTime': self.createdTime.strftime(Const.DATETIME_FMT),
- # 'dealerId': str(self.dealerId),
- 'status': self.status,
- # 'more': self.more,
- # 'detail': self.detail,
- # 'count': self.count,
- 'level': self.level,
- 'groupName': self.groupName,
- # 'address':self.address,
- 'dealedTime': self.dealedTime.strftime(Const.DATETIME_FMT),
- 'dealedDetail': self.dealedDetail,
- 'canCheck': True
- }
- @classmethod
- def unhandled_count_by_dealer(cls, dealerId):
- # type:(ObjectId)->int
- return cls.objects(dealerId = dealerId, status = FAULT_RECORD_STATUS.INIT).count()
- @classmethod
- def record_xf(cls, logicalCode, port, description, faultCode, createdTime, groupId, alarmEventId):
- """
- 记录消防队相关信息
- :return:
- """
- # 过滤掉5分钟以内重复发送的信息
- record = cls.objects.filter(
- logicalCode = logicalCode,
- port = port,
- faultCode = faultCode,
- description = description,
- createdTime__gt = createdTime - datetime.timedelta(minutes = 5)
- )
- if record:
- raise Exception("重复数据")
- group = Group.get_group(groupId)
- devNo = Device.get_devNo_by_logicalCode(logicalCode)
- device = Device.get_dev(devNo)
- record = cls(
- logicalCode = logicalCode,
- imei = devNo,
- portNo = port,
- faultCode = faultCode,
- description = description,
- groupName = group.get("groupName", ""),
- address = group.get("address", ""),
- alarmEventId = alarmEventId,
- dealerId = device.get("ownerId", ""),
- createdTime = createdTime
- )
- record.save()
- def __repr__(self):
- return '<FaultRecord id=%s>' % (self.id,)
- class DeviceEvent(Searchable):
- """
- 对应设备上报的由设备管理存储的设备事件表,可用于统计和在一定程度上恢复线下投币等数据
- 命令码
- 200 握手
- 201 查询设备信息
- 202 参数设置
- 203 移动支付
- 204 移动支付上报事件
- 205 硬币投币事件上报
- 207 心跳包
- 该表不允许任何业务逻辑使用, 仅用来对账和恢复数据
- """
- cmd = IntField(verbose_name = '命令码')
- devNo = StringField(verbose_name = '设备号')
- money = IntField(verbose_name = '投币数额')
- time = IntField(verbose_name = '上报时间戳')
- meta = {'collection': 'events', 'db_alias': 'logdata'}
- class DeviceCommandParam(EmbeddedDocument):
- id = ObjectIdField(default = ObjectId)
- description = StringField()
- key = StringField()
- default = StringField()
- allow_change = BooleanField(default = False)
- type = StringField(default='string')
- def __repr__(self):
- return '<DeviceCommandParam> key=%s default=%s' % (self.key, self.default)
- def to_dict(self):
- return {
- "id": str(self.id),
- "description": self.description,
- "key": self.key,
- "default": self.default,
- "allow_change": self.allow_change
- }
- def to_payload(self, value):
- if not self.allow_change:
- value = self.default
- # 避免字符串的转义 将json 以及 bool 类型的数据统统处理掉
- try:
- if self.type == 'string':
- value = str(value)
- else:
- value = json.loads(value)
- except Exception:
- value = value
- return {str(self.key): value}
- class DeviceCommand(Searchable):
- """
- 直接对模块发送指令 一半适用于 管理平台 或者 厂商平台
- 增添身份 对于该指令的支持
- """
- # 用于区分设备的两个字段 common 优先级大于devTypeCode
- devTypeCode = StringField(verbose_name = u'设备类型编码', default = '')
- common = BooleanField(verbose_name = u'是否所有设备通用', default = False)
- description = StringField(verbose_name = "指令描述", default = u"指令")
- # 对于模板的一些内容
- topic_pre = StringField(verbose_name = "topic前缀", default = "smartBox")
- cmd = IntField(verbose_name = u"指令的cmd", default = 201)
- params = EmbeddedDocumentListField(document_type = DeviceCommandParam, default = [])
- # 命令使用者的身份控制
- active = BooleanField(verbose_name = u"是否启用该指令", default = True)
- clientId = StringField(verbose_name = u"调用方的Id", default = "")
- role = StringField(verbose_name = u"身份", choices = ROLE.choices(), default = "supermanager")
- dateTimeAdded = DateTimeField(verbose_name = u"指令添加时间", default = datetime.datetime.now)
- meta = {'collection': 'DeviceCommands', 'db_alias': 'default'}
- search_fields = ('cmd', 'devTypeCode')
- def __repr__(self):
- return '<DeviceCommand name=%s, identifier=%s, debType=%s>' % (self.description, self.cmd, self.devTypeCode)
- @classmethod
- def common_and_type_specific(cls, logicalCode, commander):
- """
- :param logicalCode:
- :param commander:
- :return:
- """
- def _is_legal(cmd, commanderId):
- if cmd.role == ROLE.supermanager:
- return True
- else:
- return str(commanderId) == cmd.clientId
- dev = Device.get_dev_by_l(logicalCode)
- if not dev:
- return list()
- devTypeCode = dev.devType.get("code")
- cmdQuery = cls.objects(Q(devTypeCode = devTypeCode) | Q(common = True), role = commander.role, active = True)
- dataList = list()
- for _item in cmdQuery:
- if not _is_legal(_item, str(commander.id)):
- continue
- data = _item.get_one()
- data.update({"IMEI": dev.devNo})
- dataList.append(data)
- return dataList
- def to_dict(self):
- return {
- "id": str(self.id),
- "devTypeCode": self.devTypeCode,
- "common": self.common,
- "description": self.description,
- "topic_pre": self.topic_pre,
- "active": self.active,
- "cmd": self.cmd,
- "clientId": self.clientId,
- "role": self.role,
- "params": [_param.to_dict() for _param in self.params]
- }
- def get_one(self):
- """获取指令"""
- return {
- "id": str(self.id),
- "description": self.description,
- "topic_pre": self.topic_pre,
- "cmd": self.cmd,
- "params": [_param.to_dict() for _param in self.params]
- }
- def package_command(self, dev, params):
- """
- 将指令经过一系列校验之后 打包成指定的格式
- :param dev:
- :param params:
- :return:
- """
- # 首先拼接载体部分
- payload = {"IMEI": dev.devNo, "cmd": self.cmd}
- for _param in params:
- paramId = _param.get("id")
- value = _param.get("default")
- param = self.params.filter(id = paramId).first()
- if not param:
- continue
- payload.update(param.to_payload(value))
- return payload
- def supports(self, device): return True
- class Comment(Searchable):
- devNo = StringField(verbose_name = "设备编号", min_length = 1)
- logicalCode = StringField(verbose_name = "逻辑编码", min_length = 1)
- groupId = StringField(verbose_name = "逻辑编码", min_length = 1)
- groupNumber = StringField(verbose_name = "设备组内编号", default = "")
- groupName = StringField(verbose_name = "设备组内编号", default = "")
- address = StringField(verbose_name = "设备组内编号", default = "")
- ownerId = StringField(verbose_name = "所有者", default = "")
- openId = StringField(verbose_name = "微信ID", default = "")
- nickname = StringField(verbose_name = "名称", max_length = 255, default = "")
- ratingList = ListField(verbose_name = "得分", default = [])
- description = StringField(verbose_name = "用户留言", max_length = 255, default = "")
- createTime = StringField(verbose_name = "创建时间",
- default = lambda: datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
- meta = {"collection": "Comment", "db_alias": "logdata"}
- class SIMCard(Searchable):
- iccid = StringField(verbose_name = "iccid", unique = True)
- imsi = StringField(verbose_name = "imsi")
- supplier = StringField(verbose_name = "供应商")
- provider = StringField(verbose_name = "运营商",default = u'移动')
- activeTime = DateTimeField(verbose_name = "激活时间")
- expireTime = DateTimeField(verbose_name = "过期时间")
- chargeTime = DateTimeField(verbose_name = "充值时间")
- channel = StringField(verbose_name = u'通道号', default = '')
- meta = {"collection": "SIMCard", "db_alias": "logdata"}
- class Cell(Searchable):
- logicalCode = StringField(verbose_name = "设备编号", min_length = 1)
- cellNo = StringField(verbose_name = "格子编号", min_length = 1)
- boardNo = IntField(verbose_name = "板地址", default = 0)
- lockNo = IntField(verbose_name = "锁地址", default = 0)
- itemTitle = StringField(verbose_name = "商品标题", default = '')
- itemDesc = StringField(verbose_name = "商品描述", default = '')
- itemPicUrl = StringField(verbose_name = "商品图片URL", default = '')
- itemPrice = IntField(verbose_name = "商品价格,单位分", default = 0)
- lockStatus = StringField(verbose_name = "门锁状态", default = 'close')
- itemStatus = StringField(verbose_name = "商品状态", default = 'empty')
- meta = {"collection": "Cell", "db_alias": "default"}
- @staticmethod
- def update_dev_quantity_from_cell(dev):
- quantity = Cell.objects.filter(logicalCode = dev['logicalCode'], itemStatus = 'full').count()
- consumptionQuantity = Cell.objects.filter(logicalCode = dev['logicalCode'], itemStatus = 'empty').count()
- Device.update_field(dev_no = dev['devNo'],
- update = True,
- quantity = quantity,
- consumptionQuantity = consumptionQuantity)
- class Part(Searchable):
- class Status(IterConstant):
- IDLE = Const.DEV_WORK_STATUS_IDLE
- WORKING = Const.DEV_WORK_STATUS_WORKING
- FORBIDDEN = Const.DEV_WORK_STATUS_FORBIDDEN # 结束运行的状态
- FAULT = Const.DEV_WORK_STATUS_FAULT
-
- class OnlineStatus(IterConstant):
- ONLINE = 'online'
- OFFLINE = 'offline'
-
- logicalCode = StringField(verbose_name = "设备编号", min_length = 1)
- ownerId = StringField(verbose_name = "ownerId", min_length = 1)
- partNo = StringField(verbose_name = "部件编码", min_length = 1)
- partName = StringField(verbose_name = "部件名称", min_length = 1)
- partType = StringField(verbose_name = "部件类型编码", default = '5001', min_length = 1) # 部件类型,根据各个对接业务,自己定义
- attachParas = DictField(verbose_name="其余参数", default={})
- dateTimeAdded = DateTimeField(default = datetime.datetime.now, verbose_name = '添加进来的时间')
- dateTimeUpdated = DateTimeField(default = datetime.datetime.now, verbose_name = '更新时间')
- expiredTime = DateTimeField(verbose_name = u'维保过期时间',
- default = datetime.datetime.now() + datetime.timedelta(days = Const.MAINTENANCE_DAYS))
-
- status = IntField(verbose_name = u'状态',default = Const.DEV_WORK_STATUS_IDLE)
- onlineStatus = StringField(verbose_name = u'在线情况',default = 'online')
-
- meta = {"collection": "Part", "db_alias": "default"}
- @staticmethod
- def upsert_part(logicalCode, ownerId, partNo, partName, partType):
- # 先把原来一样的part 删除掉
- Part.objects.filter(logicalCode = logicalCode, partName = partName, partNo__ne = partNo).delete()
- count = Part.objects.filter(logicalCode = logicalCode, partNo = partNo).count()
- if count == 0: # 如果没有,说明是首次上线
- if partName == u'网络板':
- part = Part(
- logicalCode = logicalCode,
- ownerId = ownerId,
- partNo = partNo,
- partName = partName,
- partType = partType,
- expiredTime = datetime.datetime.now() + datetime.timedelta(days = 365)
- )
- else:
- part = Part(
- logicalCode = logicalCode,
- ownerId = ownerId,
- partNo = partNo,
- partName = partName,
- partType = partType,
- )
- part.save()
- else:
- return
-
- @staticmethod
- def insert_part_if_not_exist(logicalCode, ownerId, partNo, partName,partType='',partStatus = Const.DEV_WORK_STATUS_IDLE):
- part = Part.objects(logicalCode = logicalCode,ownerId = ownerId,partNo = str(partNo)).first()
- if part is None:
- part = Part(logicalCode = logicalCode,ownerId = ownerId,partNo = str(partNo),partName = partName,partType = partType,partStatus = partStatus)
- try:
- part.save()
- except Exception,e:
- return None
- return part
-
- @staticmethod
- def update_part_work_status(logicalCode,partNo,workStatus):
- part = Part.objects(logicalCode = logicalCode,partNo = str(partNo)).first()
- if part is None:
- return
- part.status = workStatus
- try:
- part.save()
- except Exception,e:
- return
-
- @staticmethod
- def update_part_network_status(logicalCode,partNo=None,onlineStatus='online'):
- if partNo:
- part = Part.objects(logicalCode = logicalCode,partNo = str(partNo)).first()
- if part is None:
- return
- part.onlineStatus = onlineStatus
- try:
- part.save()
- except Exception,e:
- return
- else:
- for part in Part.objects(logicalCode = logicalCode):
- part.onlineStatus = onlineStatus
- try:
- part.save()
- except Exception,e:
- continue
-
- @staticmethod
- def delete_dev(logicalCode):
- Part.objects(logicalCode= logicalCode).delete()
-
- class Town(Searchable):
- name = StringField(verbose_name = 'name', min_length = 1)
- level = StringField(verbose_name = 'level', min_length = 1) # 级别,1:镇级别,2:村级别
- code = StringField(verbose_name = 'level', min_length = 1) # 编码
- townDict = {}
- villageDict = {}
- @staticmethod
- def load_in_mem_if_not_exist():
- if Town.townDict or Town.villageDict:
- return
- for town in Town.objects.filter(level = '1'):
- Town.townDict[town.name] = town.code
- for village in Town.objects.filter(level = '2'):
- Town.villageDict[village.name] = village.code
- @staticmethod
- def analyze_town_village(address):
- Town.load_in_mem_if_not_exist()
- townCode, villageCode = None, None
- for k, v in Town.townDict.items():
- if k in address:
- townCode = v
- break
- for k, v in Town.villageDict.items():
- if k in address:
- villageCode = v
- break
- return townCode, villageCode
- # 设备的状态记录表,用于汇总设备的状态报表
- class DevStatusRecord(Searchable):
- devNo = StringField(verbose_name = "devNo", min_length = 1)
- status = StringField(verbose_name = "status", min_length = 1) # offline,offlineBusy,online
- startTime = DateTimeField(default = datetime.datetime.now, verbose_name = '状态开始时间')
- endTime = DateTimeField(default = datetime.datetime.now, verbose_name = '状态结束时间')
- duration = IntField(verbose_name = "持续时长", default = 0) # 单位秒
- valueDict = DictField(
- verbose_name = "附带数据,比如信号量") # 'signalUsages':[{'time':'2010-01-01 00:00:00','signal':9,'usage':0-100(设备使用率)}]
- meta = {'collection': 'dev_status_record', 'db_alias': 'logdata',
- 'unique_together': {'devNo', 'startTime', 'endTime'}}
- class PortReport(Searchable):
- logicalCode = StringField(verbose_name = "设备编号", min_length = 1)
- temperature = IntField(verbose_name = "温度信息", min_length = 1)
- time = IntField(verbose_name = "时间信息", min_length = 1)
- portInfo = DictField(verbose_name = "端口信息", default = {})
- meta = {"collection": "port_report", "db_alias": "default"}
- class ManagerInputDev(Searchable):
- logicalCode = StringField(verbose_name = "二维码编号", unique = True)
- devNo = StringField(verbose_name = "设备编号", unique = True)
- managerId = StringField(verbose_name = "厂商ID")
- inputTime = DateTimeField(default = lambda: datetime.datetime.now(), verbose_name = '录入时间')
- meta = {
- "collection": "ManagerInputDev",
- "db_alias": "default"
- }
- # 用于记录微付乐单板的事件1、用于全网分析,也不会被日志冲掉;2、不用memcach,用数据库记录关键数据
- class WeifuleDeviceOrder(Searchable):
- orderNo = StringField(verbose_name = 'orderNo')
- funCode = StringField(verbose_name = 'funCode')
- dateTimeAdded = DateTimeField(verbose_name = 'dateTimeAdded', default = datetime.datetime.now())
- event = DictField(verbose_name = u'消息体内容', default = {})
- meta = {
- "collection": "weifule_device_order",
- "db_alias": "logdata"
- }
- class SerialTimeOut(Searchable):
- logicalCode = StringField(verbose_name = 'logicalCode', default = '')
- devNo = StringField(verbose_name = 'devNo', default = '')
- ownerId = StringField(verbose_name = 'ownerId', default = '')
- dateTimeAdded = DateTimeField(verbose_name = 'time', default = datetime.datetime.now)
- devTypeCode = StringField(verbose_name = 'devTypeCode', default = '')
- packet = StringField()
- meta = {
- "collection": "serial_time_out",
- "db_alias": "logdata"
- }
- @classmethod
- def new_one(cls, device, fun_code, data):
- # type:(DeviceDict,str,str)->None
- try:
- SerialTimeOut(
- logicalCode = device.logicalCode,
- devNo = device.devNo,
- ownerId = device.ownerId,
- devTypeCode = device.get('devType', '').get('code', ''),
- packet = u'{}_{}'.format(fun_code, data)).save()
- except Exception as e:
- logger.exception(e)
- class MqttErrorLog(DynamicDocument):
- logicalCode = StringField(verbose_name='logicalCode', default='')
- devNo = StringField(verbose_name='devNo', default='')
- ownerId = StringField(verbose_name='ownerId', default='')
- dateTimeAdded = DateTimeField(verbose_name='time', default=datetime.datetime.now)
- devTypeCode = StringField(verbose_name='devTypeCode', default='')
- payload = StringField()
- rst = StringField()
- meta = {
- "collection": "mqtt_error_log",
- "db_alias": "logdata"
- }
- @classmethod
- def new_one(cls, device, payload, rst):
- # type:(DeviceDict,dict,str)->None
- try:
- MqttErrorLog(
- logicalCode=device.logicalCode,
- devNo=device.devNo,
- ownerId=device.ownerId,
- devTypeCode=device.devTypeCode,
- payload=json_dumps(payload), rst=str(rst)).save()
- except Exception as e:
- logger.exception(e)
- class DeviceMqttStatics(DynamicDocument):
- devNo = StringField(verbose_name='IMEI', default='')
- total = LongField(verbose_name=u'总共执行次数', default=0)
- uartTimeout = LongField(verbose_name=u'串口错误', default=0)
- connFail = LongField(verbose_name=u'串口错误', default=0)
- otherError = LongField(verbose_name=u'串口错误', default=0)
- meta = {
- 'indexes': [
- {
- 'fields': ['devNo'], 'unique': True
- },
- ],
- "collection": "device_mqtt_statics",
- "db_alias": "logdata"
- }
- @classmethod
- def update(cls, device, total, uart_error, conn_error, other_error):
- cls.objects(devNo=device.devNo).upsert_one(devNo=device.devNo, inc__total=total, inc__uartTimeout=uart_error,
- inc__connFail=conn_error, inc__otherError=other_error)
- class DevicePortReport(Searchable):
- """
- 粤万通的设备端口 10分钟 上报一次的数据 用于结算使用金额
- """
- devNo = StringField(verbose_name = "设备编号")
- port = StringField(verbose_name = "上报端口号")
- orderNo = StringField(verbose_name = "订单号")
- openId = StringField(verbose_name = "端口使用者")
- # 粤万通的充电柜 即时充电完成 但是订单没有结束之前 还是会上报电量 这个地方就放置多计费
- isBilling = BooleanField(verbose_name = "是否参与电量计费", default = True)
- voltage = IntField(verbose_name = "电压")
- power = IntField(verbose_name = "功率")
- elec = IntField(verbose_name = "电量")
- chargeTime = IntField(verbose_name = "充电时间")
- stayTime = IntField(verbose_name = "占位时间", default = 0)
- stageTime = IntField(verbose_name = "该阶段的充电时间")
- dateTimeAdded = DateTimeField(verbose_name = "生成时间", default = datetime.datetime.now)
- meta = {
- "collection": "DevicePortReport",
- "db_alias": "logdata",
- "index": [
- "orderNo"
- ]
- }
- @classmethod
- def last_one(cls, orderNo):
- return cls.objects.filter(orderNo = orderNo).order_by("-dateTimeAdded").first()
- @classmethod
- def last_billing_one(cls, orderNo):
- return cls.objects.filter(orderNo = orderNo, isBilling = True).order_by("-dateTimeAdded").first()
- @classmethod
- def create(cls, devNo, port, orderNo, openId, voltage, power, elec, chargeTime, stayTime = None, **kwargs):
- if not stayTime:
- stayTime = 0
- lastOne = cls.last_one(orderNo)
- leftChargeTime = lastOne.chargeTime if lastOne else 0
- report = cls(
- devNo = devNo,
- port = port,
- orderNo = orderNo,
- openId = openId,
- voltage = voltage,
- power = power,
- elec = elec,
- chargeTime = chargeTime,
- stageTime = chargeTime - leftChargeTime,
- stayTime = stayTime,
- **kwargs
- )
- try:
- report.save()
- except Exception as e:
- logger.error(e)
- return
- return report
- @classmethod
- def billing_records(cls, orderNo):
- return cls.objects.filter(orderNo = orderNo, isBilling = True).all()
- @classmethod
- def stay_records(cls, orderNo):
- return cls.objects.filter(orderNo = orderNo, isBilling = False).all()
- @classmethod
- def calculate(cls, records, intervalMap):
- """
- 计算记录的
- :param records:
- :param intervalMap:
- :return:
- """
- intervalMap = copy.deepcopy(intervalMap)
- for record in records:
- cls.add_power_time(intervalMap, record.power, record.stageTime)
- # 根据interval_map的累加值计算钱
- consume = 0
- for _, item in intervalMap.items():
- unitPrice = item.get("unitPrice") # 单位是小时 元
- _time = item.get("time") # 单位是分钟 需要转换
- consume += unitPrice * _time / 60.0
- return consume
- @classmethod
- def calculate_consume(cls, orderNo, allChargeTime, lastPower, interval_map, devNo, port, openId, voltage, elec):
- """
- 计算消费金钱数据 并将最后一次的主动查询或上报数据保存
- :param orderNo:
- :param allChargeTime:
- :param lastPower:
- :param interval_map:
- :param devNo: 用于记录数据
- :param port: 用于记录数据
- :param openId: 用于记录数据
- :param voltage: 用于记录数据
- :param elec: 用于记录数据
- :return:
- """
- interval_map = copy.deepcopy(interval_map)
- timeList = list()
- totalConsume = VirtualCoin(0)
- # 依次累加功率段的时间
- for record in cls.objects.filter(orderNo = orderNo):
- timeList.append(record.chargeTime)
- cls.add_power_time(interval_map, record.power, record.stageTime)
- # 计算最后一次上报到结束消费这之间的消费金额
- try:
- lastChargeTime = max(timeList)
- except ValueError as e:
- lastChargeTime = 0
- chargeTime = allChargeTime - lastChargeTime
- cls.add_power_time(interval_map, lastPower, chargeTime)
- # 把最后一次的数据也记录上去
- lastRecord = cls(
- devNo = devNo,
- port = port,
- orderNo = orderNo,
- openId = openId,
- voltage = voltage,
- power = lastPower,
- elec = elec,
- chargeTime = allChargeTime,
- stageTime = chargeTime
- )
- try:
- lastRecord.save()
- except Exception as e:
- logger.error(e)
- # 根据interval_map的累加值计算钱
- for _, item in interval_map.items():
- unitPrice = item.get("unitPrice")
- _time = item.get("time")
- totalConsume += unitPrice * _time / 60.0
- return totalConsume
- @staticmethod
- def add_power_time(interval_map, power, chargeTime):
- """
- 获取功率区间的单价
- :param interval_map: 功率区间
- :param power: 该阶段功率
- :param chargeTime: 该阶段充电时间
- :return: Ratio
- """
- for interval, item in interval_map.items():
- if int(power) in interval:
- item.update({
- "time": item["time"] + chargeTime
- })
- class DevicePortLastReport(Searchable):
- """
- 关键信息 端口号 + 设备号 唯一
- """
- orderNo = StringField(verbose_name = "订单编号")
- devNo = StringField(verbose_name = u"设备编号")
- port = StringField(verbose_name = u"端口号")
- power = IntField(verbose_name = "功率", default = 0)
- elec = FloatField(verbose_name = "已充入电量", default = 0.0)
- chargeTime = IntField(verbose_name = u"充电时间", default = 0)
- stayTime = IntField(verbose_name = u"占位时间", default = 0)
- chargeConsume = AccuracyMoneyField(verbose_name = u"目前为止的充电费用", default = AccuracyRMB(0))
- stayConsume = AccuracyMoneyField(verbose_name = u"到目前为止的占位费用", default = AccuracyRMB(0))
- totalConsume = AccuracyMoneyField(verbose_name = u"目前为止累计的总消费", default = AccuracyRMB(0))
- datetimeUpdated = DateTimeField(verbose_name = u"更新时间", default = datetime.datetime.now)
- dateTimeAdded = DateTimeField(verbose_name = "生成时间", default = datetime.datetime.now)
- meta = {'collection': 'device_port_last_report', 'db_alias': 'logdata'}
- @classmethod
- def null(cls):
- return cls()
- @classmethod
- def save_last(cls, devNo, port, **kwargs):
- """
- 将设备上报的信息 存储方式为复写
- :param devNo:
- :param port:
- :param kwargs:
- :return:
- """
- try:
- obj = cls.objects.get(devNo = devNo, port = port)
- except DoesNotExist:
- obj = cls(devNo = devNo, port = port)
- obj.power = kwargs.get("power")
- obj.elec = kwargs.get("elec")
- obj.chargeTime = kwargs.get("chargeTime")
- obj.stayTime = kwargs.get("stayTime")
- orderNo = kwargs.get("orderNo")
- # 订单号不一致 说明是覆盖之前的记录 更新一下记录的时间
- nowTime = datetime.datetime.now()
- if obj.orderNo != orderNo:
- obj.chargeConsume = AccuracyRMB(0)
- obj.stayConsume = AccuracyRMB(0)
- obj.totalConsume = AccuracyRMB(0)
- obj.dateTimeAdded = nowTime
- obj.orderNo = orderNo
- obj.datetimeUpdated = nowTime
- return obj.save()
- @classmethod
- def get_last(cls, devNo, port, orderNo):
- """
- 获取该 订单的上次上报的信息
- :param devNo:
- :param port:
- :param orderNo:
- :return:
- """
- try:
- obj = cls.objects.get(devNo = devNo, port = port)
- except DoesNotExist:
- return cls.null()
- if obj.orderNo != orderNo:
- return cls.null()
- return obj
- @classmethod
- def get_last_by_order(cls, orderNo):
- """
- 获取消费的金额
- :param orderNo:
- :return:
- """
- try:
- obj = cls.objects.get(orderNo = orderNo)
- except DoesNotExist:
- obj = cls.null()
- return obj
- def update_consume(self, chargeConsume, stayConsume):
- """更新消费金额 精确到0.1厘"""
- chargeConsume = AccuracyRMB(chargeConsume) + self.chargeConsume
- stayConsume = AccuracyRMB(stayConsume)
- totalConsume = chargeConsume + stayConsume
- self.update(chargeConsume = chargeConsume, stayConsume = stayConsume, totalConsume = totalConsume)
- class OfflineCoinStatistics(Searchable):
- logicalCode = StringField(verbose_name = u'设备编号')
- devNo = StringField(verbose_name = u"IMEI")
- count = IntField(verbose_name = u'投币次数')
- groupId = StringField(verbose_name = u'地址ID')
- dateTimeAdded = DateTimeField(verbose_name = u"添加时间", default = datetime.datetime.now)
- meta = {
- "collection": "offline_coin_statistics",
- "db_alias": "logdata",
- "index": [
- "logicalCode"
- ]
- }
- @classmethod
- def recordCoinEvent(cls, logicalCode, devNo, count, groupId):
- report = cls(
- logicalCode = logicalCode,
- devNo = devNo,
- count = count,
- groupId = groupId
- )
- try:
- report.save()
- except Exception as e:
- logger.error(e)
- return
- class OfflineReportDealers(DynamicDocument):
- """
- 投币的经销商统计 只要有投币的经销商 以ID+DATE为键存入
- """
- ownerId = StringField(verbose_name = "经销商id", required = True)
- reportDay = StringField(verbose_name = "report日期", required = True)
- datetimeAdded = DateTimeField(verbose_name = "记录时间", default = datetime.datetime.now)
- meta = {
- "collection": "offline_report_dealers",
- "db_alias": "logdata",
- 'indexes': [
- {
- 'fields': ['ownerId', 'reportDay'], 'unique': True
- },
- {
- 'fields': ['datetimeAdded'],
- # 保留 7 天的数据 方便经销商的追溯
- 'expireAfterSeconds': 24 * 3600 * 7
- }
- ],
- }
- @classmethod
- def record_dealer(cls, dealerId, dateStr = None):
- """
- 有投币的经销商统计一下
- :param dealerId:
- :param dateStr: 时间
- :return:
- """
- if dateStr is None:
- dateStr = datetime.datetime.today().strftime("%Y-%m-%d")
- if not dealerId:
- logger.error('dealer id is null.')
- return
- try:
- cls(ownerId = dealerId, reportDay = dateStr).save()
- except NotUniqueError:
- return
- except Exception as e:
- logger.exception(e)
- @classmethod
- def get_rpt_dealIds(cls, dateStr = None):
- if dateStr is None:
- dateStr = datetime.datetime.today().strftime("%Y-%m-%d")
- return [_rpt.ownerId for _rpt in cls.objects.filter(reportDay = dateStr).all()]
- class Battery(Searchable):
- batterySn = StringField(verbose_name = "电池的SN编号", regex = r"\d{15}")
- dealerId = StringField(verbose_name = "经销商的ID")
- devNo = StringField(verbose_name = "电池存放的设备编号", default = "")
- portNo = StringField(verbose_name = "电池存放的设备端口号", default = "")
- openId = StringField(verbose_name = "取走电池的用户", default = "")
- normal = BooleanField(verbose_name = "电池是否正常", default = True)
- dateTimeAdded = DateTimeField(verbose_name = "电池加入系统的时间", default = datetime.datetime.now)
- dateTimeUpdated = DateTimeField(verbose_name = "电池信息更新的时间", default = datetime.datetime.now)
- meta = {
- "collection": "Battery"
- }
- search_fields = ("devNo", "batterySn")
- def save(self, **kwargs):
- self.dateTimeUpdated = datetime.datetime.now()
- return super(Battery, self).save(**kwargs)
- @staticmethod
- def is_battery_sn_format(batterySn):
- """
- 是否是正确的电池编号格式
- :param batterySn:
- :return:
- """
- try:
- result = batterySn.isdigit() and len(batterySn) == 15
- except (AttributeError, TypeError):
- result = False
- return result
- @classmethod
- def add_from_device(cls, batterySn, devNo, port, dealerId):
- """
- 从设备侧读取的电池编号信息入库
- :param batterySn:
- :param devNo:
- :param port:
- :param dealerId:
- :return:
- """
- battery = cls(batterySn = batterySn, devNo = devNo, portNo = port, dealerId = dealerId)
- try:
- record = battery.save()
- except NotUniqueError:
- return None
- return record
- @classmethod
- def add_from_enter(cls, batterySn, dealerId):
- """
- 手动录入电池信息
- :param batterySn:
- :param dealerId:
- :return:
- """
- battery = cls(batterySn = batterySn, dealerId = dealerId)
- try:
- record = battery.save()
- except NotUniqueError:
- return None
- return record
- @classmethod
- def delete_one(cls, dealerId, batterySn):
- logger.info("delete battery dealer is <{}>, batterySn is <{}>".format(dealerId, batterySn))
- battery = cls.objects.filter(dealerId = dealerId, batterySn = batterySn)
- if not battery:
- return False
- try:
- battery.delete()
- except Exception as e:
- logger.exception("dealerId is <{}>, batterySn is <{}>, error is {}".format(dealerId, batterySn, e))
- return False
- return True
- @classmethod
- def get_one(cls, dealerId, batterySn):
- return cls.objects.filter(dealerId = dealerId, batterySn = batterySn).first()
- def is_owner(self, dealerId):
- return self.dealerId == dealerId
- def to_dict(self):
- # TODO zjl 持有信息需要修改
- if self.openId:
- from apps.web.user.models import MyUser
- user = MyUser.objects.filter(openId = self.openId).first()
- lastOwner = "{}".format(user.nickname)
- elif self.devNo:
- logicalCode = Device.get_dev(self.devNo).logicalCode
- lastOwner = "{}-{}".format(logicalCode, self.portNo)
- else:
- # 刚刚添加的设备 或者是被清除掉openId的电池
- lastOwner = u""
- data = {
- "batterySn": self.batterySn,
- "dealerId": self.dealerId,
- "dateTimeUpdated": self.dateTimeUpdated.strftime("%Y-%m-%d %H:%M:%S"),
- "lastOwner": lastOwner,
- "disable": self.disable
- }
- return data
- def update_dev_info(self, devNo, port):
- self.devNo = devNo
- self.portNo = port
- self.openId = ""
- try:
- self.save()
- except Exception as e:
- logger.exception(
- "batterySn is <{}>, devNo is <{}>, port is <{}>, error is <{}>".format(self.batterySn, devNo, port, e))
- return False
- return True
- def update_user_info(self, openId):
- """
- 同一个用户同义时间只能拥有一块电池 在更新用户的时候 需要将用户之前拥有过的电池都清除掉
- :param openId:
- :return:
- """
- self.__class__.objects.filter(openId = openId).update(openId = "")
- self.openId = openId
- self.devNo = ""
- self.portNo = ""
- try:
- self.save()
- except Exception as e:
- logger.exception("batterySn is <{}>, openId is <{}>, error is <{}>".format(self.batterySn, openId, e))
- return False
- return True
- @classmethod
- def get_user_last_battery_sn(cls, openId, dealerId):
- battery = cls.objects.filter(openId = openId, dealerId = dealerId).first()
- return battery.batterySn if battery else None
- @property
- def disable(self):
- return not self.normal
- @disable.setter
- def disable(self, value):
- if not isinstance(value, bool):
- raise TypeError(u"type of value must be bool, value is <{}>, battery is <{}>".format(value, self))
- if not self.dealerId:
- raise ValueError(u"no dealer battery can not set disable, battery is <{}>".format(self))
- self.update(normal = not value)
- # TODO capped collection 固有集合 默认 不可删除,不可修改(但非StringField可以修改),只能迭代,目前保留三万条
- class DeviceUploadInfo(Searchable):
- device_imei = StringField(verbose_name = "设备IMEI号")
- order_id = StringField(verbose_name = "事件ID", default = None)
- order_type = StringField(verbose_name = "事件类型", default = None)
- money = FloatField(verbose_name = "使用的金额(分)", default = None)
- left_money = FloatField(verbose_name = "当前剩余的金额(分)", default = None)
- amount = FloatField(verbose_name = "本单的总金额", default = None)
- create_time = FloatField(verbose_name = "创建订单时间", default = None)
- exec_time = FloatField(verbose_name = "开始充电时间", default = None)
- time = FloatField(verbose_name = "已使用时间", default = None)
- elec = FloatField(verbose_name = "已使用电量(毫度)", default = None)
- status = StringField(verbose_name = "当前设备状态码", default = None)
- last_clock = FloatField(verbose_name = "最近的时钟信息", default = None)
- last_ecnt = FloatField(verbose_name = "最近的计量值", default = None)
- last_update_time = DateTimeField(verbose_name = "最近一次更新数据时间", default = datetime.datetime.now())
- meta = {
- "collection": "device_upload_info",
- "db_alias": "logdata"
- }
- class DeviceCmdStatics(DynamicDocument):
- devNo = StringField(verbose_name = u"设备IMEI号")
- cmd = StringField(verbose_name = u"事件ID")
- count = IntField(verbose_name = u'计数', default = 0)
- meta = {
- "collection": "device_cmd_statics",
- "db_alias": "logdata"
- }
- @classmethod
- def get_collection(cls):
- return cls._get_collection()
- @classmethod
- def record(cls, devNo, cmd):
- cls.get_collection().update_one(
- filter = {'devNo': devNo, 'cmd': cmd},
- update = {'$inc': {'count': 1}},
- upsert = True)
- class DeviceRentOrderDetail(EmbeddedDocument):
- status = BooleanField(verbose_name=u"结算是否成功", require=True)
- reason = StringField(verbose_name=u"结算失败的原因", default="")
- dateTime = DateTimeField(verbose_name=u"结算时间", require=True)
- sourceKey = StringField(verbose_name=u"扣款的source")
- def to_dict(self):
- return {
- "dateTime": self.dateTime.strftime("%Y-%m-%d %H:%M:%S"),
- "status": self.status,
- "reason": self.reason
- }
- class DeviceRentOrder(Searchable):
- """
- 设备的日出租的订单
- """
- orderNo = StringField(verbose_name=u"订单编号", required=True)
- devNo = StringField(verbose_name=u"账单设备", require=True)
- # 以账单产生时候的经销商ID为准
- dealerId = StringField(verbose_name=u"账单所有者", require=True)
- billDate = DateField(verbose_name=u"账单日期", required=True)
- billAmount = MonetaryField(verbose_name=u"账单金额", require=True)
- status = BooleanField(verbose_name=u"是否已经结算", default=False)
- dateTimeAdded = DateTimeField(verbose_name=u"订单添加时间", default=datetime.datetime.now)
- detail = EmbeddedDocumentListField(document_type=DeviceRentOrderDetail, verbose_name=u"详情详情")
- meta = {
- "collection": "DeviceRentOrder",
- "db_alias": "logdata"
- }
- @staticmethod
- def make_no(date, devNo):
- return "{}{}".format(devNo, date.strftime("%Y%m%d%H%M%S"))
- @classmethod
- def create_by_device(cls, device, date=None): # type:(Device, datetime.date) -> DeviceRentOrder
- """
- 创建设备的日订单 默认是当日的订单
- :param device:
- :param date:
- :return:
- """
- date = date or datetime.date.today()
- try:
- order = cls.objects.get(devNo=device.devNo, billDate=date)
- except DoesNotExist:
- order = cls(
- orderNo=cls.make_no(date, device.devNo),
- devNo=device.devNo,
- dealerId=device.ownerId,
- billDate=date,
- billAmount=device.rentMoney
- ).save()
- return order
- @classmethod
- def get_by_device(cls, device): # type:(Device) -> QuerySet
- """
- 获取所有经销商的日租订单
- :param device:
- :return:
- """
- return cls.objects.filter(
- dealerId=device.ownerId,
- devNo=device.devNo,
- ).order_by("-dateTimeAdded")
- @classmethod
- def get_not_paid_by_dealer(cls, dealer): # type:(Dealer) -> QuerySet
- """
- 获取经销商所有没有结算的订单
- :param dealer:
- :return:
- """
- return cls.objects.filter(
- dealerId=str(dealer.id),
- status=False,
- ).order_by("dateTimeAdded")
- @classmethod
- def get_not_paid_by_device(cls, device): # type:(Device) -> QuerySet
- """
- 获取设备没有完成的订单
- :param device:
- :return:
- """
- return cls.objects.filter(
- devNo=device.devNo,
- status=False,
- ).order_by("dateTimeAdded")
- @property
- def dealer(self): # type:() -> Dealer
- return Dealer.objects.get(id=self.dealerId)
- def to_dict(self):
- return {
- "orderNo": self.orderNo,
- "billDate": self.billDate.strftime("%Y-%m-%d"),
- "billAmount": self.billAmount,
- "status": self.status,
- "detail": [_.to_dict() for _ in self.detail]
- }
- def update_for_success(self, dateTime, source):
- """
- 结算成功的更新
- 添加支付信息 添加扣款信息 更换状态
- :param dateTime:
- :param source:
- :return:
- """
- assert not self.status, u"状态更新失败"
- detail = DeviceRentOrderDetail(
- status=True,
- sourceKey=source,
- dateTime=dateTime
- )
- detailList = self.detail or list()
- detailList.append(detail)
- # 只能更新状态为False的
- self.__class__.objects.filter(
- id=self.id,
- status=False
- ).update(
- status=True,
- detail=detailList
- )
- def update_for_fail(self, dateTime, reason=u""):
- """
- 结算失败的状态更新
- 添加支付信息 添加失败原因
- :param dateTime:
- :param reason:
- :return:
- """
- # 订单状态只能从单项 即失败 ---> 成功
- assert not self.status, u"状态更新失败"
- detail = DeviceRentOrderDetail(
- status=False,
- reason=reason,
- dateTime=dateTime
- )
- detailList = self.detail or list()
- detailList.append(detail)
- # 只能更新状态为False的
- self.__class__.objects.filter(
- id=self.id,
- status=False
- ).update(
- status=False,
- detail=detailList
- )
- class EventTimes(Searchable):
- """
- 统计 MQTT 100事件上报的频率
- """
- devNo = StringField(verbose_name=u"设备编号")
- driverCode = StringField(verbose_name=u"驱动编码")
- driverVersion = StringField(verbose_name="驱动版本")
- devTypeCode = StringField(verbose_name=u"设备类型")
- server = StringField(verbose_name=u"服务器")
- times = IntField(verbose_name=u"事件次数")
- date = StringField(verbose_name="统计时间")
- meta = {
- "collection": "EventTimes",
- "db_alias": "logdata"
- }
- class Picture(EmbeddedDocument):
- IsCover = IntField(verbose_name = u'是否为封面 ',default=0) # 是否为封面,0:否,1:是
- PicID = IntField(verbose_name = u'PicID')
- Url = StringField(verbose_name = u'图片网址 ')
- Title = StringField(verbose_name = u'图片标题', default = '')
- TitleForShow = IntField(verbose_name = u'前台界面用于展现的枚举值,不作为业务用')
- SrcType = StringField(verbose_name = u'图片来源',default = '')
-
- class PriceCharging(EmbeddedDocument):
- FeeTime = StringField(verbose_name = u'收费时间段',default = '00:00-24:00')
- ElectricityFee = FloatField(verbose_name = u'站点充电费',default = 0.0000)
- ServiceFee = FloatField(verbose_name = u'站点服务费',default = 0.0000)
- class DiscountPriceCharging(EmbeddedDocument): #站点充电优惠价格 和高德的字段定义统一,这里再重新定义一个
- DiscountTime = StringField(verbose_name = u'时间段描述',default = '00:00-24:00')
- DiscountElectricityFee = FloatField(verbose_name = u'站点充电费优惠价',default = 0.0000)
- DiscountServiceFee = FloatField(verbose_name = u'站点服务费优惠价',default = 0.0000)
- class ChargeTag(EmbeddedDocument):
- tagId = IntField(verbose_name = u'标签Id')
- tagType = IntField(verbose_name = u'标签类型(0:普通标签,1:停车标签)',default = 0)
- tagDesc = StringField(verbose_name = u'标签描述',default = '')
- tagOrder = IntField(verbose_name = u'排序',default = 0)
- tagName = StringField(verbose_name = u'标签名称')
- color = StringField(verbose_name = u'标签颜色')
-
- class SwapGroup(Searchable):
- """
- 互联互通数据
- """
- groupId = StringField(verbose_name="groupId", unique = True)
- StationID = StringField(verbose_name = u"充电站ID", unique = True)
- ownerId = StringField(verbose_name="ownerId")
- swapFlag = BooleanField(verbose_name = u'是否打开互联互通',default = False)
- location = PointField(verbose_name = '经纬度',default = None )
- gcjLng = FloatField(verbose_name = u'gcj版本lng坐标',default = None)
- gcjLat = FloatField(verbose_name = u'gcj版本lat坐标',default = None)
- BusineHours = StringField(verbose_name=u"营业时间",default='00:00-24:00')#eg 10:00-15:00
- SiteGuide = StringField(verbose_name = u'站点引导',default='')
- Construction = IntField(verbose_name = u'建设场所',default = 1)
- SupportOrder = IntField(verbose_name = u'是否支持预约',default = 0)
- Pictures = EmbeddedDocumentListField(document_type = Picture, verbose_name = u'站点照片 ',default=[])
- MatchCars = StringField(verbose_name = u'使用车型描述',default = '')
- ParkInfo = StringField(verbose_name = u'车位楼层及数量描述',default = '')
- StationStatus = IntField(verbose_name = u'站点状态 ',default = 50)# 0:未知 1:建设中 5:关闭下线 6:维护中 50:正常使用
- ParkNums = IntField(verbose_name = u'车位数量 ',default = 0)#
- originalAlternateFeeRemark = StringField(verbose_name = u'慢充原价描述',default = '')
- alternateFeeRemark = StringField(verbose_name = u'慢充价格描述',default = '')
- originalDirectFeeRemark = StringField(verbose_name = u'快充原价描述',default = '')
- directFeeRemark = StringField(verbose_name = u'快充价格描述',default = '')
- PriceChargingInfo = EmbeddedDocumentListField(document_type = PriceCharging, verbose_name = u'站点收费价格明细 ')
- DiscountPriceChargingInfo = EmbeddedDocumentListField(document_type = DiscountPriceCharging, verbose_name = u'站点收费价格明细_优惠价')
- ParkFee = StringField(verbose_name = u'停车费率描述',default=u'')
- RightTag = StringField(verbose_name = u'车主权益',default=u'')
- ChargeTagList = EmbeddedDocumentListField(document_type = ChargeTag, verbose_name = u'站标签列表')
- StationTel = StringField(verbose_name = u'站点电话',default = '')
- ServiceTel = StringField(verbose_name = u'服务电话',default = '')
- StationType = IntField(verbose_name = u'站点类型 ',default = 1)#
- Remark = StringField(verbose_name = u'备注',default = '')
-
- joinedTime = DateTimeField(default = None, verbose_name = u'加入互联互通的时间')
- deviceChangedTime = DateTimeField(default = datetime.datetime.now, verbose_name = u'站下面设备变化的最新时间')
- # 实时统计的部分信息,这里放数据库里,根据设备的事件进行状态更新
- chargeType = IntField(verbose_name = u'充电类型 ',default = 0) # 0:快慢充都有,1:快充、2:慢充
- dcPortsSum = DictField(verbose_name = u'直流快充端口数统计 ',default = {'allPorts':0,'usedPorts':0,'usePorts':0})
- acPortsSum = DictField(verbose_name = u'交流快充端口数统计 ',default = {'allPorts':0,'usedPorts':0,'usePorts':0})
- exceptSum = DictField(verbose_name = u'异常设备统计 ',default = {'offline':0,'fault':0})
- deviceNum = IntField(verbose_name = u'设备数量',default = 0)
-
- @staticmethod
- def make_stationID(groupId):
- h = hashlib.md5()
- h.update(groupId.encode('utf-8'))
- return h.hexdigest()[8:24]
-
- @staticmethod
- def find_one_device_cur_fee(groupId):
- devs = Device.get_devices_by_group([groupId])
- devNo = None
- device = None
- for dev in devs.values():
- device = dev
-
- if dev.majorDeviceType and (u'交流' in dev.majorDeviceType or u'直流' in dev.majorDeviceType):
- devNo = dev['devNo']
- break
- if devNo is None :
- return None
-
- # 各个业务记录的电费和服务费的形式可能不一样,所以放到设备类型中
- box = ActionDeviceBuilder.create_action_device(device)
-
- return box.get_cur_fee()
-
- def get_tag_desc_list(self):
- self.ChargeTagList.sort(key=lambda x:x.tagOrder)
- return [ tag.tagDesc for tag in self.ChargeTagList if tag]
-
- @staticmethod
- def get_tag_desc_list_for_dict(swapInfo):
- swapInfo['ChargeTagList'].sort(key=lambda x:x['tagOrder'])
- result = []
- for tag in swapInfo['ChargeTagList']:
- if not tag:
- continue
- if tag['tagDesc'] and tag['tagName']:
- result.append('%s:%s' %(tag['tagName'],tag['tagDesc']))
- elif tag['tagName']:
- result.append(tag['tagName'])
- return result
-
- @staticmethod
- def recount_devnum(groupId):
- result = 0
- devs = Device.get_devices_by_group([groupId])
- for dev in devs.values():
- if dev.majorDeviceType and (u'交流' in dev.majorDeviceType or u'直流' in dev.majorDeviceType):
- result += 1
- continue
-
- swap = SwapGroup.objects(groupId = groupId).first()
- if swap:
- swap.deviceChangedTime = datetime.datetime.now()
- swap.deviceNum = result
-
- try:
- swap.save()
- except Exception,e:
- return
-
- @staticmethod
- def update_swap_time_and_num(groupId,devNum=0):
- swap = SwapGroup.objects(groupId = groupId).first()
- if swap:
- swap.deviceChangedTime = datetime.datetime.now()
- swap.deviceNum += devNum
- if swap.deviceNum <0:
- swap.deviceNum = 0
- try:
- swap.save()
- except Exception,e:
- return
-
- @staticmethod
- def delete_group(groupId):
- return SwapGroup.objects(groupId = groupId).delete()
-
- @property
- def lng(self):
- return self.location['coordinates'][0]
-
- @property
- def lat(self):
- return self.location['coordinates'][1]
-
- @property
- def pictures(self):
- return [{'IsCover':pic.IsCover,'Url':pic.Url,'Title':pic.Title,'SrcType':pic.SrcType} for pic in self.Pictures]
-
- @staticmethod
- def bd09_to_gcj02(lng, lat):
- """
- 百度坐标系到google坐标系的经纬度转换
- :param lng: 百度经度
- :param lat: 百度维度
- :return:
- """
- if lng == 0.0 or lat == 0.0:
- return lng, lat
- x_pi = 3.14159265358979324 * 3000.0 / 180.0
- x = lng - 0.0065
- y = lat - 0.006
- z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_pi)
- theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_pi)
- gg_lng = z * math.cos(theta)
- gg_lat = z * math.sin(theta)
- return [gg_lng, gg_lat]
-
- @staticmethod
- def get_cur_fee(priceInfoList):
- nowTime = datetime.datetime.now().strftime('%H:%M')
- for priceInfo in priceInfoList:
- tempList = priceInfo['FeeTime'].split('-')
- startTime = tempList[0]
- endTime = tempList[1]
- if nowTime >= startTime and nowTime <= endTime:
- return {'curElecFee':priceInfo['ElectricityFee'],'curServiceFee':priceInfo['ServiceFee']}
-
- return {'curElecFee':'-','curServiceFee':'-'}
-
- @staticmethod
- def get_stats(groupId):
- lcs = Device.get_logicalCode_by_groupId(groupId)
- parts = Part.objects(logicalCode__in = lcs)
- dcAllPorts,dcUsedPorts,acAllPorts,acUsedPorts=0,0,0,0
- for part in parts:
- if part.status not in [Part.Status.IDLE,Part.Status.WORKING]:
- continue
- if part.partType == 'dc':
- dcAllPorts += 1
- if part.status == Part.Status.WORKING:
- dcUsedPorts +=1
- continue
- if part.partType == 'ac':
- acAllPorts += 1
- if part.status == Part.Status.WORKING:
- acUsedPorts +=1
-
- offlineNum,faultNum = 0,0
- for lc in lcs:
- dev = Device.get_dev_by_l(lc)
- if dev is None:
- continue
- if not dev.devType or not dev.devType['majorDeviceType']:
- continue
-
- if not (u'直流' in dev.devType['majorDeviceType'] or u'交流' in dev.devType['majorDeviceType']):
- continue
- if not dev.online:
- offlineNum += 0
- if dev.status == Const.DEV_WORK_STATUS_FAULT:
- faultNum += 1
-
- return {
- 'dcAllPorts':dcAllPorts,'dcUsedPorts':dcUsedPorts,'dcUsePorts':dcAllPorts-dcUsedPorts,
- 'acAllPorts':acAllPorts,'acUsedPorts':acUsedPorts,'acUsePorts':acAllPorts-acUsedPorts,
- 'offline':offlineNum,'fault':faultNum
- }
-
-
|