models.py 226 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. """
  4. web.device.models
  5. ~~~~~~~~~
  6. """
  7. import copy
  8. import re
  9. import time
  10. import uuid
  11. import logging
  12. import datetime
  13. import warnings
  14. import hashlib
  15. import math
  16. import arrow
  17. from django.utils.functional import cached_property
  18. from parse import parse
  19. from pymongo.errors import DuplicateKeyError
  20. from pymongo.results import UpdateResult
  21. from typing import List, Tuple, Dict, Set, Optional, Any, Union, TYPE_CHECKING
  22. from apilib.systypes import IterConstant
  23. import simplejson as json
  24. from bson.objectid import ObjectId
  25. from django.conf import settings
  26. from django.core.cache import cache, caches
  27. from django.utils.module_loading import import_string
  28. from apilib.utils_json import json_dumps, json_loads
  29. from apilib.utils_mongo import format_dot_key
  30. from apps.web.common.models import OperatorLog, MonthlyPackageTemp
  31. from apps.web.core import ROLE
  32. from apps.web.core.exceptions import RentDeviceError, NoGroupFound
  33. from apps.web.core.helpers import ActionDeviceBuilder
  34. from apps.web.core.sysparas import SysParas
  35. from apps.web.dealer.constant import LinkageSwitchEnum
  36. from apps.web.exceptions import UserServerException
  37. from apps.web.helpers import DeviceTypeVisitor
  38. from apps.web.management.models import DeviceReplacement
  39. from library.memcache import Client as memcacheClient
  40. from mongoengine import StringField, DictField, ListField, BooleanField, FloatField, DateTimeField, ValidationError, \
  41. IntField, PointField, EmbeddedDocumentListField, EmbeddedDocument, DoesNotExist, ObjectIdField, QuerySet, \
  42. NotUniqueError, LazyReferenceField, DynamicDocument, DateField, EmbeddedDocumentField, DynamicEmbeddedDocument, \
  43. LongField
  44. from mongoengine.queryset.visitor import Q
  45. from apilib.monetary import VirtualCoin, AccuracyRMB, Percent
  46. from apilib.utils import rec_update_dict, flatten
  47. from apps.web.constant import Const, FAULT_RECORD_STATUS, FAULT_LEVEL, SimStatus, DeviceCmdCode, DeviceOnlineStatus, \
  48. MQTT_TIMEOUT, skip_package_unit_verify_list, skip_package_range_verify_list, skip_package_params_verify_list, \
  49. support_policy_weifule, support_policy_device
  50. from apps.web.device.define import DeviceChannelType, SOFT_VER_NO_PULSE_RE_LIST, PULSE_DEV_TYPE_RE, BT_DEV_TYPE_RE, \
  51. SOFT_VER_ONLY_PULSE_RE_LIST, TCP_DEV_TYPE_RE
  52. from apps.web.common.errors import NotInChoices
  53. from apps.web.core.db import Searchable, MonetaryField, AccuracyMoneyField, VirtualCoinField
  54. from apps.web.core.networking import MessageSender
  55. from apps.web.device.utils import device_online_cache_key, device_control_cache_key, device_warning_cache_key
  56. from apilib.monetary import RMB
  57. if TYPE_CHECKING:
  58. from apps.web.dealer.models import Dealer, DealerDict
  59. from apps.web.eventer import EventBuilder
  60. from apps.web.core.adapter.base import SmartBox
  61. from apps.web.common.models import UserSearchable
  62. from apps.web.user.models import ConsumeRecord
  63. logger = logging.getLogger(__name__)
  64. class GroupCacheMgr(object):
  65. """
  66. 地址组
  67. """
  68. @staticmethod
  69. def __group_ids_of_dealer_cache_key(dealer_id):
  70. # type:(str)->str
  71. """
  72. 经销商拥有的地址缓存
  73. :type dealer_id:
  74. """
  75. return 'dealer_group_ids_{ownerId}'.format(ownerId = dealer_id)
  76. @staticmethod
  77. def __group_ids_of_partner_cache_key(partner_id):
  78. # type:(str)->str
  79. """
  80. 合伙人拥有的地址缓存
  81. :type partner_id: object
  82. """
  83. return 'partner_group_ids_{partnerId}'.format(partnerId = partner_id)
  84. @classmethod
  85. def __group_cache_key(cls, group_id):
  86. return 'group_{id}'.format(id = group_id)
  87. @classmethod
  88. def __many_group_cache_key(cls, group_id_list):
  89. return [cls.__group_cache_key(group_id) for group_id in group_id_list]
  90. @classmethod
  91. def __group_id_from_group_cache_key(cls, group_cache_key):
  92. # type: (str)->str
  93. return group_cache_key.split('_')[1]
  94. @staticmethod
  95. def __default_group_id_key(dealer_id):
  96. return '{}_default_group_id'.format(dealer_id)
  97. @classmethod
  98. def invalid_group_cache(cls, groupIds):
  99. # type: (list)->None
  100. cache.delete_many(cls.__many_group_cache_key(groupIds))
  101. @classmethod
  102. def set_group_cache(cls, group_id, value):
  103. # type: (str, GroupDict)->None
  104. cache.set(cls.__group_cache_key(group_id), json_dumps(value, serialize_type = True))
  105. @classmethod
  106. def get_group_cache(cls, group_id):
  107. # type: (str)->Union[GroupDict, None]
  108. cache_value = cache.get(cls.__group_cache_key(group_id))
  109. if cache_value:
  110. return GroupDict(json_loads(cache_value))
  111. else:
  112. return None
  113. @classmethod
  114. def get_many_group_cache(cls, group_id_list):
  115. # type: (list)->dict
  116. group_id_key_list = cls.__many_group_cache_key(group_id_list)
  117. rv = {}
  118. for group_cache_key, value in cache.get_many(group_id_key_list).iteritems():
  119. group_id = cls.__group_id_from_group_cache_key(group_cache_key)
  120. rv[group_id] = GroupDict(json.loads(value))
  121. return rv
  122. @classmethod
  123. def invalid_group_ids_of_dealer_cache(cls, dealer_id):
  124. # type: (str)->None
  125. cache.delete(cls.__group_ids_of_dealer_cache_key(dealer_id))
  126. @classmethod
  127. def set_group_ids_of_dealer_cache(cls, dealer_id, value):
  128. # type: (str, list)->None
  129. cache.set(cls.__group_ids_of_dealer_cache_key(dealer_id), value)
  130. @classmethod
  131. def get_group_ids_of_dealer_cache(cls, dealer_id):
  132. # type: (str)->Union[list, None]
  133. return cache.get(cls.__group_ids_of_dealer_cache_key(dealer_id))
  134. @classmethod
  135. def invalid_group_ids_of_partner_cache(cls, partner_id):
  136. # type: (str)->None
  137. cache.delete(cls.__group_ids_of_partner_cache_key(partner_id))
  138. @classmethod
  139. def set_group_ids_of_partner_cache(cls, partner_id, value):
  140. # type: (str, list)->None
  141. cache.set(cls.__group_ids_of_partner_cache_key(partner_id), value)
  142. @classmethod
  143. def get_group_ids_of_partner_cache(cls, partner_id):
  144. # type: (str)->Union[list, None]
  145. return cache.get(cls.__group_ids_of_partner_cache_key(partner_id))
  146. @classmethod
  147. def invalid_group_ids_of_partner_and_dealer_cache(cls, owner_id):
  148. # type: (str)->None
  149. cache.delete_many([cls.__group_ids_of_dealer_cache_key(owner_id),
  150. cls.__group_ids_of_partner_cache_key(owner_id)])
  151. @classmethod
  152. def get_default_group_id(cls, dealer_id):
  153. # type: (str)->str
  154. return cache.get(cls.__default_group_id_key(dealer_id))
  155. @classmethod
  156. def set_default_group_id(cls, dealer_id, group_id):
  157. return cache.set(cls.__default_group_id_key(dealer_id), group_id)
  158. class DeviceControlInfo(Searchable):
  159. devNo = StringField(verbose_name = u"设备编号", min_length = 1, unique = True)
  160. value = StringField(verbose_name = u'设备控制信息', default = '')
  161. meta = {
  162. 'collection': 'device_control_info',
  163. 'db_alias': 'logdata'
  164. }
  165. @staticmethod
  166. def get(devNo):
  167. try:
  168. obj = DeviceControlInfo.objects.get(devNo = devNo)
  169. result = json.loads(obj.value)
  170. return result
  171. except DoesNotExist, e:
  172. pass
  173. return {}
  174. @staticmethod
  175. def set(devNo, valueDict):
  176. try:
  177. value = json_dumps(valueDict)
  178. DeviceControlInfo.get_collection().update({'devNo': devNo}, {'$set': {'devNo': devNo, 'value': value}},
  179. upsert = True)
  180. except Exception, e:
  181. logger.info('set device=%s json e=%s' % (devNo, e))
  182. @staticmethod
  183. def delete(devNo):
  184. try:
  185. DeviceControlInfo.get_collection().remove({'devNo': devNo})
  186. except Exception, e:
  187. logger.info('remove device=%s control info e=%s' % (devNo, e))
  188. class GroupLinkageSwitch(DynamicEmbeddedDocument):
  189. """
  190. 设备组开关项
  191. """
  192. chargeInsurance = BooleanField(default=False, verbose_name=u"充电险开关")
  193. def to_dict(self):
  194. return {"chargeInsurance": self.chargeInsurance}
  195. class Group(Searchable):
  196. ownerId = StringField(verbose_name = "所有者", default = "")
  197. groupName = StringField(verbose_name = "名称", default = "")
  198. address = StringField(verbose_name = "地址", default = "")
  199. districtId = StringField(verbose_name = "地域", default = "")
  200. addressType = StringField(verbose_name = "类型", default = "")
  201. ruleDict = DictField(verbose_name = "充值规则", default = Const.DEFAULT_DISCOUNT_RULE)
  202. cardRuleDict = DictField(verbose_name = "卡充值规则", default = {})
  203. partnerList = ListField(verbose_name = "合伙人", default = [])
  204. isDefault = BooleanField(verbose_name = "是否默认地址", default = True)
  205. isFree = BooleanField(verbose_name = "是否供免费使用", default = False)
  206. # 功能形按钮
  207. popPriceDescriptionButton = BooleanField(verbose_name = "扫码后是否弹出计费规则", default = False)
  208. beforeCharge = BooleanField(verbose_name = "强制充值", default = False)
  209. dateTimeAdded = DateTimeField(default = datetime.datetime.now, verbose_name = '添加进来的时间')
  210. dateTimeUpdated = DateTimeField(default = datetime.datetime.now, verbose_name = '更新时间')
  211. country = StringField(verbose_name = '镇村', default = '')
  212. town = StringField(verbose_name = '镇区', default = '')
  213. village = StringField(verbose_name = '村居委会', default = '')
  214. monthlyPackage = LazyReferenceField(verbose_name = "包月套餐", document_type = MonthlyPackageTemp)
  215. currencyGroup = StringField(verbose_name = u"地址标签", default = '')
  216. maxVCard = IntField(verbose_name = u"可发售的虚拟卡的数量", default = 9999)
  217. otherConf = DictField(verbose_name = u'用于扩充记录', default = {'elecFee': 1.0, 'devElec': 0.2})
  218. linkageSwitch = EmbeddedDocumentField(document_type=GroupLinkageSwitch, verbose_name="开关", default=GroupLinkageSwitch)
  219. swapFlag = BooleanField(verbose_name = "互联互通标记", default = False)
  220. meta = {
  221. "collection": "Group",
  222. "db_alias": "default",
  223. 'indexes': [
  224. {
  225. 'fields': ['ownerId', 'groupName'],
  226. 'unique': True
  227. }
  228. ],
  229. }
  230. CacheMgr = GroupCacheMgr
  231. def __repr__(self):
  232. return '<Group id=%s>' % (self.id,)
  233. @property
  234. def groupId(self):
  235. """
  236. 兼容GroupDict接口
  237. :return:
  238. """
  239. return str(self.id)
  240. @property
  241. def monthlyRule(self):
  242. if self.monthlyPackage:
  243. package = self.monthlyPackage.fetch() # type: MonthlyPackageTemp
  244. else:
  245. from apps.web.dealer.models import Dealer
  246. dealer = Dealer.objects.get(id = self.ownerId)
  247. package = dealer.defaultMonthlyPackage # type: MonthlyPackageTemp
  248. if package.saleable:
  249. return package
  250. return None
  251. @monthlyRule.setter
  252. def monthlyRule(self, package):
  253. self.update(monthlyPackage = package)
  254. # 覆写. 需要对ruleDict参数进行一次转换
  255. def update(self, **kwargs):
  256. if 'ruleDict' in kwargs:
  257. rule_dict = kwargs.pop('ruleDict')
  258. kwargs.update({'ruleDict': format_dot_key(rule_dict)})
  259. if 'cardRuleDict' in kwargs:
  260. card_rule_dict = kwargs.pop('cardRuleDict')
  261. kwargs.update({'cardRuleDict': format_dot_key(card_rule_dict)})
  262. update_result = super(Group, self).update(full_result = True, **kwargs) # type: UpdateResult
  263. created = bool(update_result.upserted_id)
  264. updated = bool((not update_result.upserted_id) and update_result.matched_count and update_result.modified_count)
  265. if updated:
  266. self.CacheMgr.invalid_group_cache([str(self.id)])
  267. return {'created': created, 'updated': updated, 'groupId': update_result.upserted_id} if created else {
  268. 'created': created, 'updated': updated, 'groupId': str(self.id)
  269. }
  270. def delete(self, signal_kwargs = None, **write_concern):
  271. super(Group, self).delete(signal_kwargs, **write_concern)
  272. self.CacheMgr.invalid_group_cache([str(self.id)])
  273. @property
  274. def cached(self):
  275. return self.get_group(str(self.id))
  276. @property
  277. def format_rule_dict(self):
  278. return format_dot_key(self.ruleDict, to_dot = True)
  279. @property
  280. def format_card_dict(self):
  281. return format_dot_key(self.cardRuleDict, to_dot = True)
  282. @classmethod
  283. def __update_group(cls, group, **update):
  284. # type: (Group, Dict)->str
  285. """
  286. 实现比较别扭,利用以下几个事实:
  287. 如果是添加一个地址, old_if_default == new_if_default, old_partner_list == new_partner_list
  288. 如果更新一个地址,但是isDefault不更新, old_if_default == new_if_default
  289. 如果更新一个地址,但是partnerList不更新,old_partner_list == new_partner_list
  290. 注意利用update等接口,mongoengine不用更新model。这里也不想reload,直接利用传入参数来判断
  291. :param group:
  292. :param update:
  293. :return:
  294. """
  295. old_if_default = group.isDefault
  296. old_partner_list = group.partnerList
  297. new_if_default = update.get(Group.isDefault.name, old_if_default)
  298. new_partner_list = update.get(Group.partnerList.name, old_partner_list)
  299. update_result = group.update(upsert = True, **update) # type: dict
  300. try:
  301. group_id = update_result['groupId']
  302. if (update_result['created'] and new_if_default) or (
  303. update_result['updated'] and new_if_default and new_if_default != old_if_default):
  304. objs = Group.objects(ownerId = group.ownerId, id__ne = group_id, isDefault = True).filter()
  305. for obj in objs:
  306. try:
  307. obj.update(isDefault = False)
  308. except Exception as e:
  309. # 当添加第一个组的时候,会取不到旧的组
  310. logger.debug('adding first group %s' % e)
  311. return group_id
  312. finally:
  313. if update_result['created']:
  314. cls.CacheMgr.invalid_group_ids_of_dealer_cache(group.ownerId)
  315. for partner in new_partner_list:
  316. cls.CacheMgr.invalid_group_ids_of_partner_cache(partner['id'])
  317. else:
  318. if new_if_default and new_if_default != old_if_default:
  319. cls.CacheMgr.set_default_group_id(group.ownerId, str(group.id))
  320. old_partner_ids = set([partner['id'] for partner in old_partner_list])
  321. new_partner_ids = set([partner['id'] for partner in new_partner_list])
  322. need_invalid_partner_ids = old_partner_ids ^ new_partner_ids
  323. for partner_id in need_invalid_partner_ids:
  324. cls.CacheMgr.invalid_group_ids_of_partner_cache(partner_id)
  325. @classmethod
  326. def update_group(cls, group_id, **payload):
  327. group = Group.objects(id=str(group_id)).first()
  328. if not group:
  329. logger.debug('failed to get group %s' % (group_id,))
  330. return False, u'地址不存在,请更新后重试', group_id
  331. if 'ownerId' in payload:
  332. ownerId = payload.pop('ownerId')
  333. if ownerId != group.ownerId:
  334. logger.error('set ownerId<{}> != groupOwnerId<{}>'.format(ownerId, group.ownerId))
  335. return False, u'非经销商所属地址,请联系客服', group_id
  336. try:
  337. group_id = Group.__update_group(group, **payload)
  338. return True, 'success', group_id
  339. except NoGroupFound, e:
  340. logger.exception('group is not exist. groupId = %s, dealerId = %s' % (group_id, group.ownerId))
  341. return False, u'组不存在,请更新后再试', group_id
  342. except Exception as e:
  343. logger.exception(
  344. 'save group error. exception = %s, groupId = %s, dealerId=%s' % (e, group_id, group.ownerId))
  345. return False, u'更新失败,请重试', group_id
  346. @classmethod
  347. def add_group(cls, ownerId, name, districtId, address, addressType, isDefault, discountRuleDict, discountCardRuleDict, country, tag, beforeCharge):
  348. objs = cls.objects(ownerId=ownerId) # type: QuerySet
  349. if objs.count() >= 2000:
  350. return False, u'最多只能保存2000个地址', None
  351. group = objs.filter(groupName=name).first()
  352. if group:
  353. return False, u'相同名称的地址已经存在', None
  354. try:
  355. update = {
  356. 'districtId': districtId,
  357. 'address': address,
  358. 'addressType': addressType,
  359. 'isDefault': isDefault,
  360. 'ruleDict': discountRuleDict,
  361. 'cardRuleDict': discountCardRuleDict,
  362. 'country': country,
  363. 'tag': tag,
  364. 'beforeCharge': beforeCharge
  365. }
  366. group = cls(
  367. ownerId=ownerId,
  368. groupName=name
  369. )
  370. group_id = cls.__update_group(group, **update)
  371. return True, 'success', group_id
  372. except Exception as e:
  373. logger.exception('add address error=%s' % e)
  374. return False, u'保存地址错误', None
  375. @classmethod
  376. def delete_Group(cls, ownerId, groupId):
  377. try:
  378. group = cls.objects(id = str(groupId)).first() # type: Group
  379. if not group:
  380. return False
  381. else:
  382. group.delete()
  383. cls.CacheMgr.invalid_group_ids_of_dealer_cache(ownerId)
  384. for partner in group.partnerList:
  385. cls.CacheMgr.invalid_group_ids_of_partner_cache(partner['id'])
  386. return True
  387. except Exception as e:
  388. logger.exception(e)
  389. return False
  390. @classmethod
  391. def __cache_and_get_group(cls, groupId):
  392. # type: (str)->Union[GroupDict, None]
  393. try:
  394. group = cls.objects(id = ObjectId(groupId)).first() # type: Group
  395. if not group:
  396. return None
  397. partnerDict = {}
  398. for partner in group.partnerList:
  399. partnerDict[partner['id']] = partner
  400. newRuleDict = format_dot_key(group['ruleDict'], to_dot = True)
  401. newCardRuleDict = format_dot_key(group["cardRuleDict"], to_dot = True)
  402. value = GroupDict({
  403. 'groupId': str(group.id),
  404. 'address': group.address,
  405. 'districtId': group.districtId,
  406. 'addressType': group.addressType,
  407. 'isDefault': group.isDefault,
  408. 'groupName': group.groupName,
  409. 'ruleDict': newRuleDict,
  410. 'cardRuleDict': newCardRuleDict,
  411. 'partnerDict': partnerDict,
  412. 'ownerId': group.ownerId,
  413. 'isFree': group.isFree,
  414. 'beforeCharge': group.beforeCharge,
  415. 'country': group.country,
  416. 'town': group.town,
  417. 'village': group.village,
  418. 'dateTimeAdded': group.dateTimeAdded,
  419. 'currencyGroup': group.currencyGroup,
  420. 'maxVCard': group.maxVCard,
  421. 'linkageSwitch': group.linkageSwitch.to_dict(),
  422. 'swapFlag': group.swapFlag,
  423. 'popPriceDescriptionButton': group.popPriceDescriptionButton,
  424. "otherConf": group.otherConf
  425. })
  426. cls.CacheMgr.set_group_cache(group_id = groupId, value = value)
  427. return value
  428. except Exception as e:
  429. logger.exception('get group = %s, error = %s' % (groupId, e))
  430. return None
  431. @classmethod
  432. def get_group_ids_of_partner(cls, partner_id):
  433. partner_group_list = cls.CacheMgr.get_group_ids_of_partner_cache(partner_id = partner_id)
  434. if partner_group_list:
  435. return partner_group_list
  436. partner_group_list = []
  437. try:
  438. rcds = Group.get_collection().find({'partnerList.id': partner_id})
  439. for rcd in rcds:
  440. partner_group_list.append(str(rcd['_id']))
  441. cls.CacheMgr.set_group_ids_of_partner_cache(partner_id, partner_group_list)
  442. except Exception, e:
  443. logger.exception('get partner group list error=%s' % e)
  444. return partner_group_list
  445. # 添加搜索(先筛选缓存,再找数据库)
  446. @classmethod
  447. def search_group_ids_of_partner(cls, partner_id, searchKey = None):
  448. partner_group_list = cls.CacheMgr.get_group_ids_of_partner_cache(partner_id = partner_id)
  449. if partner_group_list:
  450. if searchKey:
  451. for item in cls.get_groups_by_group_ids(partner_group_list).values():
  452. if searchKey.upper() not in item[u'groupName'].upper():
  453. partner_group_list.remove(item[u'groupId'])
  454. return partner_group_list
  455. partner_group_list = []
  456. try:
  457. rcds = Group.get_collection().find({u'partnerList.id': partner_id})
  458. for rcd in rcds:
  459. if searchKey.upper() in rcd[u'groupName'].upper():
  460. partner_group_list.append(str(rcd[u'_id']))
  461. except Exception, e:
  462. logger.exception('get partner group list error=%s' % e)
  463. return partner_group_list
  464. @classmethod
  465. def get_group_ids_of_dealer(cls, dealer_id):
  466. dealer_group_list = cls.CacheMgr.get_group_ids_of_dealer_cache(dealer_id)
  467. if dealer_group_list:
  468. assert isinstance(dealer_group_list, list), 'adrList has to be a list, %s was given, ownerId=%s' % (
  469. dealer_group_list, dealer_id)
  470. return dealer_group_list
  471. dealer_group_list = []
  472. try:
  473. objs = Group.objects.filter(ownerId = dealer_id)
  474. for obj in objs:
  475. dealer_group_list.append(str(obj.id))
  476. if dealer_group_list:
  477. cls.CacheMgr.set_group_ids_of_dealer_cache(dealer_id = dealer_id, value = dealer_group_list)
  478. else:
  479. logger.debug('groups of dealer<id={}> is zero.'.format(dealer_id))
  480. except Exception as e:
  481. logger.exception('get group list error=%s' % e)
  482. return dealer_group_list
  483. # 添加搜索(先筛选缓存,再找数据库)
  484. @classmethod
  485. def search_group_ids_of_dealer(cls, dealer_id, searchKey = None):
  486. dealer_group_list = cls.CacheMgr.get_group_ids_of_dealer_cache(dealer_id)
  487. if dealer_group_list is not None:
  488. if searchKey:
  489. for item in cls.get_groups_by_group_ids(dealer_group_list).values():
  490. if searchKey.upper() not in item['groupName'].upper():
  491. dealer_group_list.remove(item['groupId'])
  492. assert isinstance(dealer_group_list, list), 'adrList has to be a list, %s was given, ownerId=%s' % (
  493. dealer_group_list, dealer_id)
  494. return dealer_group_list
  495. dealer_group_list = []
  496. try:
  497. objs = Group.objects.filter(ownerId = dealer_id, groupName__contains = searchKey)
  498. for obj in objs:
  499. dealer_group_list.append(str(obj.id))
  500. except Exception, e:
  501. logger.exception('get group list error=%s' % e)
  502. return dealer_group_list
  503. @classmethod
  504. def get_group_ids_of_dealer_and_partner(cls, ownerId):
  505. return cls.get_group_ids_of_dealer(ownerId) + cls.get_group_ids_of_partner(ownerId)
  506. @classmethod
  507. def get_groups_by_group_ids(cls, groupIds):
  508. # type: (list)->dict
  509. value_dict = cls.CacheMgr.get_many_group_cache(group_id_list = groupIds)
  510. left_group_ids = list(set(groupIds) - set(value_dict.keys()))
  511. for group_id in left_group_ids:
  512. group_dict = cls.__cache_and_get_group(group_id)
  513. if group_dict:
  514. value_dict[group_id] = group_dict
  515. return value_dict
  516. @classmethod
  517. def get_groups_of_dealer(cls, dealerId):
  518. return cls.get_groups_by_group_ids(cls.get_group_ids_of_dealer(dealerId)).values()
  519. @classmethod
  520. def get_dealer_group(cls, dealerId, **kwargs):
  521. group = cls.objects.filter(ownerId = dealerId, **kwargs).first()
  522. return group
  523. @classmethod
  524. def get_group(cls, groupId):
  525. # type: (str)->GroupDict
  526. """
  527. 没有找到组返回None
  528. """
  529. if not groupId: return None
  530. group_dict = cls.CacheMgr.get_group_cache(groupId)
  531. if group_dict:
  532. return group_dict
  533. else:
  534. return cls.__cache_and_get_group(groupId)
  535. @classmethod
  536. def get_default_group_id(cls, dealer_id):
  537. group_id = cls.CacheMgr.get_default_group_id(dealer_id)
  538. if not group_id:
  539. default_group = Group.objects(ownerId = dealer_id, isDefault = True).first()
  540. if default_group:
  541. group_id = str(default_group.id)
  542. cls.CacheMgr.set_default_group_id(dealer_id, group_id)
  543. return group_id
  544. @classmethod
  545. def get_default_group(cls, dealer_id):
  546. default_group_id = cls.get_default_group_id(dealer_id)
  547. if not default_group_id:
  548. return None
  549. return cls.get_group(default_group_id)
  550. @classmethod
  551. def get_groupName_by_logicalCode(cls, logicalCode):
  552. groupId = Device.objects(logicalCode = logicalCode).first().groupId
  553. if groupId != '':
  554. return Group.get_group(groupId)['groupName']
  555. else:
  556. return None
  557. @classmethod
  558. def get_group_ids_without_partner(cls, ownerId):
  559. gs = cls.objects(ownerId = ownerId)
  560. return [str(_.id) for _ in gs if _.partnerList is None or _.partnerList == []]
  561. @classmethod
  562. def get_all_partner_ids(cls, dealerId):
  563. groups = cls.objects.filter(ownerId = dealerId)
  564. partners = set()
  565. for _group in groups:
  566. if _group.partnerList:
  567. for _partner in _group.partnerList:
  568. partners.add(_partner["id"])
  569. return partners
  570. @classmethod
  571. def get_lawful_partner_ids(cls, dealerId):
  572. """获取经销商的所有 有效的合伙人Id"""
  573. groups = cls.objects.filter(ownerId = dealerId)
  574. partners = list()
  575. for _group in groups:
  576. if not _group.partnerList:
  577. continue
  578. for _partner in _group.partnerList:
  579. if float(_partner["percent"]) <= 0:
  580. continue
  581. partners.append(_partner["id"])
  582. return set(partners)
  583. @classmethod
  584. def check_virtual_card_number(cls, groupId):
  585. from apps.web.user.models import UserVirtualCard
  586. vCard = UserVirtualCard.objects.filter(
  587. groupIds__in = [groupId],
  588. expiredTime__gt = datetime.datetime.now()
  589. )
  590. group = cls.objects.get(id = groupId)
  591. return group.maxVCard > vCard.count()
  592. @classmethod
  593. def invalid_group_cache(cls, groupIds):
  594. cls.CacheMgr.invalid_group_cache(groupIds)
  595. @classmethod
  596. def is_currency_mode_group(cls, groupId1, groupId2):
  597. # type: (str,str) -> bool
  598. if groupId1 == groupId2:
  599. return True
  600. group1 = cls.get_group(groupId1)
  601. group2 = cls.get_group(groupId2)
  602. if not all([group1, group2]): # 没有组
  603. return False
  604. dealerId1 = group1.get('ownerId')
  605. dealerId2 = group2.get('ownerId')
  606. if dealerId1 != dealerId2: # 不是一个经销商
  607. return False
  608. from apps.web.dealer.models import Dealer
  609. dealer = Dealer.objects.filter(id = dealerId1).first()
  610. if not dealer:
  611. return False
  612. currency_mode = dealer.currency_mode
  613. if currency_mode == 'allYes':
  614. return True
  615. elif currency_mode == 'allNo':
  616. return False
  617. elif currency_mode == 'asGroup':
  618. currencyGroup1 = group1.get('currencyGroup') # 此处默认为""
  619. currencyGroup2 = group2.get('currencyGroup')
  620. if currencyGroup1 == currencyGroup2: # 在同一个通用规则下
  621. return True
  622. else:
  623. return False
  624. elif currency_mode == '': # 默认不通用
  625. return False
  626. else:
  627. pass
  628. def get_linkage_switch(self):
  629. return {
  630. LinkageSwitchEnum.CHARGE_INSURANCE: self.linkageSwitch.chargeInsurance
  631. }
  632. def turn_on(self, category):
  633. """
  634. 打开保险的开关
  635. """
  636. if category == LinkageSwitchEnum.CHARGE_INSURANCE:
  637. self.linkageSwitch.chargeInsurance = True
  638. self.update(linkageSwitch__chargeInsurance=self.linkageSwitch.chargeInsurance)
  639. self.invalid_group_cache([str(self.id)])
  640. def turn_off(self, category):
  641. """
  642. 关闭保险的开关
  643. """
  644. if category == LinkageSwitchEnum.CHARGE_INSURANCE:
  645. self.linkageSwitch.chargeInsurance = False
  646. self.update(linkageSwitch__chargeInsurance=self.linkageSwitch.chargeInsurance)
  647. self.invalid_group_cache([str(self.id)])
  648. class DeviceDefaultSetting(Searchable):
  649. """默认值修改,如默认清洗套餐等, 方便配置管理"""
  650. devType = StringField(verbose_name = "设备类型", unique = True)
  651. packages = ListField(DictField(), verbose_name = "套餐", default = [])
  652. meta = {"collection": "DeviceDefaultSetting", "db_alias": "default"}
  653. class MajorDeviceType(Searchable):
  654. name = StringField(verbose_name = u'主类型名称', unique = True)
  655. createdTime = DateTimeField(default = datetime.datetime.now, verbose_name = u'添加进来的时间')
  656. search_fields = ('name',)
  657. meta = {'collection': 'major_device_type', 'db_alias': 'default'}
  658. def __repr__(self): return '<MajorDeviceType name=%s>' % (self.name,)
  659. def to_dict(self):
  660. return {
  661. 'name': self.name,
  662. }
  663. class BillAsServiceFeature(dict):
  664. @property
  665. def support(self):
  666. return self.get('support', False)
  667. @property
  668. def on(self):
  669. if not self.support:
  670. return False
  671. return self.get('on', False)
  672. @property
  673. def elec_charge(self):
  674. return RMB(self.get('elecCharge', 0))
  675. @property
  676. def service_charge(self):
  677. return RMB(self.get('serviceCharge', 0))
  678. @property
  679. def charge_unit(self):
  680. if self.support:
  681. return {
  682. 'elecCharge': self.elec_charge,
  683. 'serviceCharge': self.service_charge
  684. }
  685. else:
  686. return None
  687. def current_elec_fee(self, consumeMoney):
  688. return RMB(float(consumeMoney) / float(self.elec_charge + self.service_charge) * float(self.elec_charge))
  689. def current_service_fee(self, consumeMoney):
  690. return RMB(float(consumeMoney) / float(self.elec_charge + self.service_charge) * float(self.service_charge))
  691. class DeviceType(Searchable):
  692. name = StringField(verbose_name = u'设备类型名称(经销商,代理商,厂商看到的名称)')
  693. alias = StringField(verbose_name = u'设备类型别名(扫码用户看到的类型)')
  694. code = StringField(verbose_name = '设备编码')
  695. online = BooleanField(verbose_name = '是否为在线设备')
  696. package = ListField(DictField(), verbose_name = '套餐', default = [])
  697. # : 有部分设备,如售货机,套餐的时间属性,并无意义,通过此字段可以跳过对时间的处理
  698. timeBased = BooleanField(verbose_name = '计量是否以时间为基准', default = True)
  699. stock = BooleanField(verbose_name = '是否库存', default = False)
  700. instructions = StringField(default = '', verbose_name = '使用说明')
  701. dateTimeAdded = DateTimeField(default = datetime.datetime.now, verbose_name = '添加进来的时间')
  702. unit = StringField(verbose_name = '消费单位', default = u'分钟') # 消费单位,多少钱**包/分钟/升/度
  703. payableWhileBusy = BooleanField(verbose_name = u'是否支持端口正在使用时追加充值', default = False)
  704. displayCardCharge = BooleanField(verbose_name = u'是否支持套餐页面显示充卡入口', default = False)
  705. #: 每次注册累加,通过权重来排序
  706. popularity = IntField(verbose_name = '展示权重', default = 0)
  707. agentId = StringField(verbose_name = '所属代理商')
  708. managerId = StringField(verbose_name = '所属厂商')
  709. supportDiagnostics = BooleanField(verbose_name = u'是否支持自主调测', default = False)
  710. supportVirtualCard = BooleanField(verbose_name = u'是否支持虚拟卡的使用', default = True)
  711. supportIcCardcharge = BooleanField(verbose_name = u'是否支持IC卡的充值', default = True)
  712. majorDeviceType = StringField(verbose_name = u'主类型名称', null = False)
  713. autoRefundEnable = BooleanField(verbose_name = u'是否支持自动退款', default = True)
  714. finishedMessageTemplateDict = DictField(verbose_name = u'结束推送信息模板字典', default = {})
  715. finishedReasonDict = DictField(verbose_name = u'结束原因类型字典', default = {})
  716. servicesButtonDict = DictField(verbose_name = u'正在服务显示按钮字典', default = {})
  717. features = DictField(verbose_name = u'设备类型特性', default = {})
  718. dailyRent = DictField(verbose_name=u"设备类型的日租特性", default={})
  719. extraInfo = DictField(verbose_name=u"特定设备类型的特殊自定义信息", default={})
  720. meta = {'collection': 'DeviceType', 'db_alias': 'default', 'unique_together': {'name', 'agentId'}}
  721. def __repr__(self):
  722. return '<DeviceType(code=%s)>' % (self.code,)
  723. @classmethod
  724. def all(cls, agentId):
  725. return [_.to_dict() for _ in cls.objects(agentId = str(agentId)).all()]
  726. @classmethod
  727. def most_popular(cls):
  728. return cls.objects().order_by('-popularity').first()
  729. def to_dict(self):
  730. result = {
  731. 'id': str(self.id),
  732. 'name': self.name,
  733. 'alias': self.alias or self.name,
  734. 'code': self.code,
  735. 'online': self.online,
  736. 'package': self.package,
  737. 'timeBased': self.timeBased,
  738. 'stock': self.stock,
  739. 'unit': self.unit,
  740. 'instructions': self.instructions,
  741. 'payableWhileBusy': self.payableWhileBusy,
  742. 'majorDeviceType': self.majorDeviceType,
  743. 'supportDiagnostics': self.supportDiagnostics,
  744. 'supportVirtualCard': self.supportVirtualCard,
  745. 'features': self.features,
  746. 'autoRefundEnable': self.autoRefundEnable,
  747. 'displayCardCharge': self.displayCardCharge,
  748. 'extraInfo': dict()
  749. }
  750. for _k, _v in self.extraInfo.items():
  751. result['extraInfo'].update({_k: _v})
  752. return result
  753. @property
  754. def dict_for_register_device(self):
  755. return {
  756. 'id': str(self.id),
  757. 'name': self.name,
  758. 'code': self.code,
  759. 'online': self.online,
  760. 'timeBased': self.timeBased,
  761. 'stock': self.stock,
  762. 'unit': self.unit,
  763. 'instructions': self.instructions,
  764. 'payableWhileBusy': self.payableWhileBusy,
  765. 'majorDeviceType': self.majorDeviceType,
  766. 'supportDiagnostics': self.supportDiagnostics,
  767. 'supportVirtualCard': self.supportVirtualCard,
  768. 'features': self.features,
  769. 'autoRefundEnable': self.autoRefundEnable,
  770. 'displayCardCharge': self.displayCardCharge
  771. }
  772. @classmethod
  773. def get_by_ids(cls, ids):
  774. return cls.objects.filter(id__in = ids)
  775. @classmethod
  776. def get_by_id(cls, id_):
  777. try:
  778. return cls.objects.filter(id = id_).first()
  779. except ValidationError:
  780. logger.exception('')
  781. return None
  782. @classmethod
  783. def get_services_button(cls, id):
  784. return cls.objects(id = id).first().servicesButtonDict
  785. @property
  786. def supportRent(self):
  787. """
  788. 设备类型是否支持租售
  789. :return:
  790. """
  791. return bool(self.dailyRent)
  792. @property
  793. def rentTerm(self):
  794. """
  795. 设备类型的租期
  796. :return:
  797. """
  798. if not self.supportRent: raise RentDeviceError(u"该设备类型不支持出租")
  799. return self.dailyRent["rentTerm"]
  800. @property
  801. def rentMoney(self):
  802. """
  803. 该设备类型的单日租金
  804. :return:
  805. """
  806. if not self.supportRent: raise RentDeviceError(u"该设备类型不支持出租")
  807. return self.dailyRent["rentMoney"]
  808. @property
  809. def maxWaitForActive(self):
  810. if not self.supportRent: raise RentDeviceError(u"该设备类型不支持出租")
  811. return self.dailyRent["maxWaitForActive"]
  812. @property
  813. def bill_as_service_feature(self):
  814. # type: ()->BillAsServiceFeature
  815. return BillAsServiceFeature(self.features.get('billAsService', {}))
  816. @classmethod
  817. def is_pulse_device_type(cls, device_type_code):
  818. if not device_type_code:
  819. return False
  820. if device_type_code in [Const.DEVICE_TYPE_CODE_HP_GATE, Const.DEVICE_TYPE_CODE_QUICK_CHARGE]:
  821. return False
  822. if PULSE_DEV_TYPE_RE.match(device_type_code):
  823. return True
  824. else:
  825. return False
  826. @classmethod
  827. def is_bt_device_type(cls, device_type_code):
  828. if not device_type_code:
  829. return False
  830. if BT_DEV_TYPE_RE.match(device_type_code):
  831. return True
  832. else:
  833. return False
  834. @classmethod
  835. def find_candidate(cls, devObj, dealer):
  836. # type: (Device, Dealer)->Tuple[List, List]
  837. def is_only_pulse_soft_version(softVer):
  838. for item in SOFT_VER_ONLY_PULSE_RE_LIST:
  839. if item.match(softVer):
  840. return True
  841. else:
  842. return False
  843. def is_hw_support_pulse(device):
  844. support = True
  845. if device.softVer.startswith('v6.'):
  846. if device.hwVer in ['2gsck', 'pureuart', 'flb', '4gcat1dual']:
  847. support = False
  848. elif device.mf == 'Quectel':
  849. pass
  850. else:
  851. for item in SOFT_VER_NO_PULSE_RE_LIST:
  852. if item.match(device.softVer):
  853. support = False
  854. break
  855. return support
  856. def handle_bt(devObj, dealer):
  857. # type: (Device, Dealer)->Tuple[List, List]
  858. recommend, all = [], []
  859. lastObj = Device.objects(__raw__ = {
  860. 'ownerId': str(dealer.id),
  861. 'logicalCode': {'$regex': '^[^B]'}
  862. }).order_by('-dateTimeUpdated').first()
  863. if lastObj and lastObj.devType and lastObj.devType.get('id') and lastObj.devType.get('code'):
  864. if DeviceType.is_bt_device_type(lastObj.devType.get('code')):
  865. lastDevType = lastObj.devType
  866. else:
  867. lastDevType = None
  868. else:
  869. lastDevType = None
  870. last_id_equal_list = []
  871. last_type_equal_list = []
  872. bt_list = []
  873. try:
  874. devTypes = DeviceTypeVisitor().visit(dealer)
  875. except Exception as e:
  876. logger.warning('dealer<id={}> exception in device type visitor.'.format(str(dealer.id)))
  877. devTypes = []
  878. for devType in devTypes:
  879. if not DeviceType.is_bt_device_type(devType.code):
  880. continue
  881. if lastDevType:
  882. if str(devType.id) == lastDevType.get('id') and str(devType.code) == lastDevType.get('code'):
  883. last_id_equal_list.append(devType.to_dict())
  884. continue
  885. elif str(devType.code) == lastDevType.get('code'):
  886. last_type_equal_list.append(devType.to_dict())
  887. continue
  888. bt_list.append(devType.to_dict())
  889. if last_id_equal_list:
  890. recommend = last_id_equal_list
  891. all.extend(recommend)
  892. all.extend(last_type_equal_list)
  893. else:
  894. recommend = last_type_equal_list
  895. all.extend(recommend)
  896. all.extend(bt_list)
  897. return recommend, all
  898. def handle_pulse_driver_code(devObj, dealer):
  899. # type: (Device, Dealer)->Tuple[List, List]
  900. hw_support_pulse = is_hw_support_pulse(device = devObj)
  901. recommend, all = [], []
  902. if not hw_support_pulse:
  903. return recommend, all
  904. lastObj = Device.objects(ownerId = str(dealer.id), driverCode = devObj.driverCode).order_by(
  905. '-dateTimeUpdated').first()
  906. if lastObj and lastObj.devType and lastObj.devType.get('id') and lastObj.devType.get('code'):
  907. if DeviceType.is_pulse_device_type(lastObj.devType.get('code')):
  908. lastDevType = lastObj.devType
  909. else:
  910. lastDevType = None
  911. else:
  912. lastDevType = None
  913. last_id_equal_list = []
  914. last_type_equal_list = []
  915. pulse_list = []
  916. try:
  917. devTypes = DeviceTypeVisitor().visit(dealer)
  918. except Exception as e:
  919. logger.warning('dealer<id={}> exception in device type visitor.'.format(str(dealer.id)))
  920. devTypes = []
  921. for devType in devTypes:
  922. if not DeviceType.is_pulse_device_type(devType.code):
  923. continue
  924. if lastDevType:
  925. if str(devType.id) == lastDevType.get('id') and str(devType.code) == lastDevType.get('code'):
  926. last_id_equal_list.append(devType.to_dict())
  927. continue
  928. elif str(devType.code) == lastDevType.get('code'):
  929. last_type_equal_list.append(devType.to_dict())
  930. continue
  931. pulse_list.append(devType.to_dict())
  932. if last_id_equal_list:
  933. recommend = last_id_equal_list
  934. all.extend(recommend)
  935. all.extend(last_type_equal_list)
  936. else:
  937. recommend = last_type_equal_list
  938. all.extend(recommend)
  939. all.extend(pulse_list)
  940. return recommend, all
  941. def handle_not_pulse_driver_code(devObj, dealer):
  942. hw_support_pulse = is_hw_support_pulse(device = devObj)
  943. supportDevTypes = DeviceTypeDriverRelation.support_device_type_list(devObj.driverCode)
  944. if (not supportDevTypes) and (not hw_support_pulse):
  945. logger.warning('driver code {} is not registered.'.format(devObj.driverCode))
  946. return [], []
  947. lastObj = Device.objects(ownerId = str(dealer.id), driverCode = devObj.driverCode).order_by(
  948. '-dateTimeUpdated').first()
  949. if lastObj and lastObj.devType and lastObj.devType.get('id') and lastObj.devType.get('code'):
  950. lastDevType = lastObj.devType
  951. lastDevTypeCode = lastDevType.get('code')
  952. if not lastDevTypeCode:
  953. lastDevType = None
  954. else:
  955. if DeviceType.is_pulse_device_type(lastDevTypeCode):
  956. if not hw_support_pulse:
  957. lastDevType = None
  958. else:
  959. if lastDevTypeCode not in supportDevTypes:
  960. lastDevType = None
  961. else:
  962. lastDevType = None
  963. recommend, all = [], []
  964. pulse_list = []
  965. equal_list = []
  966. no_pulse_list = []
  967. last_id_equal_list = []
  968. last_type_equal_list = []
  969. try:
  970. devTypes = DeviceTypeVisitor().visit(dealer)
  971. except Exception as e:
  972. logger.warning('dealer<id={}> exception in device type visitor.'.format(str(dealer.id)))
  973. devTypes = []
  974. for devType in devTypes:
  975. if lastDevType:
  976. if str(devType.id) == lastDevType.get('id') and devType.code == lastDevType.get('code'):
  977. last_id_equal_list.append(devType.to_dict())
  978. continue
  979. elif str(devType.code) == lastDevType.get('code'):
  980. last_type_equal_list.append(devType.to_dict())
  981. continue
  982. if str(devType.code) not in supportDevTypes:
  983. if DeviceType.is_pulse_device_type(str(devType.code)):
  984. if hw_support_pulse:
  985. pulse_list.append(devType.to_dict())
  986. continue
  987. else:
  988. continue
  989. else:
  990. if devType.code == devObj.driverCode:
  991. equal_list.append(devType.to_dict())
  992. else:
  993. no_pulse_list.append(devType.to_dict())
  994. if last_id_equal_list:
  995. recommend = last_id_equal_list
  996. all.extend(recommend)
  997. all.extend(last_type_equal_list)
  998. else:
  999. recommend = last_type_equal_list
  1000. all.extend(recommend)
  1001. all.extend(equal_list)
  1002. all.extend(no_pulse_list)
  1003. all.extend(pulse_list)
  1004. return recommend, all
  1005. def handle_no_driver_code(devObj, dealer):
  1006. # type: (Device, Dealer)->Tuple[List, List]
  1007. recommend, all = [], []
  1008. if devObj.softVer and is_only_pulse_soft_version(devObj.softVer):
  1009. only_pulse = True
  1010. else:
  1011. only_pulse = False
  1012. try:
  1013. devTypes = DeviceTypeVisitor().visit(dealer)
  1014. except Exception as e:
  1015. logger.warning('dealer<id={}> exception in device type visitor.'.format(str(dealer.id)))
  1016. devTypes = []
  1017. for devType in devTypes:
  1018. if only_pulse:
  1019. if DeviceType.is_pulse_device_type(devType.code):
  1020. all.append(devType.to_dict())
  1021. else:
  1022. all.append(devType.to_dict())
  1023. return recommend, all
  1024. def handle_tcp_device(devObj, dealer):
  1025. lastObj = Device.objects(ownerId = str(dealer.id), driverCode = devObj.driverCode).order_by(
  1026. '-dateTimeUpdated').first()
  1027. if lastObj and lastObj.devType and lastObj.devType.get('id') and lastObj.devType.get('code'):
  1028. lastDevType = lastObj.devType
  1029. else:
  1030. lastDevType = None
  1031. recommend, all = [], []
  1032. last_id_equal_list = []
  1033. last_type_equal_list = []
  1034. match_list = []
  1035. match_re = re.compile('^{}[0-9]{}$'.format(devObj.driverCode[0:2], devObj.driverCode[3:]))
  1036. try:
  1037. devTypes = DeviceTypeVisitor().visit(dealer)
  1038. except Exception as e:
  1039. logger.warning('dealer<id={}> exception in device type visitor.'.format(str(dealer.id)))
  1040. devTypes = []
  1041. for devType in devTypes:
  1042. if not match_re.match(devType.code):
  1043. continue
  1044. if lastDevType:
  1045. if str(devType.id) == lastDevType.get('id') and match_re.match(devType.code):
  1046. last_id_equal_list.append(devType.to_dict())
  1047. continue
  1048. elif str(devType.code) == lastDevType.get('code') and match_re.match(devType.code):
  1049. last_type_equal_list.append(devType.to_dict())
  1050. continue
  1051. match_list.append(devType.to_dict())
  1052. if last_id_equal_list:
  1053. recommend = last_id_equal_list
  1054. all.extend(recommend)
  1055. all.extend(last_type_equal_list)
  1056. else:
  1057. recommend = last_type_equal_list
  1058. all.extend(recommend)
  1059. all.extend(match_list)
  1060. return recommend, all
  1061. if Device.utils_is_bluetooth(devObj.logicalCode):
  1062. return handle_bt(devObj, dealer)
  1063. elif devObj.driverCode:
  1064. if TCP_DEV_TYPE_RE.match(devObj.driverCode):
  1065. return handle_tcp_device(devObj, dealer)
  1066. elif devObj.driverCode in ['000000', '999999']:
  1067. # 没有驱动版本, 这个无法注册, 必须先处理问题
  1068. return [], []
  1069. elif devObj.driverCode in ['100000', '100120']:
  1070. # 仅支持脉冲的驱动版本
  1071. return handle_pulse_driver_code(devObj, dealer)
  1072. else:
  1073. if devObj.softVer and is_only_pulse_soft_version(devObj.softVer):
  1074. # 只支持脉冲的软件版本
  1075. return handle_pulse_driver_code(devObj, dealer)
  1076. else:
  1077. return handle_not_pulse_driver_code(devObj, dealer)
  1078. else:
  1079. if devObj.softVer and is_only_pulse_soft_version(devObj.softVer): # 只支持脉冲的软件版本
  1080. return handle_pulse_driver_code(devObj, dealer)
  1081. else:
  1082. return handle_no_driver_code(devObj, dealer)
  1083. class DeviceTypeDriverRelation(DynamicDocument):
  1084. driverCode = StringField(required = True, null = False)
  1085. devTypeCode = StringField(required = True, null = False)
  1086. meta = {
  1087. 'collection': 'device_type_driver_relation',
  1088. 'db_alias': 'default',
  1089. "indexes": [
  1090. 'driverCode',
  1091. {'fields': ['driverCode', 'devTypeCode'], 'unique': True}
  1092. ],
  1093. }
  1094. @classmethod
  1095. def support_device_type_list(cls, driverCode):
  1096. return [str(obj.devTypeCode) for obj in cls.objects(driverCode = driverCode).all()]
  1097. class DeviceCacheMgr(object):
  1098. LOGICAL_CODE_KEY = 'logicalCode{}'
  1099. DEVNO_UNDER_GROUP_KEY = '{groupId}_devList'
  1100. @classmethod
  1101. def __l_cache_key(cls, logicalCode):
  1102. return cls.LOGICAL_CODE_KEY.format(logicalCode)
  1103. @classmethod
  1104. def delete_l_cache(cls, logicalCode):
  1105. cache.delete(cls.__l_cache_key(logicalCode))
  1106. @classmethod
  1107. def update_l_cache(cls, devNo, logicalCode):
  1108. cache.set(cls.__l_cache_key(logicalCode), str(devNo))
  1109. @classmethod
  1110. def get_dev_no_from_l_cache(cls, logicalCode):
  1111. return cache.get(cls.__l_cache_key(logicalCode))
  1112. @classmethod
  1113. def __dev_no_list_of_group_cache_key(cls, group_id):
  1114. # type:(str)->str
  1115. return cls.DEVNO_UNDER_GROUP_KEY.format(groupId = group_id)
  1116. @classmethod
  1117. def set_dev_no_list_of_group_cache(cls, group_id, dev_no_list):
  1118. # type: (str, list)->None
  1119. cache.set(cls.__dev_no_list_of_group_cache_key(group_id = group_id), dev_no_list)
  1120. @classmethod
  1121. def get_dev_no_list_of_group_cache(cls, group_id):
  1122. return cache.get(cls.__dev_no_list_of_group_cache_key(group_id))
  1123. @classmethod
  1124. def delete_dev_no_list_of_group_cache(cls, group_id):
  1125. cache.delete(cls.__dev_no_list_of_group_cache_key(group_id = group_id))
  1126. @classmethod
  1127. def get_many_dev_no_list_of_group_cache(cls, group_id_list):
  1128. return {
  1129. parse(cls.DEVNO_UNDER_GROUP_KEY, key).named['groupId']: items
  1130. for key, items in
  1131. cache.get_many([cls.__dev_no_list_of_group_cache_key(_) for _ in group_id_list]).iteritems()
  1132. }
  1133. @classmethod
  1134. def delete_many_dev_no_list_of_group_cache(cls, group_id_list):
  1135. # type: (List[str])->None
  1136. cache.delete_many([cls.__dev_no_list_of_group_cache_key(group_id = groupId) for groupId in group_id_list])
  1137. @classmethod
  1138. def delete_device_cache(cls, dev_no):
  1139. cache.delete(dev_no)
  1140. @classmethod
  1141. def delete_many_device_cache(cls, dev_no_list):
  1142. cache.delete_many(dev_no_list)
  1143. @staticmethod
  1144. def update_device_cache(devNo, devValue):
  1145. cache.set(devNo, devValue)
  1146. @classmethod
  1147. def get_many_device_cache(cls, dev_no_list):
  1148. return cache.get_many(dev_no_list)
  1149. @classmethod
  1150. def get_device_cache(cls, dev_no):
  1151. return cache.get(dev_no)
  1152. class DeviceRegisterLog(EmbeddedDocument):
  1153. operation = StringField(verbose_name = u'注册行为(register,unregister)')
  1154. ownerId = ObjectIdField(verbose_name = u'经销商ID')
  1155. dateTimeAdded = DateTimeField(verbose_name = u'设备注册时间', default = lambda: datetime.datetime.now())
  1156. operator = StringField(verbose_name = u'操作员', default = '')
  1157. extra = DictField(verbose_name = u'额外信息', default = {})
  1158. class DailyRent(EmbeddedDocument):
  1159. """
  1160. 设备日租相关的特性
  1161. """
  1162. # 与设备相关的
  1163. active = BooleanField(verbose_name=u"是否激活", default=False)
  1164. # 租金与租期与设备类型相互绑定 租金的单位是元 租期的单位是天
  1165. rentMoney = MonetaryField(verbose_name=u"单日租金")
  1166. rentTerm = IntField(verbose_name=u"租期")
  1167. # 激活的截至时间 超过这个时间系统会自动激活
  1168. # 设备被标记为出租设备的日期
  1169. rentDate = DateTimeField(verbose_name=u"出租日期")
  1170. # 设备的截至激活日期 超过这个时间 设备将会自动激活
  1171. lastActiveDate = DateTimeField(verbose_name=u"激活截至日期")
  1172. # 设备的实际激活时间
  1173. activeDate = DateTimeField(verbose_name=u"激活日期")
  1174. # 结算相关
  1175. lastRentDate = DateField(verbose_name=u"最后结算的日期 结算到了哪一天")
  1176. class Device(Searchable):
  1177. devNo = StringField(verbose_name = u"设备编号", min_length = 1, unique = True)
  1178. logicalCode = StringField(verbose_name = u"逻辑编码", default = None)
  1179. devType = DictField(verbose_name = "设备类型", default = {})
  1180. maxCoins = IntField(verbose_name = "最大投币数", default = 4)
  1181. groupId = StringField(verbose_name = "地址ID", default = "")
  1182. districtId = StringField(verbose_name = "地域", default = "")
  1183. ownerId = StringField(verbose_name = "所有者", default = "")
  1184. groupNumber = StringField(verbose_name = "设备组内编号", default = "")
  1185. server = StringField(verbose_name = "server", default = "120.27.251.159:1883")
  1186. server1 = StringField(verbose_name = "IP1", default = "")
  1187. mf = StringField(verbose_name = "厂商", default = "")
  1188. softVer = StringField(verbose_name = "软件版本", default = "")
  1189. hwVer = StringField(verbose_name = "固件版本", default = "")
  1190. cycle = IntField(verbose_name = "心跳间隔", default = Const.DEV_CYCLE_DEFAULT)
  1191. washConfig = DictField(verbose_name = "设备配置", default = {})
  1192. tempWashConfig = DictField(verbose_name = "临时设备配置", default = {})
  1193. trapSwtich = IntField(verbose_name = "trap开关", default = 1)
  1194. heartSwitch = StringField(verbose_name = "心跳开关", default = "")
  1195. remarks = StringField(verbose_name = "备注", default = "")
  1196. signal = IntField(verbose_name = "信号", default = 0)
  1197. pulseWidth1 = IntField(verbose_name = "脉冲宽度", default = 40)
  1198. pulseInterval1 = IntField(verbose_name = "脉冲间隔", default = 500)
  1199. battery = IntField(verbose_name = "待机电平", default = 0)
  1200. isFault = BooleanField(verbose_name = "是否故障停用", default = False)
  1201. isDND = BooleanField(verbose_name = u'是否勿扰模式', default = False)
  1202. isDNDTimeInterval = ListField(verbose_name = u'勿扰模式时间区间', default = [])
  1203. dateTimeAdded = StringField(default = lambda: datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  1204. verbose_name = '设备添加进来的时间')
  1205. # TODO: 这个名字不太合适
  1206. dateTimeUpdated = DateTimeField(default = lambda: datetime.datetime.now(),
  1207. verbose_name = '经销商注册时间, 其他操作不能按照字段名来更新, 只能在注册的时候更新该时间')
  1208. location = PointField(default = None, verbose_name = '设备经纬度')
  1209. expireDate = DateTimeField(default = None, verbose_name = '流量卡费用截止时间') # 废弃掉
  1210. simExpireDate = DateTimeField(default = None, verbose_name = 'SIM卡费用过期时间(数据来自运营商)')
  1211. simActiveDate = DateTimeField(default = None, verbose_name = 'SIM卡激活时间(数据来自运营商)')
  1212. simActiveFirstTime = DateTimeField(default = None, verbose_name = 'SIM卡激活时间(数据来自设备上报事件)')
  1213. simStatus = StringField(default = SimStatus.Updated,
  1214. verbose_name = 'sim卡的状态') # updated:表示已经更新了 ;chargedUnupdated充值了,但是未更新时间;illegal 非法卡
  1215. simChargeAuto = BooleanField(default = False, verbose_name = u'sim卡自动充值与否')
  1216. simSource = StringField(default = '', verbose_name = 'sim卡商') # jieyang/hezhou/qiben
  1217. serviceState = StringField(default = Const.ServiceState.Normal.name, verbose_name = '服务状态Const.ServiceState')
  1218. instructions = StringField(default = '', verbose_name = '设备自定义使用说明', max_length = 100)
  1219. autoRefundLeftMoney = BooleanField(verbose_name = '是否支持设备自动退款', default = False)
  1220. imsi = StringField(default = '', verbose_name = 'imsi')
  1221. iccid = StringField(default = '', verbose_name = 'iccid')
  1222. iccidHistory = ListField(field = StringField(), verbose_name = u'SIM卡换卡记录', default = [])
  1223. otherConf = DictField(verbose_name = u'各种设备其他配置', default = {})
  1224. driverCode = StringField(default = '', verbose_name = 'driverCode')
  1225. driverVersion = StringField(default = '', verbose_name = 'driverVersion')
  1226. mcuVersion = StringField(default = '', verbose_name = 'mcuVersion')
  1227. coreVer = StringField(default = '', verbose_name = u'核心版本')
  1228. boardValid = IntField(verbose_name = u'主板检测电压有效值(0 - 低电平有效, 1 - 高电平有效, 2 - 不做检测)', default = 2)
  1229. # boardVolt = IntField(verbose_name=u'主板检测电压(0 - 低电平, 1 - 高电平)', default=0)
  1230. annualTrafficCost = MonetaryField(default = Const.PLATFORM_DEFAULT_TRAFFIC_COST, verbose_name = '该字段废弃')
  1231. trafficCardCost = MonetaryField(verbose_name = "流量卡的真实成本", default = None)
  1232. dateTimeBinded = DateTimeField(verbose_name = u'设备绑定时间', default = None)
  1233. debug = StringField(verbose_name = u'调试标记', default = '')
  1234. registerLog = EmbeddedDocumentListField(document_type = DeviceRegisterLog, verbose_name = u'设备(解)注册日志')
  1235. stockDetailDict = DictField(verbose_name = u'库存详情', default = {})
  1236. nodeDict = DictField(verbose_name = u'节点字典', default = {}) # {'1':devNo}
  1237. gatewayNode = StringField(verbose_name = u'网关节点 devNo', default = '')
  1238. isRent = BooleanField(verbose_name=u"设备是否出租", default=False)
  1239. dailyRent = EmbeddedDocumentField(document_type=DailyRent, verbose_name=u"设备出租的相关信息")
  1240. binder = StringField(verbose_name = u'绑定者标识', default = '')
  1241. isApi = BooleanField(verbose_name=u"是否未API设备", default=None)
  1242. disableADExpireDate = DateTimeField(verbose_name=u'纯净版有效期', default=None)
  1243. policyTemp = DictField(verbose_name=u'计费模板', default={})
  1244. meta = {
  1245. 'collection': 'Device',
  1246. 'db_alias': 'default',
  1247. # 'shard_key':('devNo',)
  1248. }
  1249. search_fields = ('devNo', 'logicalCode')
  1250. __mgr_cache = caches['devmgr']
  1251. __base_cache_mgr = DeviceCacheMgr
  1252. def __str__(self):
  1253. return '{}<logicalCode={} devNo={}>'.format(self.__class__.__name__, self.logicalCode, self.devNo)
  1254. @property
  1255. def devTypeCode(self):
  1256. return self.devType.get('code', '')
  1257. @property
  1258. def devTypeName(self):
  1259. return self.devType.get('name', '')
  1260. @property
  1261. def devTypeFeatures(self):
  1262. return self.devType.get('features', {})
  1263. @property
  1264. def bill_as_service_feature(self):
  1265. # type: ()->BillAsServiceFeature
  1266. return BillAsServiceFeature(self.devTypeFeatures.get('billAsService', {}))
  1267. def rent(self):
  1268. """
  1269. 将设备标记为出租类型 标记前必须是已经注册的设备
  1270. 除了激活信息外 其余所有出租信息均已在此添加
  1271. :return:
  1272. """
  1273. if self.isRent: raise RentDeviceError(u"设备已经出租,请勿重复操作!")
  1274. # 出租日期
  1275. rentDate = datetime.datetime.now()
  1276. devType = DeviceType.objects.get(id=self.devType["id"]) # type: DeviceType
  1277. # 添加激活 的相关信息
  1278. dailyRent = DailyRent(
  1279. active=False,
  1280. rentMoney=RMB(devType.rentMoney),
  1281. rentTerm=int(devType.rentTerm),
  1282. rentDate=rentDate,
  1283. lastActiveDate=rentDate + datetime.timedelta(days=devType.maxWaitForActive),
  1284. )
  1285. # 兼容之前的没有isRent的设备
  1286. result = self.__class__.objects.filter(
  1287. Q(id=self.id),
  1288. Q(isRent=False) | Q(isRent=None)
  1289. ).update(
  1290. isRent=True,
  1291. dailyRent=dailyRent
  1292. )
  1293. if not result:
  1294. raise RentDeviceError(u"操作失败")
  1295. # TODO 禁用设别(如何禁用)
  1296. def active_rent(self):
  1297. """
  1298. 激活出租的设备 设备激活后
  1299. 从激活的当天开始收取日租费用
  1300. 激活的设备不能再次激活
  1301. """
  1302. if self.dailyRent.active:
  1303. raise RentDeviceError(u"请勿重复激活设备")
  1304. # 更正激活状态和日期
  1305. self.__class__.objects.filter(
  1306. id=self.id,
  1307. dailyRent__active=False
  1308. ).update(
  1309. dailyRent__activeDate=datetime.datetime.now(),
  1310. dailyRent__active=True
  1311. )
  1312. @property
  1313. def rentMoney(self):
  1314. """
  1315. 设备的租金
  1316. """
  1317. return RMB(self.dailyRent.rentMoney)
  1318. def __hash__(self):
  1319. return hash(self.devNo)
  1320. @classmethod
  1321. def __fill_up_online_info(cls, device, online_cache_info):
  1322. # type: (dict, dict)->dict
  1323. device.update({
  1324. 'online': DeviceOnlineStatus.DEV_STATUS_OFFLINE,
  1325. 'offTime': 0,
  1326. 'signal': 0,
  1327. 'updateTime': 0
  1328. })
  1329. try:
  1330. # 蓝牙或者特殊的调试标记的模块始终在线
  1331. if cls.utils_is_bluetooth(device[cls.logicalCode.name]) or device.get('debug', '') == 'fake_online':
  1332. device.update({
  1333. 'online': DeviceOnlineStatus.DEV_STATUS_ONLINE,
  1334. 'updateTime': long(time.time() * 1000)
  1335. })
  1336. return device
  1337. except Exception as e:
  1338. pass
  1339. if online_cache_info:
  1340. online_info = json.loads(online_cache_info)
  1341. if online_info['online'] == DeviceOnlineStatus.DEV_STATUS_ONLINE:
  1342. cycle = device['cycle'] if device['cycle'] else Const.DEV_CYCLE_DEFAULT
  1343. if (long(time.time() * 1000) - long(
  1344. online_info['updateTime'])) > Const.DEVICE_ONLINE_CHECK_TIMES * cycle * 1000:
  1345. device.update(
  1346. {
  1347. 'online': DeviceOnlineStatus.DEV_STATUS_OFFLINE,
  1348. 'updateTime': long(online_info['updateTime']),
  1349. 'offTime': Const.DEVICE_ONLINE_CHECK_TIMES * cycle * 1000 + long(online_info['updateTime'])
  1350. }
  1351. )
  1352. else:
  1353. device.update(
  1354. {
  1355. 'online': DeviceOnlineStatus.DEV_STATUS_ONLINE,
  1356. 'updateTime': long(online_info['updateTime'])
  1357. }
  1358. )
  1359. elif online_info['online'] == DeviceOnlineStatus.DEV_STATUS_OFFLINE:
  1360. device.update(
  1361. {
  1362. 'online': DeviceOnlineStatus.DEV_STATUS_OFFLINE,
  1363. 'offTime': long(online_info['offTime'])
  1364. }
  1365. )
  1366. device.update({'signal': online_info.get('signal', 0)})
  1367. return device
  1368. @classmethod
  1369. def __fill_up_control_info(cls, device, control_cache_info):
  1370. # type: (dict, dict)->dict
  1371. # TODO zjl 将设备的控制信息与故障信息拆开
  1372. device.update({
  1373. 'status': Const.DEV_WORK_STATUS_IDLE,
  1374. 'statusInfo': '',
  1375. })
  1376. if control_cache_info:
  1377. if 'status' not in control_cache_info or 'usePorts' in control_cache_info:
  1378. try:
  1379. ports_cache_info = control_cache_info
  1380. if 'ports' in control_cache_info:
  1381. ports_cache_info = control_cache_info['ports']
  1382. for key, value in ports_cache_info.iteritems():
  1383. if str(key).isdigit():
  1384. # 如果有isStart并且为false, 说明该端口已经结束
  1385. if 'isStart' in value:
  1386. if not value['isStart']:
  1387. continue
  1388. # 没有isStart或者isStart为True, 还需要使用status和finishedTime校正
  1389. # 在没有收到结束事件的时候, 端口也有一个预估的结束时间, 超过这个时间, 也认为结束
  1390. if 'status' in value:
  1391. if 'finishedTime' in value:
  1392. if value['finishedTime'] > int(time.time()):
  1393. device.update({'status': Const.DEV_WORK_STATUS_WORKING})
  1394. break
  1395. else:
  1396. if value['status'] == Const.DEV_WORK_STATUS_WORKING:
  1397. device.update({'status': Const.DEV_WORK_STATUS_WORKING})
  1398. break
  1399. # 如果都没有, 则认为端口空闲
  1400. except Exception as e:
  1401. logger.exception(e)
  1402. device.update({'status': Const.DEV_WORK_STATUS_IDLE})
  1403. else:
  1404. if control_cache_info['status'] == Const.DEV_WORK_STATUS_WORKING:
  1405. if control_cache_info.get('finishedTime', 0) < int(time.time()):
  1406. device.update({'status': Const.DEV_WORK_STATUS_IDLE})
  1407. else:
  1408. device.update({'status': Const.DEV_WORK_STATUS_WORKING})
  1409. # elif control_cache_info['status'] == Const.DEV_WORK_STATUS_FAULT:
  1410. # device.update(
  1411. # {'status': Const.DEV_WORK_STATUS_FAULT,
  1412. # 'statusInfo': control_cache_info.get('statusInfo', u'故障')})
  1413. else:
  1414. device.update({'status': control_cache_info['status']})
  1415. else:
  1416. device.update({'status': Const.DEV_WORK_STATUS_IDLE})
  1417. return device
  1418. @classmethod
  1419. def __fill_up_warning_info(cls, device, warning_cache_info):
  1420. """标记设备是否处于告警状态"""
  1421. warning_cache_info = warning_cache_info or dict()
  1422. for _part, _warning in warning_cache_info.items():
  1423. if _warning.get("warningStatus", False):
  1424. warning = True
  1425. break
  1426. else:
  1427. warning = False
  1428. device["deviceWarning"] = warning
  1429. return device
  1430. @classmethod
  1431. def __fill_up_status_info(cls, device, online_cache_info, service_cache_info, warning_cache_info):
  1432. # type: (dict, dict, dict, dict)->dict
  1433. device = cls.__fill_up_online_info(device, online_cache_info)
  1434. device = cls.__fill_up_control_info(device, service_cache_info)
  1435. device = cls.__fill_up_warning_info(device, warning_cache_info)
  1436. return device
  1437. @classmethod
  1438. def utils_is_expired(cls, device):
  1439. # type:(Union[Device, DeviceDict])->bool
  1440. sim_status = device.simStatus
  1441. if sim_status == SimStatus.Charged:
  1442. return False
  1443. if sim_status == SimStatus.Illegal:
  1444. return True
  1445. # 没有拿到sim卡信息的,可能是才上线,运营商都没有数据。还有一种情况,是换卡(我们家的别人家的)
  1446. sim_expire_date = device.fixedSimExpireDate
  1447. if not sim_expire_date:
  1448. return False
  1449. # 10天内必须充值,不让用
  1450. return datetime.datetime.now() >= sim_expire_date
  1451. @classmethod
  1452. def utils_is_expired_in_this_month(cls, device): # type:(Union[Device, DeviceDict])->bool
  1453. sim_status = device.simStatus
  1454. if sim_status == SimStatus.Charged:
  1455. return False
  1456. if sim_status == SimStatus.Illegal:
  1457. return True
  1458. sim_expire_date = device.fixedSimExpireDate # type: datetime.datetime
  1459. if not sim_expire_date:
  1460. return False
  1461. now = datetime.datetime.now()
  1462. return now.year == sim_expire_date.year and now.month == sim_expire_date.month
  1463. @classmethod
  1464. def utils_is_registered(cls, device):
  1465. # type: (Union[Device, DeviceDict])->bool
  1466. owner_id = device.ownerId
  1467. if owner_id and owner_id != '':
  1468. return True
  1469. else:
  1470. return False
  1471. @classmethod
  1472. def utils_is_bluetooth(cls, logicalCode):
  1473. # type: (str)->bool
  1474. if logicalCode.startswith('B'):
  1475. return True
  1476. else:
  1477. return False
  1478. @classmethod
  1479. def utils_channel_type(cls, device):
  1480. # type: (Union[Device, DeviceDict])->str
  1481. if cls.utils_is_bluetooth(device.logicalCode):
  1482. return DeviceChannelType.Channel_BT
  1483. core_ver = device.coreVer
  1484. if not core_ver:
  1485. return DeviceChannelType.Channel_UNKNOWN
  1486. if 'ASR1802' in core_ver or 'RDA8910' in core_ver:
  1487. if device.mf == 'vivestone_mesh_gate':
  1488. return DeviceChannelType.Channel_4G_GATE
  1489. else:
  1490. return DeviceChannelType.Channel_4G
  1491. if 'LuaRTOS' in core_ver:
  1492. return DeviceChannelType.Channel_WIFI
  1493. if '8955' in core_ver:
  1494. return DeviceChannelType.Channel_2G
  1495. return DeviceChannelType.Channel_UNKNOWN
  1496. @classmethod
  1497. def utils_major_type(cls, device):
  1498. # type: (Union[Device, DeviceDict])->str
  1499. if not cls.utils_is_registered(device):
  1500. return ''
  1501. dev_type = device.devType
  1502. majorDeviceType = dev_type.get('majorDeviceType', None)
  1503. if not majorDeviceType:
  1504. majorDeviceType = device.devType.get('name', None)
  1505. if not majorDeviceType:
  1506. majorDeviceType = u'自助设备'
  1507. return majorDeviceType
  1508. @property
  1509. def is_expire(self):
  1510. return self.utils_is_expired(self)
  1511. @property
  1512. def is_expire_in_this_month(self):
  1513. return self.utils_is_expired_in_this_month(self)
  1514. @classmethod
  1515. def get_sim_expire_date(cls, device):
  1516. # type: (Union[Device, DeviceDict])->Optional[datetime]
  1517. if cls.utils_is_bluetooth(device.logicalCode):
  1518. return None
  1519. if device.simExpireDate:
  1520. expire_date = device.simExpireDate
  1521. elif device.expireDate:
  1522. expire_date = device.expireDate
  1523. else:
  1524. expire_date = None
  1525. if not expire_date:
  1526. return None
  1527. else:
  1528. if device.simStatus == SimStatus.Updated:
  1529. sim_card = SIMCard.objects(iccid = device.iccid).first() # type: SIMCard
  1530. if sim_card and sim_card.channel == '58':
  1531. return expire_date.replace(day = 10)
  1532. return expire_date.replace(day = Const.SIM_CARD_FORBIDDEN_DAY)
  1533. @property
  1534. def fixedSimExpireDate(self):
  1535. return self.get_sim_expire_date(self)
  1536. def is_authorized_to_dealer(self, dealer_id):
  1537. return self.ownerId == dealer_id
  1538. @property
  1539. def channelType(self):
  1540. return self.utils_channel_type(self)
  1541. @property
  1542. def is_registered(self):
  1543. return self.utils_is_registered(self)
  1544. @property
  1545. def majorDeviceType(self):
  1546. return self.utils_major_type(self)
  1547. @classmethod
  1548. def invalid_l_cache(cls, logicalCode):
  1549. cls.__base_cache_mgr.delete_l_cache(logicalCode)
  1550. @classmethod
  1551. def update_l_cache(cls, devNo, logicalCode):
  1552. cls.__base_cache_mgr.update_l_cache(devNo, logicalCode)
  1553. @classmethod
  1554. def invalid_device_cache(cls, devNo):
  1555. cls.__base_cache_mgr.delete_device_cache(devNo)
  1556. @classmethod
  1557. def invalid_many_device_cache(cls, dev_no_list):
  1558. if dev_no_list:
  1559. cls.__base_cache_mgr.delete_many_device_cache(dev_no_list)
  1560. @classmethod
  1561. def __update_device_cache(cls, devNo, devValue):
  1562. cls.__base_cache_mgr.update_device_cache(devNo, json_dumps(data = devValue, serialize_type = True))
  1563. @classmethod
  1564. def __get_device_cache(cls, dev_no):
  1565. cache_info = cls.__base_cache_mgr.get_device_cache(dev_no)
  1566. if not cache_info:
  1567. return None
  1568. return json_loads(cache_info)
  1569. @classmethod
  1570. def get_and_update_device_cache(cls, dev_no, **kwargs):
  1571. # type: (str, Dict)->None
  1572. dev_cache = cls.__get_device_cache(dev_no)
  1573. if not dev_cache:
  1574. return None
  1575. dev_cache.update(**kwargs)
  1576. cls.__update_device_cache(dev_no, dev_cache)
  1577. @classmethod
  1578. def update_online_cache(cls, devNo, online, signal = None,updateTime = None):
  1579. online_key = device_online_cache_key(devNo)
  1580. if not signal:
  1581. online_now_cache = cls.__mgr_cache.get(online_key)
  1582. if online_now_cache:
  1583. online_now_cache = json.loads(online_now_cache)
  1584. if 'signal' in online_now_cache:
  1585. signal = online_now_cache['signal']
  1586. else:
  1587. signal = 0
  1588. else:
  1589. signal = 0
  1590. online_set_cache = {
  1591. 'online': online,
  1592. 'signal': signal,
  1593. 'updateTime': long(time.time() * 1000) if not updateTime else updateTime
  1594. }
  1595. if not online:
  1596. online_set_cache.update({'offTime': time.time()})
  1597. cls.__mgr_cache.set(online_key, json.dumps(online_set_cache))
  1598. return online_set_cache
  1599. @classmethod
  1600. def _get_many_device_status_cache(cls, devNoList):
  1601. cacheKeys = []
  1602. for devNo in devNoList:
  1603. cacheKeys.append(device_online_cache_key(devNo))
  1604. cacheKeys.append(device_control_cache_key(devNo))
  1605. cacheKeys.append(device_warning_cache_key(devNo))
  1606. return cls.__mgr_cache.get_many(cacheKeys)
  1607. @classmethod
  1608. def get_many_device_status_cache(cls, deviceDict):
  1609. # type: (Dict[str, Dict])->Dict[str, Dict]
  1610. result = {}
  1611. all_cache_info = Device._get_many_device_status_cache(deviceDict.keys())
  1612. for devNo, device_info in deviceDict.iteritems():
  1613. result[devNo] = cls.__fill_up_status_info(
  1614. device_info,
  1615. all_cache_info.get(device_online_cache_key(devNo), None),
  1616. all_cache_info.get(device_control_cache_key(devNo), None),
  1617. all_cache_info.get(device_warning_cache_key(devNo), None))
  1618. return result
  1619. @classmethod
  1620. def get_device_status_cache(cls, device):
  1621. # type: (DeviceDict)->DeviceDict
  1622. online_key = device_online_cache_key(device.devNo)
  1623. control_key = device_control_cache_key(device.devNo)
  1624. warning_key = device_warning_cache_key(device.devNo)
  1625. cacheKeys = [online_key, control_key, warning_key]
  1626. cache_info = cls.__mgr_cache.get_many(cacheKeys)
  1627. control_cache_info = cache_info.get(control_key, None)
  1628. if control_cache_info is None:
  1629. logger.debug('oh,memcached missed,devNo=%s' % device.devNo)
  1630. cache_info[control_key] = DeviceControlInfo.get(device.devNo)
  1631. Device.__mgr_cache.set(control_key, cache_info[control_key])
  1632. cls.__fill_up_status_info(
  1633. device,
  1634. cache_info.get(device_online_cache_key(device.devNo), None),
  1635. cache_info.get(device_control_cache_key(device.devNo), None),
  1636. cache_info.get(device_warning_cache_key(device.devNo), None))
  1637. return device
  1638. @staticmethod
  1639. def error_start_times_cache_key(devNo, port):
  1640. return "est_{devNo}_{port}".format(devNo = devNo, port = port)
  1641. @classmethod
  1642. def get_error_start_times(cls, devNo, port):
  1643. cacheKey = Device.error_start_times_cache_key(devNo, port)
  1644. return Device.__mgr_cache.get(cacheKey, 0)
  1645. @classmethod
  1646. def set_error_start_times(cls, devNo, port, value, timeout = None):
  1647. cacheKey = Device.error_start_times_cache_key(devNo, port)
  1648. Device.__mgr_cache.set(cacheKey, value, timeout)
  1649. @classmethod
  1650. def delete_error_start_times(cls, devNo, port):
  1651. cacheKey = Device.error_start_times_cache_key(devNo, port)
  1652. Device.__mgr_cache.delete(cacheKey)
  1653. @classmethod
  1654. def update_dev_control_cache(cls, devNo, newValue):
  1655. """
  1656. 更新设备操作信息.分update和overwrite两种方式,overwrite方式是重写,比如某个端口开始充电,就需要把以前的数据清理掉
  1657. 递归地更新端口信息。
  1658. 如果要更新某个端口的某个字段,该端口其余的信息是保留的,如果要清空用下方的clear_port_control_cache
  1659. :param devNo:
  1660. :param newValue:
  1661. :return:
  1662. """
  1663. key = device_control_cache_key(devNo)
  1664. oldValue = Device.__mgr_cache.get(key)
  1665. if oldValue is None:
  1666. logger.debug('oh,memcached missed,devNo=%s' % devNo)
  1667. oldValue = DeviceControlInfo.get(devNo)
  1668. if not oldValue:
  1669. Device.__mgr_cache.set(key, newValue)
  1670. DeviceControlInfo.set(devNo, newValue)
  1671. return
  1672. if isinstance(oldValue, dict):
  1673. #: 老接口是直接替换 {'port': {}}, 此例不会在递归更新种更新该端口为{}
  1674. if not newValue.values():
  1675. warnings.warn("deprecated, use clear_dev_control_cache instead!", DeprecationWarning)
  1676. return Device.clear_port_control_cache(devNo, newValue.keys()[0])
  1677. else:
  1678. oldValue = rec_update_dict(oldValue, newValue)
  1679. Device.__mgr_cache.set(key, oldValue, 24 * 3600)
  1680. DeviceControlInfo.set(devNo, oldValue)
  1681. #: 获取设备操作信息
  1682. @classmethod
  1683. def get_dev_control_cache(cls, devNo):
  1684. key = device_control_cache_key(devNo)
  1685. result = Device.__mgr_cache.get(key, {})
  1686. if not result:
  1687. logger.debug('oh, memcached missed, devNo=%s' % devNo)
  1688. result = DeviceControlInfo.get(devNo)
  1689. if result:
  1690. Device.__mgr_cache.set(key, result)
  1691. logger.debug('device<devNo={}> control info is: {}'.format(devNo, str(result)))
  1692. return result
  1693. @classmethod
  1694. def get_dev_warning_cache(cls, devNo):
  1695. """获取设备的全部告警信息"""
  1696. key = device_warning_cache_key(devNo)
  1697. result = cls.__mgr_cache.get(key, dict())
  1698. return result
  1699. @classmethod
  1700. def get_part_warning_cache(cls, devNo, part):
  1701. """获取设备部件的告警信息"""
  1702. key = device_warning_cache_key(devNo)
  1703. result = cls.__mgr_cache.get(key, dict())
  1704. partCache = result.get(part, dict())
  1705. return partCache
  1706. @classmethod
  1707. def update_dev_warning_cache(cls, devNo, warningData):
  1708. """更新或新增设备的部件告警信息"""
  1709. key = device_warning_cache_key(devNo)
  1710. oldValue = cls.__mgr_cache.get(key, dict()) # type: dict
  1711. oldValue.update(warningData)
  1712. cls.__mgr_cache.set(key, oldValue)
  1713. @classmethod
  1714. def clear_dev_warning_cache(cls, devNo):
  1715. """清除设备的全部故障"""
  1716. key = device_warning_cache_key(devNo)
  1717. cls.__mgr_cache.set(key, {})
  1718. @classmethod
  1719. def clear_part_warning_cache(cls, devNo, part):
  1720. """清除设备部件告警信息"""
  1721. key = device_warning_cache_key(devNo)
  1722. oldValue = cls.__mgr_cache.get(key, dict()) # type: dict
  1723. partCache = oldValue.get(part)
  1724. if not partCache:
  1725. return
  1726. oldValue.update({part: {}})
  1727. cls.__mgr_cache.set(key, oldValue)
  1728. @classmethod
  1729. def get_port_control_cache(cls, devNo, port):
  1730. _cache_info = cls.get_dev_control_cache(devNo)
  1731. if not _cache_info:
  1732. return {}
  1733. else:
  1734. return _cache_info.get(port, {})
  1735. @classmethod
  1736. def get_many_dev_control_cache(cls, devNoList):
  1737. keyList = [device_control_cache_key(devNo) for devNo in devNoList]
  1738. return Device.__mgr_cache.get_many(keyList, {})
  1739. @classmethod
  1740. def clear_port_control_cache(cls, devNo, port):
  1741. key = device_control_cache_key(devNo)
  1742. oldValue = cls.__mgr_cache.get(key)
  1743. if not oldValue:
  1744. logger.debug('oh,memcached missed,devNo=%s' % devNo)
  1745. oldValue = DeviceControlInfo.get(devNo)
  1746. if not oldValue:
  1747. return {}
  1748. port_cache = {}
  1749. try:
  1750. port_cache = oldValue.get(str(port), {})
  1751. oldValue[str(port)] = {}
  1752. cls.__mgr_cache.set(key, oldValue)
  1753. DeviceControlInfo.set(devNo, oldValue)
  1754. except Exception as e:
  1755. logger.exception(e)
  1756. finally:
  1757. return port_cache
  1758. @classmethod
  1759. def invalid_device_control_cache(cls, devNo):
  1760. DeviceControlInfo.delete(devNo)
  1761. return cls.__mgr_cache.delete(device_control_cache_key(devNo))
  1762. @classmethod
  1763. def get_devNo_by_logicalCode(cls, logicalCode):
  1764. # type: (str)->Optional[str]
  1765. if not logicalCode:
  1766. return None
  1767. devNo = Device.__base_cache_mgr.get_dev_no_from_l_cache(logicalCode)
  1768. if devNo is None:
  1769. try:
  1770. dev = Device.get_collection().find_one({'logicalCode': logicalCode})
  1771. if dev is None:
  1772. return None
  1773. devNo = dev['devNo']
  1774. Device.__base_cache_mgr.update_l_cache(devNo, logicalCode)
  1775. return devNo
  1776. except Exception as e:
  1777. logger.exception('get dev by logicalCode error=%s' % e)
  1778. return devNo
  1779. @classmethod
  1780. def get_logicalCode_by_devNo(cls, devNo):
  1781. try:
  1782. dev = Device.get_dev(devNo) # type: DeviceDict
  1783. if not dev:
  1784. return None
  1785. else:
  1786. return dev.logicalCode
  1787. except Exception as e:
  1788. logger.exception('get logical code failure. dev = %s; error = %s' % (devNo, e))
  1789. return None
  1790. @classmethod
  1791. def get_logicalCode_by_groupId(cls, groupId):
  1792. # type:(str) -> list
  1793. devMap = cls.get_devices_by_group([groupId])
  1794. return [_d.logicalCode for _d in devMap.values() if _d]
  1795. @classmethod
  1796. def __load_dev_no_list_of_group_cache(cls, groupId):
  1797. try:
  1798. objs = Device.objects.filter(groupId = groupId)
  1799. tmpList = [obj.devNo for obj in objs]
  1800. cls.__base_cache_mgr.set_dev_no_list_of_group_cache(groupId, tmpList)
  1801. return tmpList
  1802. except Exception as e:
  1803. logger.exception('load to memcache error=%s,groupId=%s' % (e, groupId))
  1804. return []
  1805. @classmethod
  1806. def __get_dev_no_list_by_group(cls, group_id_list):
  1807. # type: (List[str])->Dict
  1808. result = {}
  1809. valueDict = cls.__base_cache_mgr.get_many_dev_no_list_of_group_cache(group_id_list)
  1810. for group_id, dev_no_list in valueDict.items():
  1811. result[group_id] = dev_no_list
  1812. leftIds = list(set(group_id_list) - set(valueDict.keys()))
  1813. for group_id in leftIds:
  1814. dev_no_list = Device.__load_dev_no_list_of_group_cache(group_id)
  1815. result[group_id] = dev_no_list
  1816. return result
  1817. @classmethod
  1818. def invalid_group_device_list_cache(cls, group_id_list):
  1819. cls.__base_cache_mgr.delete_many_dev_no_list_of_group_cache(group_id_list)
  1820. @classmethod
  1821. def get_device_count_by_group(cls, group_id_list):
  1822. # type: (List[str])->Dict
  1823. value_dict = cls.__get_dev_no_list_by_group(group_id_list)
  1824. return {
  1825. group_id: len(dev_no_list) for group_id, dev_no_list in value_dict.items()
  1826. }
  1827. @classmethod
  1828. def get_devNos_by_group(cls, group_id_list):
  1829. # type: (List[str])->List
  1830. assert isinstance(group_id_list, list), u'groupIds应为list'
  1831. value_dict = cls.__get_dev_no_list_by_group(group_id_list)
  1832. result = []
  1833. for dev_no_list in value_dict.values():
  1834. result.extend(dev_no_list)
  1835. return result
  1836. @staticmethod
  1837. def protected_fields():
  1838. # type:()->list
  1839. """
  1840. 返回不向外公开的字段
  1841. :return:
  1842. """
  1843. return [
  1844. 'mf',
  1845. 'iccid',
  1846. 'server',
  1847. 'imsi',
  1848. 'hwVer',
  1849. 'softVer',
  1850. 'ownerId',
  1851. 'driverCode',
  1852. 'driverVersion',
  1853. 'instructions',
  1854. 'otherConf'
  1855. ]
  1856. @classmethod
  1857. def get_dev_by_nos(cls, devNoList, verbose = False, base_only = False):
  1858. # type:(List[str], Optional[bool], Optional[bool])->(Optional[Dict[str, DeviceDict]])
  1859. """
  1860. :param devNoList: 设备号列表
  1861. :param verbose: 是否显示更详细的信息,如设备所在的组名称
  1862. :return:
  1863. """
  1864. assert isinstance(devNoList, list), u'devNoList应为list'
  1865. def complete(device, verbose = False):
  1866. if not verbose:
  1867. return device
  1868. else:
  1869. groupInfo = Group.get_group(groupId = device['groupId'])
  1870. device['groupInfo'] = groupInfo
  1871. return device
  1872. result = {}
  1873. try:
  1874. all_device_cache_info = Device.__base_cache_mgr.get_many_device_cache(devNoList)
  1875. all_service_cache_info = None
  1876. if not base_only:
  1877. all_service_cache_info = Device._get_many_device_status_cache(devNoList)
  1878. for devNo, device_cache_info in all_device_cache_info.items():
  1879. device_value = complete(json_loads(str(device_cache_info)), verbose = verbose)
  1880. if not base_only:
  1881. device_value = cls.__fill_up_status_info(
  1882. device_value,
  1883. all_service_cache_info.get(device_online_cache_key(devNo), None),
  1884. all_service_cache_info.get(device_control_cache_key(devNo), None),
  1885. all_service_cache_info.get(device_warning_cache_key(devNo), None))
  1886. result[devNo] = DeviceDict(device_value)
  1887. leftDevNoList = set(devNoList) - set(all_device_cache_info.keys())
  1888. for devNo in leftDevNoList:
  1889. logger.debug('device<devNo={}> cache miss.'.format(devNo))
  1890. try:
  1891. obj = Device.objects.get(devNo = devNo) # type: Device
  1892. device_value = {
  1893. 'id': str(obj.id),
  1894. 'devNo': obj.devNo,
  1895. 'server': str(obj.server),
  1896. 'groupNumber': obj.groupNumber,
  1897. 'ownerId': obj.ownerId,
  1898. 'groupId': obj.groupId,
  1899. 'remarks': obj.remarks,
  1900. 'logicalCode': obj.logicalCode,
  1901. 'washConfig': obj.washConfig,
  1902. 'tempWashConfig': obj.tempWashConfig,
  1903. 'devType': obj.devType,
  1904. 'majorDeviceType': obj.majorDeviceType,
  1905. 'isFault': obj.isFault,
  1906. 'isDND': obj.isDND,
  1907. 'isRent': obj.isRent,
  1908. 'isDNDTimeInterval': obj.isDNDTimeInterval,
  1909. 'serviceState': obj.serviceState,
  1910. 'simExpireDate': obj.simExpireDate,
  1911. 'expireDate': obj.expireDate,
  1912. 'simStatus': obj.simStatus,
  1913. 'lbs': obj.lbsFlag,
  1914. 'lat': obj.lat,
  1915. 'lng': obj.lng,
  1916. 'instructions': obj.instructions,
  1917. 'dateTimeAdded': obj.dateTimeAdded,
  1918. 'mf': obj.mf,
  1919. 'softVer': obj.softVer,
  1920. 'hwVer': obj.hwVer,
  1921. 'cycle': obj.cycle,
  1922. 'trapSwtich': obj.trapSwtich,
  1923. 'heartSwitch': obj.heartSwitch,
  1924. 'pulseWidth1': obj.pulseWidth1,
  1925. 'pulseInterval1': obj.pulseInterval1,
  1926. 'battery': obj.battery,
  1927. 'iccid': obj.iccid,
  1928. 'imsi': obj.imsi,
  1929. 'otherConf': obj.otherConf,
  1930. 'driverCode': obj.driverCode,
  1931. 'driverVersion': obj.driverVersion,
  1932. 'coreVer': obj.coreVer,
  1933. 'quantity': getattr(obj, 'quantity', 0),
  1934. 'consumptionQuantity': getattr(obj, 'consumptionQuantity', 0),
  1935. 'debug': obj.debug,
  1936. 'boardValid': obj.boardValid,
  1937. 'disableDevice': getattr(obj, 'otherConf', {}).get('disableDevice', False),
  1938. 'isApi': obj.isApi,
  1939. 'disableADExpireDate': obj.disableADExpireDate,
  1940. 'policyTemp': obj.policyTemp
  1941. }
  1942. if hasattr(obj, 'priceDescription'):
  1943. device_value.update({'priceDescription': obj.priceDescription})
  1944. if obj.logicalCode:
  1945. cls.__update_device_cache(devNo, device_value)
  1946. device_value = complete(device_value, verbose = verbose)
  1947. if not base_only:
  1948. device_value = cls.__fill_up_status_info(
  1949. device_value,
  1950. all_service_cache_info.get(device_online_cache_key(devNo), None),
  1951. all_service_cache_info.get(device_control_cache_key(devNo), None),
  1952. all_service_cache_info.get(device_warning_cache_key(devNo), None)
  1953. )
  1954. result[devNo] = DeviceDict(device_value)
  1955. except Exception as e:
  1956. logger.info('get dev by nos(devNo=%s) error=%s' % (devNo, e))
  1957. continue
  1958. except memcacheClient.MemcachedKeyCharacterError as e:
  1959. logger.exception('invalid memcache key, input=%s error=%s' % (devNoList, e))
  1960. return None
  1961. except Exception as e:
  1962. logger.exception('get_dev_by_nos input=%s error=%s' % (devNoList, e))
  1963. return None
  1964. return result
  1965. @staticmethod
  1966. def get_devices_by_group(groupIds, verbose = False):
  1967. devNoList = Device.get_devNos_by_group(groupIds)
  1968. devDict = Device.get_dev_by_nos(devNoList, verbose)
  1969. return devDict
  1970. @staticmethod
  1971. def all():
  1972. """ 获取所有经销商的设备列表"""
  1973. Dealer = import_string('apps.web.dealer.models.Dealer')
  1974. dealerIds = [str(d.id) for d in Dealer.objects]
  1975. groupIds = flatten([Group.get_group_ids_of_dealer(dealerId) for dealerId in dealerIds])
  1976. return [v for k, v in Device.get_devices_by_group(list(groupIds)).items()]
  1977. @staticmethod
  1978. def get_dev(devNo):
  1979. # type: (str)->Optional[DeviceDict]
  1980. """
  1981. :param devNo:
  1982. :return:
  1983. """
  1984. if (devNo is None) or not (devNo.strip()):
  1985. return None
  1986. devDict = Device.get_dev_by_nos([devNo], base_only = True)
  1987. if (devDict is None) or (devNo not in devDict):
  1988. return None
  1989. return devDict[devNo]
  1990. @staticmethod
  1991. def get_dev_by_logicalCode(logicalCode):
  1992. # type: (str)->DeviceDict
  1993. return Device.get_dev(Device.get_devNo_by_logicalCode(logicalCode))
  1994. get_dev_by_l = get_dev_by_logicalCode
  1995. @classmethod
  1996. def get_devs_by_ownerId(cls, ownerId):
  1997. return Device.get_devices_by_group(Group.get_group_ids_of_dealer(ownerId)).values()
  1998. @classmethod
  1999. def register_device(cls, dealer, devNo, logicalCode, groupId, districtId, groupNumber, remarks, rawWashConfigs,
  2000. devType, agentId=None, policyTemp=None):
  2001. """
  2002. ..20171218
  2003. #: 整改
  2004. 0: 去掉更新devNo, logicalCode字段,该2个字段的对应关系在`预注册`阶段已经插入封闭后期不可更改保持数据的一致性。
  2005. 1: 当缓存找不到该设备时报错,确保无垃圾信息入库
  2006. :param dealer:
  2007. :param devNo:
  2008. :param logicalCode:
  2009. :param groupId:
  2010. :param districtId:
  2011. :param groupNumber:
  2012. :param remarks:
  2013. :param rawWashConfigs:
  2014. :param devType: DeviceType
  2015. :return:
  2016. """
  2017. # 检测套餐单位是否一致
  2018. def check_package_unit(typeCode, package):
  2019. if typeCode in skip_package_unit_verify_list:
  2020. return True
  2021. dic = map(lambda x: {'unit': x.get('unit')}, package)
  2022. res = reduce(lambda x, y: x if x == y else None, dic)
  2023. if res is None:
  2024. return False
  2025. else:
  2026. return True
  2027. # 检查套餐单位参数的范围
  2028. def check_params_range(typeCode, package):
  2029. if typeCode in skip_package_range_verify_list:
  2030. return None
  2031. dic = map(lambda x: [x.get('time')], package)
  2032. res = reduce(lambda x, y: x + y, dic)
  2033. result = None
  2034. for item in res:
  2035. l = str(item).split(".")
  2036. if len(l) > 1 and len(l[1]) > 2:
  2037. result = (res.index(item) // 3) + 1
  2038. break
  2039. return result
  2040. def check_params(typeCode, package):
  2041. if typeCode in skip_package_params_verify_list:
  2042. return True
  2043. lis = map(lambda x: [x.get('time'), x.get('price'), x.get('coins')], package)
  2044. res = reduce(lambda x, y: x + y, lis)
  2045. for i in res:
  2046. if i is None or float(i) < 0:
  2047. return False
  2048. return True
  2049. # 添加sn排序顺序
  2050. for item in rawWashConfigs:
  2051. item["sn"] = rawWashConfigs.index(item)
  2052. # 组装washConfig
  2053. washConfigs = {}
  2054. policyTemps = {}
  2055. devType_dict = devType.to_dict()
  2056. devType_dict.pop('package', None)
  2057. if not check_params(devType_dict["code"], rawWashConfigs):
  2058. return False, u'请完整的填写套餐中的所有参数'
  2059. if not check_package_unit(devType_dict["code"], rawWashConfigs):
  2060. return False, u'提交失败,设备套餐用户获得参数单位不一致'
  2061. f = check_params_range(devType_dict["code"], rawWashConfigs)
  2062. if f:
  2063. return False, u'设备第%s个套餐 用户获得参数应为小数点后两位' % f
  2064. if devType_dict["code"] in support_policy_weifule:
  2065. try:
  2066. from apps.web.core.models import DriverAdapter
  2067. adapter = DriverAdapter.get_driver_adapter(devType['code'], None)
  2068. if adapter.support_device_package:
  2069. washConfigs, policyTemps = adapter.reg_model(dealer, rawWashConfigs, policyTemp, devType)
  2070. except Exception as e:
  2071. return False, e.result['description']
  2072. elif devType_dict["code"] in support_policy_device:
  2073. try:
  2074. from apps.web.core.models import DriverAdapter
  2075. adapter = DriverAdapter.get_driver_adapter(devType['code'], None)
  2076. if adapter.support_device_package:
  2077. washConfigs, policyTemps = adapter.reg_model(dealer, rawWashConfigs, policyTemp, devType)
  2078. except Exception as e:
  2079. return False, e.result['description']
  2080. elif devType_dict["code"] in [Const.DEVICE_TYPE_CODE_WASHCAR_LANGUANG]:
  2081. devType_dict.update({'displayCardCharge': True})
  2082. elif devType_dict["code"] in [Const.DEVICE_TYPE_CODE_CAR_CHANGING_JINQUE,
  2083. Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_JFPG,
  2084. Const.DEVICE_TYPE_CODE_CAR_WEIFILE_HOME_DOUB_JFPG,
  2085. Const.DEVICE_TYPE_CODE_CHARGE_XIAOKEDOU]:
  2086. ii = 0
  2087. for config in rawWashConfigs:
  2088. ii += 1
  2089. # 注意,为了兼容设备类型里套餐的name字段,已统一更改description 为 name
  2090. washConfigs[str(ii)] = {}
  2091. if 'switch' in config:
  2092. washConfigs[str(ii)].update({'switch': config['switch']})
  2093. if 'billingMethod' in config:
  2094. washConfigs[str(ii)].update({'billingMethod': config['billingMethod']})
  2095. if 'price' in config:
  2096. washConfigs[str(ii)].update({'price': round(float(config['price']), 2) or 0})
  2097. if 'coins' in config:
  2098. washConfigs[str(ii)].update({'coins': round(float(config['coins']), 2) or 0})
  2099. if 'time' in config:
  2100. washConfigs[str(ii)].update({'time': config['time'] or 0})
  2101. if 'name' in config:
  2102. washConfigs[str(ii)].update({'name': config['name'] or '套餐{}'.format(ii)})
  2103. if 'unit' in config:
  2104. washConfigs[str(ii)].update({'unit': config['unit']})
  2105. if 'sn' in config:
  2106. washConfigs[str(ii)].update({'sn': config['sn']})
  2107. if 'autoStop' in config:
  2108. washConfigs[str(ii)].update({'autoStop': config['autoStop']})
  2109. if 'autoRefund' in config:
  2110. washConfigs[str(ii)].update({'autoRefund': config['autoRefund']})
  2111. if 'minAfterStartCoins' in config:
  2112. washConfigs[str(ii)].update({'minAfterStartCoins': config['minAfterStartCoins']})
  2113. if 'minFee' in config:
  2114. washConfigs[str(ii)].update({'minFee': config['minFee']})
  2115. else:
  2116. if devType_dict["code"] == Const.DEVICE_TYPE_CODE_HP_GATE: # 霍珀的阶梯套餐适配
  2117. ii = 0
  2118. tempPackage = {}
  2119. for step in rawWashConfigs:
  2120. ii += 1
  2121. tempPackage[str(ii)] = {
  2122. "maxHour": step.get("maxHour", 24),
  2123. "price": step.get("price"),
  2124. "unit": step.get("unit", u"小时"),
  2125. "sn": step.get("sn")
  2126. }
  2127. washConfigs[str(1)] = tempPackage
  2128. else:
  2129. ii = 0
  2130. for config in rawWashConfigs:
  2131. ii += 1
  2132. # 注意,为了兼容设备类型里套餐的name字段,已统一更改description 为 name
  2133. washConfigs[str(ii)] = {
  2134. 'coins': float(config['coins']),
  2135. 'name': config['name'],
  2136. 'time': float(config.get('time', 0)),
  2137. 'price': float(config['price']),
  2138. 'description': config.get('description', ''),
  2139. 'imgList': config.get('imgList', []),
  2140. 'unit': config.get('unit', u'分钟'),
  2141. 'sn': config.get('sn')
  2142. }
  2143. if config.get('pulse'):
  2144. washConfigs[str(ii)].update({
  2145. 'pulse': float(config.get('pulse')),
  2146. })
  2147. if config.get('basePrice'):
  2148. washConfigs[str(ii)].update({
  2149. 'basePrice': float(config.get('basePrice')),
  2150. })
  2151. if config.get('billingMethod'):
  2152. washConfigs[str(ii)].update({
  2153. 'billingMethod': config.get('billingMethod'),
  2154. })
  2155. # 添加默认套餐到经销商下辖
  2156. dealer.defaultWashConfig[str(devType['id'])] = rawWashConfigs
  2157. dealer.save()
  2158. try:
  2159. traffic_cost = Device.objects.get(devNo=devNo).trafficCardCost
  2160. updateDict = {
  2161. 'ownerId': str(dealer.id),
  2162. 'groupId': groupId,
  2163. 'districtId': districtId,
  2164. 'groupNumber': str(groupNumber),
  2165. 'washConfig': washConfigs,
  2166. 'remarks': remarks,
  2167. 'devType': devType_dict,
  2168. 'isFault': False,
  2169. 'isApi': False,
  2170. 'dateTimeAdded': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
  2171. 'dateTimeUpdated': datetime.datetime.now(),
  2172. 'otherConf': {}
  2173. }
  2174. if policyTemp:
  2175. updateDict.update({'policyTemp': policyTemps})
  2176. # 设备如果已经注册过, 就有流量卡成本, 并且始终以这个为准
  2177. if not traffic_cost:
  2178. if dealer.trafficCardCost:
  2179. updateDict.update({'trafficCardCost': dealer.trafficCardCost})
  2180. else:
  2181. from apps.web.agent.models import Agent
  2182. agent = Agent.objects(id=dealer.agentId).get() # type: Agent
  2183. updateDict.update({'trafficCardCost': agent.trafficCardCost})
  2184. if devType_dict['code'] == Const.DEVICE_TYPE_CODE_TISSUE: # 适配的代码,如果是纸巾机,就需要初始化记录库存情况
  2185. updateDict.update({'consumptionQuantity': 0, 'quantity': 0})
  2186. cls.objects(devNo=devNo, logicalCode=logicalCode).update_one(upsert=False, **updateDict)
  2187. content = {
  2188. 'logicalCode': logicalCode,
  2189. 'devNo': devNo,
  2190. 'devTypeCode': devType_dict['code']
  2191. }
  2192. if agentId:
  2193. content.update({'agentId': agentId})
  2194. OperatorLog.log(user=dealer, level=OperatorLog.LogLevel.INFO, operator_name='register device',
  2195. content=content)
  2196. except Exception as e:
  2197. logger.exception(
  2198. 'set cache error=%s, when registering device (devNo=%s), ownerId=%s' % (e, devNo, str(dealer.id)))
  2199. return False, u'注册设备失败,请重试'
  2200. finally:
  2201. # 失效缓存
  2202. cls.invalid_device_cache(devNo)
  2203. cls.invalid_group_device_list_cache([groupId])
  2204. return True, 'success'
  2205. @classmethod
  2206. def get_elec_static_time(cls, devNo):
  2207. device = cls.objects(devNo = devNo).first()
  2208. deviceType = DeviceType.objects(id = device.devType['id']).first()
  2209. return deviceType.features.get('elecStaticTime', 900)
  2210. @property
  2211. def lbsFlag(self):
  2212. if self.location:
  2213. return True
  2214. else:
  2215. return False
  2216. @property
  2217. def lbs(self):
  2218. return self.lbsFlag
  2219. @property
  2220. def lat(self):
  2221. if self.location:
  2222. return self.location['coordinates'][1]
  2223. else:
  2224. return 360
  2225. @property
  2226. def lng(self):
  2227. if self.location:
  2228. return self.location['coordinates'][0]
  2229. else:
  2230. return 360
  2231. @staticmethod
  2232. def testSignal(logicalCode):
  2233. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  2234. if devNo is None:
  2235. return u'设备不存在', 0
  2236. device = Device.get_dev(devNo) # type: DeviceDict
  2237. if not device:
  2238. return u'设备不存在', 0
  2239. if not device.online:
  2240. return u'设备掉线,无法获取网络信号情况', 0
  2241. result = MessageSender.send(device, DeviceCmdCode.GET_DEVINFO, {'IMEI': devNo}, timeout = MQTT_TIMEOUT.SHORT)
  2242. if result['rst'] != 0:
  2243. return 'OK', 0
  2244. else:
  2245. return 'OK', int(result.get('signal', 0))
  2246. @classmethod
  2247. def un_register(cls, dev, force=False, operator=None):
  2248. # type: (DeviceDict, bool, str)->None
  2249. if not dev.is_registered:
  2250. logger.debug('dev<no={}> is not registered.'.format(dev.devNo))
  2251. return
  2252. # 出租设备只有系统管理员能够解绑
  2253. if dev.isRent and not force:
  2254. logger.debug("dev <{}> is rent, not allow to unregiste!")
  2255. raise RentDeviceError(u"租用设备无法解绑")
  2256. try:
  2257. emptyValue = {
  2258. 'groupId': Device.groupId.default,
  2259. 'districtId': Device.districtId.default,
  2260. 'devType': Device.devType.default,
  2261. 'groupNumber': Device.groupNumber.default,
  2262. 'washConfig': Device.washConfig.default,
  2263. 'tempWashConfig': Device.tempWashConfig.default,
  2264. 'remarks': Device.remarks.default,
  2265. 'instructions': Device.instructions.default,
  2266. 'otherConf': Device.otherConf.default,
  2267. 'ownerId': '',
  2268. 'policyTemp': Device.policyTemp.default,
  2269. }
  2270. OperatorLog.log(user=dev.owner, level=OperatorLog.LogLevel.INFO,
  2271. operator_name='unregister device' if not force else 'force unregister device',
  2272. content=dict(dev.my_obj.to_mongo()))
  2273. Device.objects(devNo=dev.devNo).update_one(**emptyValue)
  2274. finally:
  2275. Device.invalid_group_device_list_cache([dev.groupId])
  2276. Device.invalid_device_cache(dev.devNo)
  2277. @staticmethod
  2278. def filter(dealerId, searchKey, online = '', expireStatus = '', equipmentGroupId = ''):
  2279. def cmp_group_devName(x, y):
  2280. # type: (Dict, Dict)->int
  2281. if x['groupId'] > y['groupId']:
  2282. return 1
  2283. elif x['groupId'] == y['groupId']:
  2284. if x['online'] < y['online']:
  2285. return -1
  2286. elif x['online'] > y['online']:
  2287. return 1
  2288. else:
  2289. if x['id'] < y['id']:
  2290. return -1
  2291. else:
  2292. return 0
  2293. else:
  2294. return -1
  2295. def match_expire_status(dev, expire_status):
  2296. # type:(DeviceDict, str)->bool
  2297. if expire_status not in ['normal', 'expire', 'toExpire']:
  2298. return True
  2299. if expire_status == 'normal':
  2300. if (not dev.is_expired) and (not dev.is_to_expired):
  2301. return True
  2302. else:
  2303. return False
  2304. if expire_status == 'expire':
  2305. if dev.is_expired:
  2306. return True
  2307. else:
  2308. return False
  2309. if expire_status == 'toExpire':
  2310. if dev.is_to_expired:
  2311. return True
  2312. else:
  2313. return False
  2314. if online == '' or online == 'all':
  2315. onlineList = [0, 1]
  2316. elif online == '1':
  2317. onlineList = [1]
  2318. elif online == '0':
  2319. onlineList = [0]
  2320. else:
  2321. onlineList = []
  2322. groupIds = [equipmentGroupId]
  2323. partnerGroupList = Group.get_group_ids_of_partner(dealerId)
  2324. if equipmentGroupId == 'all' or equipmentGroupId == '':
  2325. groupIds = Group.get_group_ids_of_dealer(dealerId)
  2326. groupIds.extend(partnerGroupList)
  2327. groupDict = Group.get_groups_by_group_ids(groupIds)
  2328. devNoList = Device.get_devNos_by_group(groupIds)
  2329. devs = Device.get_dev_by_nos(devNoList).values()
  2330. devList = []
  2331. for dev in devs: # type: DeviceDict
  2332. try:
  2333. if dev.online not in onlineList:
  2334. continue
  2335. if not match_expire_status(dev, expireStatus):
  2336. continue
  2337. group = groupDict.get(dev['groupId'])
  2338. if any(map(lambda _: searchKey in _, (dev['devNo'],
  2339. dev['remarks'],
  2340. dev['logicalCode'],
  2341. group['groupName'],
  2342. group['address']))):
  2343. item = {
  2344. 'id': dev.devNo,
  2345. 'logicalCode': dev.logicalCode,
  2346. 'name': group['groupName'],
  2347. 'groupId': group['groupId'],
  2348. 'type': dev.devType['name'],
  2349. 'typeId': dev.devType['id'],
  2350. 'online': dev.online,
  2351. 'timeBased': dev.devType.get('timeBased', True),
  2352. 'isManager': False if dev['groupId'] in partnerGroupList else True,
  2353. 'serviceState': dev.get('serviceState', Const.ServiceState.Normal.name),
  2354. 'consumptionQuantity': dev.get('consumptionQuantity', 0),
  2355. 'quantity': dev.get('quantity', 0),
  2356. 'devType': {'code': dev.devType.get('code', '99999')},
  2357. 'expireDate': dev.formatSimExpireDate,
  2358. 'simStatus': dev.simStatus
  2359. }
  2360. devList.append(item)
  2361. except Exception, e:
  2362. logger.exception(
  2363. '[Device.filter] has some error=%s dealerId=%s, searchKey=%s' % (e, dealerId, searchKey))
  2364. continue
  2365. devList.sort(cmp = cmp_group_devName)
  2366. return groupIds, devList
  2367. @staticmethod
  2368. def tree_filter(dealerId = None, agentId = None, managerId = None, searchKey = None, pageIndex = 1, pageSize = 10,
  2369. **kwargs):
  2370. # type: (Optional[str], Optional[str], Optional[str], Optional[str], int, int, **Any)->Tuple[int, List[dict]]
  2371. """
  2372. 分层获取设备列表
  2373. :param dealerId:
  2374. :param agentId:
  2375. :param managerId:
  2376. :param searchKey:
  2377. :param pageIndex:
  2378. :param pageSize:
  2379. :return:
  2380. """
  2381. online = kwargs.get('online', None)
  2382. registered = kwargs.get('registered', None)
  2383. Agent = import_string('apps.web.agent.models.Agent')
  2384. Dealer = import_string('apps.web.dealer.models.Dealer')
  2385. Manager = import_string('apps.web.management.models.Manager')
  2386. shadow = kwargs.get('shadow', False)
  2387. dealerMap = {}
  2388. agentMap = {}
  2389. managerMap = {}
  2390. #: 显示没有注册的设备
  2391. if not registered and registered is not None:
  2392. devices = Device.objects(Q(ownerId__exists = 0) | Q(ownerId = "")).search(searchKey)
  2393. else:
  2394. #: 如果没有任何厂商代理商经销商,显示所有的设备
  2395. if dealerId is not None:
  2396. dealerFilter = Q(id = ObjectId(dealerId))
  2397. else:
  2398. dealerFilter = Q()
  2399. if agentId is not None:
  2400. agentIds = [agentId]
  2401. dealerFilter &= Q(agentId__in = agentIds)
  2402. else:
  2403. if managerId is not None:
  2404. agentQuery = Q(managerId = managerId)
  2405. else:
  2406. managerMap = {
  2407. str(d['_id']): d for d in
  2408. Manager.get_collection().find({}, {'_id': 1, 'nickname': 1, 'username': 1, 'domain': 1})
  2409. }
  2410. agentQuery = Q(managerId__in = managerMap.keys())
  2411. agentMap = {
  2412. str(d['_id']): d
  2413. for d in Agent.get_collection().find(agentQuery.to_query(Agent),
  2414. {'_id': 1, 'username': 1, 'nickname': 1, 'managerId': 1})
  2415. }
  2416. dealerFilter &= Q(agentId__in = agentMap.keys())
  2417. dealerMap = {
  2418. str(d['_id']): d
  2419. for d in Dealer.get_collection().find(dealerFilter.to_query(Dealer),
  2420. {'_id': 1, 'nickname': 1, 'username': 1, 'agentId': 1})
  2421. }
  2422. dealerIds = dealerMap.keys()
  2423. devices = Device.objects(ownerId__in = dealerIds).search(searchKey)
  2424. total = devices.count()
  2425. devNos = []
  2426. groupIds = []
  2427. for d in devices.paginate(pageIndex, pageSize):
  2428. devNos.append(d['devNo'])
  2429. if d['groupId']:
  2430. groupIds.append(d['groupId'])
  2431. devs = Device.get_dev_by_nos(devNos)
  2432. groups = Group.get_groups_by_group_ids(groupIds)
  2433. def device_filter(devices):
  2434. if online is not None:
  2435. for dev in devices: # type: DeviceDict
  2436. if str(dev.online) == str(online):
  2437. yield dev
  2438. else:
  2439. for dev in devices:
  2440. yield dev
  2441. items = []
  2442. for dev in device_filter(devs.values()): # type: DeviceDict
  2443. group = groups.get(dev.groupId, {})
  2444. item = {
  2445. 'logicalCode': dev.logicalCode,
  2446. 'devNo': dev.devNo,
  2447. 'createdTime': dev['dateTimeAdded'],
  2448. 'groupId': dev.groupId,
  2449. 'groupName': group.get('groupName'),
  2450. 'address': group.get('address'),
  2451. 'online': dev.online,
  2452. 'signal': dev.signal,
  2453. 'lastOffTime': dev.offTime,
  2454. 'simExpireDate': dev.fixedSimExpireDate,
  2455. 'simStatus': dev.simStatus,
  2456. 'server': dev.server,
  2457. 'devType': dev.devType,
  2458. 'driverCode': dev.get('driverCode', ''),
  2459. 'driverVersion': dev.get('driverVersion', ''),
  2460. 'cycle': dev['cycle'],
  2461. 'pulseInterval1': dev['pulseInterval1'],
  2462. 'battery': dev['battery'],
  2463. 'imsi': dev['imsi'],
  2464. 'iccid': dev['iccid'],
  2465. 'remarks': dev['remarks'],
  2466. 'registered': dev.is_registered,
  2467. 'softVer': dev['softVer'],
  2468. 'coreVer': dev['coreVer'],
  2469. "disableDevice": dev.get("otherConf", {}).get("disableDevice", False),
  2470. 'hwVer': dev.hwVer,
  2471. 'supportPG': dev.support_power_graph
  2472. }
  2473. if dev['ownerId']:
  2474. if dev['ownerId'] in dealerMap:
  2475. dealer = dealerMap[dev['ownerId']]
  2476. else:
  2477. dealer = Dealer.get_collection().find_one({'_id': ObjectId(dev['ownerId'])},
  2478. {'_id': 1, 'nickname': 1, 'username': 1, 'agentId': 1})
  2479. dealerMap[dev['ownerId']] = dealer
  2480. if dealer['agentId'] not in agentMap:
  2481. agent = Agent.get_collection().find_one({'_id': ObjectId(dealer['agentId'])},
  2482. {'_id': 1, 'username': 1, 'nickname': 1, 'managerId': 1})
  2483. if not agent:
  2484. logger.error(
  2485. 'no agent. dealerId = {}, agentId = {}'.format(dealer['_id'], str(dealer['agentId'])))
  2486. continue
  2487. agentMap[dealer['agentId']] = agent
  2488. agent = agentMap[dealer['agentId']]
  2489. if agent['managerId'] in managerMap:
  2490. manager = managerMap[agent['managerId']]
  2491. else:
  2492. manager = Manager.get_collection().find_one({'_id': ObjectId(agent['managerId'])},
  2493. {'_id': 1, 'nickname': 1, 'username': 1, 'domain': 1})
  2494. managerMap[agent['managerId']] = manager
  2495. if manager['domain'] != settings.MY_DOMAIN:
  2496. logger.debug('manager<id={},domain={}> not belong to me.'.format(manager['_id'], manager['domain']))
  2497. continue
  2498. item['manager'] = {
  2499. 'id': manager.get('_id'),
  2500. 'username': '******' if shadow else manager.get('username', ''),
  2501. 'nickname': manager.get('nickname', '')
  2502. }
  2503. item['agent'] = {
  2504. 'id': agent.get('_id'),
  2505. 'username': '******' if shadow else agent.get('username', ''),
  2506. 'nickname': agent.get('nickname', '')
  2507. }
  2508. item['dealer'] = {
  2509. 'id': dealer.get('_id'),
  2510. 'username': '******' if shadow else dealer.get('username', ''),
  2511. 'nickname': dealer.get('nickname', '')
  2512. }
  2513. else:
  2514. item['manager'] = {
  2515. 'id': '',
  2516. 'username': '',
  2517. 'nickname': ''
  2518. }
  2519. item['agent'] = {
  2520. 'id': '',
  2521. 'username': '',
  2522. 'nickname': ''
  2523. }
  2524. item['dealer'] = {
  2525. 'id': '',
  2526. 'username': '',
  2527. 'nickname': ''
  2528. }
  2529. # 添加续费记录的相关信息
  2530. from apps.web.dealer.models import DealerRechargeRecord
  2531. DRRS = DealerRechargeRecord.objects.filter(dealerId = str(item['dealer']['id']), status = "Paid").order_by(
  2532. '-finishedTime')
  2533. item[u'chargeRecord'] = []
  2534. for DRR in DRRS:
  2535. for res in DRR.items:
  2536. if res.get(u'devNo') == dev.devNo:
  2537. res[u'orderNo'] = DRR.orderNo
  2538. res[u'nickname'] = DRR.nickname
  2539. res[u'finishedTime'] = DRR.finishedTime
  2540. item[u'chargeRecord'].append(res)
  2541. items.append(item)
  2542. return total, items
  2543. @staticmethod
  2544. def accurate_filter(logicalCode, shadow):
  2545. Agent = import_string('apps.web.agent.models.Agent')
  2546. Dealer = import_string('apps.web.dealer.models.Dealer')
  2547. Manager = import_string('apps.web.management.models.Manager')
  2548. dev = Device.get_dev_by_logicalCode(logicalCode) # type: DeviceDict
  2549. if not dev:
  2550. return
  2551. if dev.get("groupId"):
  2552. group = Group.get_group(dev.get("groupId"))
  2553. else:
  2554. group = dict()
  2555. item = {
  2556. 'logicalCode': dev.logicalCode,
  2557. 'devNo': dev.devNo,
  2558. 'createdTime': dev['dateTimeAdded'],
  2559. 'groupId': dev.groupId,
  2560. 'groupName': group.get('groupName'),
  2561. 'address': group.get('address'),
  2562. 'online': dev.online,
  2563. 'signal': dev.signal,
  2564. 'lastOffTime': dev.offTime,
  2565. 'simExpireDate': dev.fixedSimExpireDate,
  2566. 'server': dev.server,
  2567. 'devType': dev.devType,
  2568. 'driverCode': dev.get('driverCode', ''),
  2569. 'driverVersion': dev.get('driverVersion', ''),
  2570. 'cycle': dev['cycle'],
  2571. 'pulseInterval1': dev['pulseInterval1'],
  2572. 'battery': dev['battery'],
  2573. 'imsi': dev['imsi'],
  2574. 'iccid': dev['iccid'],
  2575. 'remarks': dev['remarks'],
  2576. 'registered': dev.is_registered,
  2577. 'softVer': dev['softVer'],
  2578. 'coreVer': dev['coreVer'],
  2579. 'hwVer': dev.hwVer,
  2580. 'supportPG': dev.support_power_graph
  2581. }
  2582. if dev.get("ownerId"):
  2583. try:
  2584. dealer = Dealer.get_collection().find_one({'_id': ObjectId(dev['ownerId'])},
  2585. {'_id': 1, 'nickname': 1, 'username': 1, "agentId": 1})
  2586. agent = Agent.get_collection().find_one({'_id': ObjectId(dealer['agentId'])},
  2587. {'_id': 1, 'username': 1, 'nickname': 1, "managerId": 1})
  2588. manager = Manager.get_collection().find_one({'_id': ObjectId(agent['managerId'])},
  2589. {'_id': 1, 'nickname': 1, 'username': 1, 'domain': 1})
  2590. item['manager'] = {
  2591. 'id': manager.get('_id'),
  2592. 'username': manager.get('username', '') if shadow is False else '******',
  2593. 'nickname': manager.get('nickname', '')
  2594. }
  2595. item['agent'] = {
  2596. 'id': agent.get('_id'),
  2597. 'username': agent.get('username', '') if shadow is False else '******',
  2598. 'nickname': agent.get('nickname', '')
  2599. }
  2600. item['dealer'] = {
  2601. 'id': dealer.get('_id'),
  2602. 'username': dealer.get('username', '') if shadow is False else '******',
  2603. 'nickname': dealer.get('nickname', '')
  2604. }
  2605. except Exception as e:
  2606. item['manager'] = {
  2607. 'id': '',
  2608. 'username': '',
  2609. 'nickname': ''
  2610. }
  2611. item['agent'] = {
  2612. 'id': '',
  2613. 'username': '',
  2614. 'nickname': ''
  2615. }
  2616. item['dealer'] = {
  2617. 'id': '',
  2618. 'username': '',
  2619. 'nickname': ''
  2620. }
  2621. else:
  2622. item['manager'] = {
  2623. 'id': '',
  2624. 'username': '',
  2625. 'nickname': ''
  2626. }
  2627. item['agent'] = {
  2628. 'id': '',
  2629. 'username': '',
  2630. 'nickname': ''
  2631. }
  2632. item['dealer'] = {
  2633. 'id': '',
  2634. 'username': '',
  2635. 'nickname': ''
  2636. }
  2637. # 添加续费记录的相关信息
  2638. from apps.web.dealer.models import DealerRechargeRecord
  2639. DRRS = DealerRechargeRecord.objects.filter(dealerId = str(item['dealer']['id']), status = "Paid").order_by(
  2640. '-finishedTime')
  2641. item[u'chargeRecord'] = []
  2642. for DRR in DRRS:
  2643. for res in DRR.items:
  2644. if res.get('devNo') == dev.devNo:
  2645. res[u'orderNo'] = DRR.orderNo
  2646. res[u'nickname'] = DRR.nickname
  2647. res[u'finishedTime'] = DRR.finishedTime
  2648. item[u'chargeRecord'].append(res)
  2649. return item
  2650. @classmethod
  2651. def update_field(cls, dev_no, update = False, **valueDict):
  2652. try:
  2653. cls.get_collection().update_one({'devNo': dev_no}, {'$set': valueDict})
  2654. if update:
  2655. cls.get_and_update_device_cache(dev_no, **valueDict)
  2656. else:
  2657. cls.invalid_device_cache(dev_no)
  2658. except Exception as e:
  2659. logger.exception('update dev error=%s' % e)
  2660. return False
  2661. return True
  2662. def is_auto_refund(self):
  2663. return self.autoRefundLeftMoney
  2664. @staticmethod
  2665. def get_dev_no_from_request(request):
  2666. devNo = request.GET.get('devNo', None)
  2667. if not devNo:
  2668. logicalCode = request.GET.get('logicalCode', None)
  2669. if logicalCode:
  2670. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  2671. return devNo
  2672. @staticmethod
  2673. def update_port_control_cache(devNo, portInfo, updateType = 'update'):
  2674. #: 两种方式update,以及overwrite
  2675. oldValue = Device.get_dev_control_cache(devNo)
  2676. port = str(portInfo['port'])
  2677. if port in oldValue and updateType == 'update':
  2678. oldValue[port].update(portInfo)
  2679. else:
  2680. oldValue[port] = portInfo
  2681. Device.update_dev_control_cache(devNo, oldValue)
  2682. return oldValue[port]
  2683. @staticmethod
  2684. def modify_port_control_cache(devNo, port, portInfo):
  2685. key = device_control_cache_key(devNo)
  2686. oldValue = Device.__mgr_cache.get(key)
  2687. if oldValue is None:
  2688. logger.debug('oh,memcached missed,devNo=%s' % devNo)
  2689. oldValue = DeviceControlInfo.get(devNo)
  2690. if not isinstance(oldValue, dict):
  2691. logger.warning('control cache old value is not dict. value = {}'.format(oldValue))
  2692. oldValue = None
  2693. if not oldValue or str(port) not in oldValue:
  2694. new_value = {str(port): portInfo}
  2695. Device.__mgr_cache.set(key, new_value)
  2696. DeviceControlInfo.set(devNo, new_value)
  2697. else:
  2698. oldValue[str(port)].update(portInfo)
  2699. Device.__mgr_cache.set(key, oldValue)
  2700. DeviceControlInfo.set(devNo, oldValue)
  2701. @staticmethod
  2702. def overwrite_port_control_cache(devNo, port, portInfo):
  2703. key = device_control_cache_key(devNo)
  2704. oldValue = Device.__mgr_cache.get(key)
  2705. if oldValue is None:
  2706. logger.debug('oh,memcached missed,devNo=%s' % devNo)
  2707. oldValue = DeviceControlInfo.get(devNo)
  2708. if not isinstance(oldValue, dict):
  2709. logger.warning('control cache old value is not dict. value = {}'.format(oldValue))
  2710. oldValue = None
  2711. if not oldValue:
  2712. new_value = {str(port): portInfo}
  2713. Device.__mgr_cache.set(key, new_value)
  2714. DeviceControlInfo.set(devNo, new_value)
  2715. else:
  2716. oldValue[str(port)] = portInfo
  2717. Device.__mgr_cache.set(key, oldValue)
  2718. DeviceControlInfo.set(devNo, oldValue)
  2719. @classmethod
  2720. def generate_sim_expire_query(cls, expire_start_date, expire_end_date,
  2721. dealer_id = None, sim_source = None, sim_status = None):
  2722. query = {'ownerId': dealer_id} if dealer_id else {'ownerId': {'$nin': [None, '']}}
  2723. if expire_start_date and expire_end_date:
  2724. query.update({
  2725. '$or': [
  2726. {
  2727. 'simExpireDate': {
  2728. '$lt': expire_end_date,
  2729. '$gte': expire_start_date
  2730. }
  2731. },
  2732. {
  2733. 'expireDate': {
  2734. '$lt': expire_end_date,
  2735. '$gte': expire_start_date
  2736. },
  2737. 'simExpireDate': None
  2738. },
  2739. ]
  2740. })
  2741. elif expire_start_date:
  2742. query.update({
  2743. '$or': [
  2744. {
  2745. 'simExpireDate': {
  2746. '$gte': expire_start_date
  2747. }
  2748. },
  2749. {
  2750. 'expireDate': {
  2751. '$gte': expire_start_date
  2752. },
  2753. 'simExpireDate': None
  2754. },
  2755. ]
  2756. })
  2757. elif expire_end_date:
  2758. query.update({
  2759. '$or': [
  2760. {
  2761. 'simExpireDate': {
  2762. '$lt': expire_end_date
  2763. }
  2764. },
  2765. {
  2766. 'expireDate': {
  2767. '$lt': expire_end_date
  2768. },
  2769. 'simExpireDate': None
  2770. },
  2771. ]
  2772. })
  2773. query.update({
  2774. 'logicalCode': {'$regex': '^[^B]'},
  2775. })
  2776. if sim_source:
  2777. query.update({'simSource': sim_source})
  2778. if sim_status:
  2779. query.update({'simStatus': {'$in': [sim_status, None]}})
  2780. return query
  2781. @classmethod
  2782. def check_sim_expire_notify(cls, device):
  2783. # type: (Optional[Device, DeviceDict])->bool
  2784. if not device.fixedSimExpireDate:
  2785. return False
  2786. if device.simStatus != SimStatus.Updated:
  2787. return False
  2788. now = arrow.now()
  2789. first_day = now.replace(day = 1, hour = 0, minute = 0, second = 0, microsecond = 0) # type: arrow
  2790. last_day = first_day.shift(months = 1).shift(days = -1) # type: arrow
  2791. if device.fixedSimExpireDate >= first_day.naive:
  2792. return True
  2793. else:
  2794. return False
  2795. @property
  2796. def sim_expire_notify(self):
  2797. return self.check_sim_expire_notify(self)
  2798. def set_fault(self):
  2799. updated = self.update(isFault = True)
  2800. assert updated, 'set %r fault failed' % (self,)
  2801. Device.invalid_device_cache(self.devNo)
  2802. @property
  2803. def cached(self):
  2804. return Device.get_dev(self.devNo)
  2805. @staticmethod
  2806. # 计算设备的使用率
  2807. def calc_dev_usage(devNo):
  2808. ctrInfo = Device.get_dev_control_cache(devNo)
  2809. usage = 0
  2810. if ctrInfo is not None and ctrInfo:
  2811. portCount, busyCount = 0, 0
  2812. for k, v in ctrInfo.items():
  2813. if str(k).isdigit():
  2814. portCount += 1
  2815. if v.has_key('status') and v['status'] == Const.DEV_WORK_STATUS_WORKING:
  2816. busyCount += 1
  2817. else:
  2818. continue
  2819. if portCount:
  2820. usage = float(busyCount) / portCount * 100.0
  2821. else:
  2822. serviceInfo = Device.get_dev_control_cache(devNo)
  2823. if serviceInfo is not None and serviceInfo.has_key('status') and serviceInfo[
  2824. 'status'] == Const.DEV_WORK_STATUS_WORKING:
  2825. if not serviceInfo.has_key('finishedTime'):
  2826. return 0
  2827. if time.time() > serviceInfo['finishedTime']:
  2828. return 0
  2829. return 100.0
  2830. return float(usage)
  2831. @classmethod
  2832. def invalid_all_cache(cls, device):
  2833. # type:(Optional[DeviceDict, Device])->None
  2834. cls.__base_cache_mgr.delete_device_cache(device.devNo)
  2835. cls.__base_cache_mgr.delete_l_cache(device.logicalCode)
  2836. cls.invalid_group_device_list_cache([device.groupId])
  2837. cls.invalid_device_control_cache(device.devNo)
  2838. @classmethod
  2839. def replace(cls, old_lc, new_lc, operator):
  2840. # type:(str, str, UserSearchable)->None
  2841. old_device = Device.objects(logicalCode = old_lc).first() # type: Optional[Device]
  2842. new_device = Device.objects(logicalCode = new_lc).first() # type: Optional[Device]
  2843. if not old_device:
  2844. raise UserServerException(u'旧设备({})不存在'.format(old_lc))
  2845. if not new_device:
  2846. raise UserServerException(u'新设备({})不存在'.format(new_lc))
  2847. if (old_device.ownerId != new_device.ownerId) and new_device.ownerId:
  2848. raise UserServerException(u'设备注册经销商不一致,不允许替换')
  2849. record = DeviceReplacement(
  2850. oldLogicalCode = old_lc,
  2851. newLogicalCode = new_lc,
  2852. oldDevice = dict(old_device.to_mongo()),
  2853. newDevice = dict(new_device.to_mongo()),
  2854. replaceType = 'replace'
  2855. ).save()
  2856. OperatorLog.log(user = operator,
  2857. level = OperatorLog.LogLevel.CRITICAL,
  2858. operator_name = u'换绑设备',
  2859. content = {
  2860. 'ref_id': record.id
  2861. })
  2862. try:
  2863. old_device.delete()
  2864. update_dict = {
  2865. 'logicalCode': old_device.logicalCode,
  2866. 'ownerId': old_device.ownerId,
  2867. 'groupId': old_device.groupId,
  2868. 'districtId': old_device.districtId,
  2869. 'groupNumber': old_device.groupNumber,
  2870. 'washConfig': old_device.washConfig,
  2871. 'tempWashConfig': old_device.tempWashConfig,
  2872. 'remarks': old_device.remarks,
  2873. 'instructions': old_device.instructions,
  2874. 'isFault': old_device.isFault,
  2875. 'autoRefundLeftMoney': old_device.autoRefundLeftMoney,
  2876. 'devType': old_device.devType,
  2877. 'dateTimeUpdated': datetime.datetime.now(),
  2878. 'iccidHistory': old_device.iccidHistory,
  2879. 'otherConf': old_device.otherConf,
  2880. 'registerLog': old_device.registerLog,
  2881. 'serviceState': old_device.serviceState,
  2882. 'trafficCardCost': old_device.trafficCardCost,
  2883. 'stockDetailDict': old_device.stockDetailDict
  2884. }
  2885. if old_device.location:
  2886. update_dict['location'] = old_device.location
  2887. updated = new_device.update(**update_dict)
  2888. if not updated:
  2889. raise UserServerException(u'未更新成功,请重试')
  2890. finally:
  2891. Device.invalid_all_cache(old_device)
  2892. Device.invalid_all_cache(new_device)
  2893. @classmethod
  2894. def swap(cls, left_lc, right_lc, operator):
  2895. # type:(str,str,UserSearchable)->None
  2896. left_device = Device.objects(logicalCode = left_lc).first() # type: Optional[Device]
  2897. right_device = Device.objects(logicalCode = right_lc).first() # type: Optional[Device]
  2898. if not left_device:
  2899. raise UserServerException(u'设备({})不存在'.format(left_lc))
  2900. if not right_device:
  2901. raise UserServerException(u'设备({})不存在'.format(right_lc))
  2902. if left_device.ownerId != right_device.ownerId:
  2903. raise UserServerException(u'不同经销商设备不能交换二维码')
  2904. raw_left_device = dict(left_device.to_mongo()) # type: Dict
  2905. raw_right_device = dict(right_device.to_mongo()) # type: Dict
  2906. record = DeviceReplacement(
  2907. oldLogicalCode = left_lc,
  2908. newLogicalCode = right_lc,
  2909. oldDevice = raw_left_device,
  2910. newDevice = raw_right_device,
  2911. replaceType = 'swap'
  2912. ).save()
  2913. OperatorLog.log(user = operator,
  2914. level = OperatorLog.LogLevel.CRITICAL,
  2915. operator_name = u'互换设备',
  2916. content = {
  2917. 'ref_id': record.id
  2918. })
  2919. try:
  2920. map(lambda _: _.delete(), [left_device, right_device])
  2921. raw_left_device['logicalCode'] = right_lc
  2922. Device(**raw_left_device).save()
  2923. raw_right_device['logicalCode'] = left_lc
  2924. Device(**raw_right_device).save()
  2925. finally:
  2926. Device.invalid_all_cache(left_device)
  2927. Device.invalid_all_cache(right_device)
  2928. @classmethod
  2929. def rollback_replacement(cls, replacement_id):
  2930. replacement = DeviceReplacement.objects(id = replacement_id).first() # type: Optional[DeviceReplacement]
  2931. if not replacement:
  2932. raise Exception(u'无此调换记录')
  2933. raw_old_device = replacement.oldDevice # type: dict
  2934. raw_new_device = replacement.newDevice # type: dict
  2935. devices = Device.objects(devNo__in = [raw_old_device['devNo'], raw_new_device['devNo']])
  2936. map(lambda _: _.delete(), devices)
  2937. old_device = Device(**raw_old_device).save()
  2938. new_device = Device(**raw_new_device).save()
  2939. updated = replacement.update(revokedTime = datetime.datetime.now())
  2940. if not updated:
  2941. logger.error('cannot update %r' % (replacement,))
  2942. Device.invalid_all_cache(old_device)
  2943. Device.invalid_all_cache(new_device)
  2944. @classmethod
  2945. def bind(cls, devNo, logicalCode, operator = None):
  2946. # type:(str, str, UserSearchable)->None
  2947. document = {
  2948. 'logicalCode': logicalCode,
  2949. 'devNo': devNo,
  2950. 'dateTimeBinded': datetime.datetime.now(),
  2951. 'binder': operator.identity_id if operator else ''
  2952. }
  2953. try:
  2954. Device.get_collection().insert_one(copy.deepcopy(document))
  2955. except DuplicateKeyError:
  2956. result = Device.get_collection().update_one(
  2957. filter = {'devNo': devNo, 'logicalCode': {'$in': [None, '']}},
  2958. update = {'$set': document},
  2959. upsert = False)
  2960. if result.matched_count <= 0:
  2961. raise UserServerException(u'IMEI({})已经绑定'.format(devNo))
  2962. elif result.modified_count <= 0:
  2963. raise UserServerException(u'绑定失败,请重试')
  2964. Device.__base_cache_mgr.update_l_cache(devNo, logicalCode)
  2965. Device.get_dev(devNo)
  2966. try:
  2967. CheckDevice.get_collection().update_one({'imei': devNo},
  2968. {'$set':
  2969. {
  2970. 'imei': devNo,
  2971. 'logicalCode': logicalCode,
  2972. 'bindTime': datetime.datetime.now()
  2973. }
  2974. },
  2975. upsert = True)
  2976. except Exception, e:
  2977. logger.exception(e)
  2978. @classmethod
  2979. def unbind(cls, dev, operator = None):
  2980. # type: (DeviceDict, UserSearchable)->None
  2981. if not dev:
  2982. raise UserServerException(u'该设备不存在,无须解绑')
  2983. if dev.is_registered:
  2984. raise UserServerException(u'设备已经注册,无法解绑')
  2985. device = dev.my_obj # type: Device
  2986. if not device:
  2987. raise UserServerException(u'该设备不存在,无须解绑')
  2988. if operator:
  2989. if operator.identity_id != device.binder:
  2990. raise UserServerException(u'不是您绑定的设备,您无法进行解绑定')
  2991. device.delete()
  2992. Device.invalid_all_cache(dev)
  2993. try:
  2994. CheckDevice.get_collection().delete_one({'imei': dev.devNo})
  2995. except:
  2996. pass
  2997. @classmethod
  2998. def get_sim_expire_notify_devices(cls, dealer_id = None, extra_filter = None,
  2999. fields = {'_id': 0, 'logicalCode': 1, 'ownerId': 1}):
  3000. now = arrow.now()
  3001. this_month_first_day = now.replace(day = 1, hour = 0, minute = 0, second = 0, microsecond = 0) # type: arrow
  3002. next_month_first_day = this_month_first_day.shift(months = 1) # type: arrow
  3003. query = cls.generate_sim_expire_query(expire_start_date = this_month_first_day.naive,
  3004. expire_end_date = next_month_first_day.naive,
  3005. dealer_id = dealer_id,
  3006. sim_status = SimStatus.Updated)
  3007. if extra_filter:
  3008. query.update(extra_filter)
  3009. devices = Device.get_collection().find(query, fields)
  3010. return list(devices)
  3011. @classmethod
  3012. def set_debug_flag(cls, devNo, flag = ''):
  3013. Device.get_collection().update({'devNo': devNo}, {'$set': {'debug': flag}}, upsert = False)
  3014. Device.invalid_device_cache(devNo)
  3015. @staticmethod
  3016. def bolai_get_node_dev(cls, gatewayDevNo, nodeIndex):
  3017. devObj = Device.objects.get(devNo = gatewayDevNo)
  3018. nodeDevNo = devObj.nodeDict.get(nodeIndex, None)
  3019. if not nodeDevNo:
  3020. return None
  3021. devObj = Device.objects.get(devNo = nodeDevNo)
  3022. return devObj
  3023. @classmethod
  3024. def switch_api_mode(cls, logicalCode, isApi):
  3025. # type:(Union[str, unicode, list], bool) -> bool
  3026. if isinstance(logicalCode, list):
  3027. logicalCodes = logicalCode
  3028. elif isinstance(logicalCode, (str, unicode)):
  3029. logicalCodes = [logicalCode]
  3030. else:
  3031. return
  3032. if not logicalCodes:
  3033. return
  3034. devs = Device.objects.filter(logicalCode__in=logicalCodes)
  3035. if devs:
  3036. result = devs.update(isApi=isApi)
  3037. Device.invalid_many_device_cache(map(lambda _: _.devNo, devs))
  3038. return result
  3039. @classmethod
  3040. def check_and_update_tcpip_info(cls,dev,devPort,serverIp,serverPort):
  3041. if not dev.network_address:
  3042. devObj = Device.objects.get(devNo = dev['devNo'])
  3043. devObj.otherConf['devPort'] = devPort
  3044. devObj.server = serverIp + ':' + str(serverPort)
  3045. devObj.save()
  3046. Device.invalid_device_cache(dev['devNo'])
  3047. oldServer,oldPort,oldLabel = dev.network_address
  3048. if 'devPort' not in dev.otherConf or dev.otherConf['devPort'] != devPort or oldLabel != 'car-tcp-ip' or oldServer != serverIp or oldPort != serverPort:
  3049. devObj = Device.objects.get(devNo = dev['devNo'])
  3050. devObj.otherConf['devPort'] = devPort
  3051. devObj.server = serverIp + ':' + str(serverPort)
  3052. devObj.save()
  3053. Device.invalid_device_cache(dev['devNo'])
  3054. @property
  3055. def owner(self):
  3056. # type:()->Dealer
  3057. if hasattr(self, '__owner__'):
  3058. return getattr(self, '__owner__')
  3059. if not self.ownerId:
  3060. return None
  3061. Dealer = import_string('apps.web.dealer.models.Dealer')
  3062. dealer = Dealer.objects(id = self.ownerId).first()
  3063. if dealer:
  3064. setattr(self, '__owner__', dealer)
  3065. return dealer
  3066. @owner.setter
  3067. def owner(self, value):
  3068. setattr(self, '__owner__', value)
  3069. class DeviceDict(dict):
  3070. """
  3071. 设备的缓存表示. 注意不能直接當作字典進行json編碼
  3072. """
  3073. @property
  3074. def id(self):
  3075. if "id" not in self.v:
  3076. Device.invalid_device_cache(self.devNo)
  3077. _id = Device.get_dev(self.devNo).get("id")
  3078. else:
  3079. _id = self["id"]
  3080. return _id
  3081. @property
  3082. def cycle(self):
  3083. return self['cycle']
  3084. @property
  3085. def majorDeviceType(self):
  3086. return self['majorDeviceType']
  3087. @property
  3088. def status(self):
  3089. return self['status']
  3090. @property
  3091. def need_fetch_online(self):
  3092. if self.online == DeviceOnlineStatus.DEV_STATUS_ONLINE:
  3093. return True
  3094. # 如果离线,但是在2个小时内有上线记录,也需要去检查下状态
  3095. if self.lastUpdateOnlineTime > 0:
  3096. elapse_time = (long(time.time() * 1000) - long(self['updateTime']))
  3097. if elapse_time < 2 * 60 * 60 * 1000:
  3098. return True
  3099. return False
  3100. @property
  3101. def statusInfo(self):
  3102. return self['statusInfo']
  3103. @property
  3104. def online(self):
  3105. return self['online']
  3106. @property
  3107. def offTime(self):
  3108. # type: ()->long
  3109. return self['offTime']
  3110. @property
  3111. def lastUpdateOnlineTime(self):
  3112. # type: ()->long
  3113. return self['updateTime']
  3114. @property
  3115. def signal(self):
  3116. # type: ()->int
  3117. return self['signal']
  3118. @property
  3119. def devNo(self):
  3120. return self['devNo']
  3121. @property
  3122. def logicalCode(self):
  3123. return self['logicalCode']
  3124. @property
  3125. def groupId(self):
  3126. return self.get('groupId', Device.groupId.default)
  3127. @property
  3128. def group(self): # type:() -> GroupDict
  3129. if hasattr(self, '__group__'):
  3130. return getattr(self, '__group__')
  3131. group = Group.get_group(self.groupId)
  3132. if group:
  3133. setattr(self, '__group__', group)
  3134. return group
  3135. @property
  3136. def is_registered(self):
  3137. # type:()->bool
  3138. return Device.utils_is_registered(self)
  3139. @property
  3140. def is_expired(self):
  3141. # type:()->bool
  3142. return Device.utils_is_expired(self)
  3143. @property
  3144. def is_to_expired(self):
  3145. expire_date = self.fixedSimExpireDate
  3146. if not expire_date:
  3147. return False
  3148. now = arrow.now()
  3149. start_date = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0).naive
  3150. end_date = now.replace(day=(Const.SIM_CARD_FORBIDDEN_DAY + 1), hour=0, minute=0, second=0,
  3151. microsecond=0).naive
  3152. if (expire_date > start_date) and (expire_date < end_date):
  3153. return True
  3154. else:
  3155. return False
  3156. @property
  3157. def channelType(self):
  3158. return Device.utils_channel_type(self)
  3159. @property
  3160. def coreVer(self):
  3161. return self.get('coreVer', '')
  3162. @property
  3163. def softVer(self):
  3164. return self.get('softVer', '')
  3165. @property
  3166. def mf(self):
  3167. return self.get('mf', '')
  3168. @property
  3169. def ownerId(self):
  3170. return self.get('ownerId', Device.ownerId.default)
  3171. @property
  3172. def simExpireDate(self):
  3173. sim_expire_date = self.get('simExpireDate', Device.simExpireDate.default)
  3174. if not sim_expire_date:
  3175. return sim_expire_date
  3176. if isinstance(sim_expire_date, basestring):
  3177. return datetime.datetime.strptime(sim_expire_date, Const.DATE_FMT)
  3178. else:
  3179. return sim_expire_date
  3180. @property
  3181. def formatSimExpireDate(self):
  3182. # type: ()->basestring
  3183. if Device.utils_is_bluetooth(self.logicalCode):
  3184. return '-'
  3185. expire_date = self.fixedSimExpireDate
  3186. if expire_date:
  3187. return expire_date.strftime(Const.DATE_FMT)
  3188. else:
  3189. return u'待更新'
  3190. @property
  3191. def expireDate(self):
  3192. return self.get('expireDate', Device.expireDate.default)
  3193. @property
  3194. def sim_expire_notify(self):
  3195. return Device.check_sim_expire_notify(self)
  3196. @property
  3197. def fixedSimExpireDate(self):
  3198. return Device.get_sim_expire_date(self)
  3199. @property
  3200. def simStatus(self):
  3201. return self.get('simStatus', SimStatus.Updated)
  3202. @property
  3203. def devType(self):
  3204. # type: ()->Dict
  3205. return self.get('devType', {})
  3206. @property
  3207. def devTypeId(self):
  3208. return self.devType.get('id')
  3209. @property
  3210. def devTypeName(self):
  3211. return self.devType.get('name')
  3212. @property
  3213. def devTypeCode(self):
  3214. # type: ()->str
  3215. return self.devType.get('code')
  3216. @property
  3217. def devTypeFeatures(self):
  3218. return self.devType.get('features', {})
  3219. @property
  3220. def is_online_type(self):
  3221. # type: ()->bool
  3222. return self.devType.get('online', None)
  3223. @property
  3224. def hwVer(self):
  3225. return self.get('hwVer', '')
  3226. @property
  3227. def iccid(self):
  3228. return self.get('iccid', '')
  3229. @property
  3230. def imsi(self):
  3231. return self.get('imsi', '')
  3232. @property
  3233. def server(self):
  3234. return self.get('server', Device.server.default)
  3235. @property
  3236. def network_address(self):
  3237. host, port = self.server.split(':')
  3238. host = SysParas.get_private_ip(str(host))
  3239. if int(port) < 30000:
  3240. return host, port, 'mqtt'
  3241. elif int(port) < 50000:
  3242. return host, port, 'tcpip'
  3243. else:
  3244. return host, port, 'car-tcp-ip'
  3245. @property
  3246. def lbs(self):
  3247. return self['lbs']
  3248. @property
  3249. def lat(self):
  3250. return self['lat']
  3251. @property
  3252. def lng(self):
  3253. return self['lng']
  3254. @property
  3255. def debug(self):
  3256. return self.get('debug', '')
  3257. @property
  3258. def groupNumber(self):
  3259. return self.get('groupNumber', '')
  3260. @property
  3261. def otherConf(self):
  3262. return self.get('otherConf', {})
  3263. @property
  3264. def support_reliable(self):
  3265. tokens = self.driverVersion.split('.')
  3266. if tokens[0] >= 'v5':
  3267. if 'start_device_realiable' in self.deviceAdapter.__class__.__dict__:
  3268. return True
  3269. else:
  3270. return False
  3271. else:
  3272. return False
  3273. @property
  3274. def support_sid_topic(self):
  3275. try:
  3276. tokens = self.softVer.split('.')
  3277. if len(tokens) == 3:
  3278. mainVersion = int(str(tokens[0]).replace("v", ""))
  3279. if 7 <= mainVersion < 40:
  3280. logger.debug('version is: {}; sidTopic = False'.format(self.softVer))
  3281. return False
  3282. if int(tokens[2]) >= int(Const.TOPIC_WITH_SID_VERSION):
  3283. logger.debug('version is: {}; sidTopic = True'.format(self.softVer))
  3284. return True
  3285. logger.debug('version is: {}; sidTopic = False'.format(self.softVer))
  3286. return False
  3287. except Exception as e:
  3288. logger.debug('exception. version is: {}; sidTopic = False'.format(self.softVer))
  3289. logger.exception(e)
  3290. return False
  3291. @property
  3292. def ban(self):
  3293. return self.get('disableDevice', False)
  3294. @property
  3295. def driverCode(self):
  3296. return self.get('driverCode', '000000')
  3297. @property
  3298. def driverVersion(self):
  3299. return self.get('driverVersion', '0.0.0')
  3300. @property
  3301. def support_power_graph(self):
  3302. return self.get('otherConf', dict()).get('supportPG', False)
  3303. @property
  3304. def is_auto_refund(self):
  3305. try:
  3306. return self.my_obj.is_auto_refund()
  3307. except Exception as e:
  3308. logger.exception(e)
  3309. return False
  3310. @property
  3311. def is_DND_now(self):
  3312. if self.get('isDND', False) is False:
  3313. return False
  3314. DNDRange = self.get('isDNDTimeInterval', [])
  3315. nowTime = datetime.datetime.now().strftime('%H:%M:%S')
  3316. for _ in DNDRange:
  3317. if _.get('isDNDStartTime') <= nowTime <= _.get('isDNDEndTime'):
  3318. return True
  3319. return False
  3320. @property
  3321. def is_fault(self):
  3322. return self["isFault"]
  3323. @property
  3324. def is_warning(self):
  3325. return self["deviceWarning"]
  3326. @property
  3327. def isRent(self):
  3328. return self.get("isRent", False)
  3329. @property
  3330. def isApi(self):
  3331. return self.get("isApi")
  3332. @property
  3333. def disableADExpireDate(self):
  3334. return self.get("disableADExpireDate")
  3335. @property
  3336. def bill_as_service_feature(self):
  3337. # type:()-> BillAsServiceFeature
  3338. return BillAsServiceFeature(self.devTypeFeatures.get('billAsService', {}))
  3339. @property
  3340. def policyTemp(self):
  3341. return self.get("policyTemp", {})
  3342. @property
  3343. def priceDescription(self):
  3344. if self.get('priceDescription'):
  3345. priceDescription = self['priceDescription']
  3346. priceDescription = priceDescription.replace('\n', '<br>')
  3347. priceDescription = priceDescription.replace(' ', '&nbsp;')
  3348. return priceDescription
  3349. elif self.policyTemp and not self.get('priceDescription'):
  3350. forApps = self.policyTemp.get('forApps', {})
  3351. policyType = forApps.get('policyType')
  3352. if policyType == 'time':
  3353. prices = forApps.get('rule', {}).get('prices', [])
  3354. text = '计费模式: 按功率计费' + '<br>'
  3355. lastStep = 0
  3356. for price in prices:
  3357. text += '<b>{}</b>-<b>{}</b>瓦, <b>{}</b>元/小时 <br>'.format(lastStep, price['power'], price['price'])
  3358. lastStep = price['power']
  3359. return text
  3360. elif policyType == 'elec':
  3361. price = forApps.get('rule', {}).get('price')
  3362. text = '计费模式: 按电量计费' + '<br>'
  3363. if price:
  3364. text += '单价: <b>{}</b>元/度 <br>'.format(price)
  3365. return text
  3366. else:
  3367. # 保留一个按次计费
  3368. pass
  3369. else:
  3370. pass
  3371. @property
  3372. def identity_info(self):
  3373. return {
  3374. 'devNo': self.devNo,
  3375. 'logicalCode': self.logicalCode,
  3376. 'devTypeName': self.devTypeName,
  3377. 'devTypeCode': self.devTypeCode,
  3378. 'groupId': self.groupId,
  3379. 'groupName': self.group.groupName,
  3380. 'groupNumber': self.groupNumber,
  3381. 'address': self.group.address
  3382. }
  3383. @cached_property
  3384. def deviceAdapter(self): # type:()->SmartBox
  3385. return ActionDeviceBuilder.create_action_device(self)
  3386. @cached_property
  3387. def eventer(self): # type: ()->EventBuilder
  3388. return ActionDeviceBuilder.create_eventer_by_adapter(self.deviceAdapter)
  3389. @cached_property
  3390. def parts(self):
  3391. return Part.objects.filter(logicalCode=self.logicalCode)
  3392. @cached_property
  3393. def owner(self): # type:()->Dealer
  3394. cls = import_string('apps.web.dealer.models.Dealer')
  3395. dealer = cls.objects(id=self.ownerId).first()
  3396. return dealer
  3397. @cached_property
  3398. def my_obj(self): # type:() -> Device
  3399. return Device.objects(devNo=self.devNo).first()
  3400. @cached_property
  3401. def dealer(self): # type:() -> DealerDict
  3402. cls = import_string('apps.web.dealer.models.Dealer')
  3403. dealer = cls.get_dealer(self.ownerId)
  3404. return dealer
  3405. @property
  3406. def v(self):
  3407. return dict(self)
  3408. def __repr__(self):
  3409. return 'DeviceDict<logicalCode={} devNo={}>'.format(self.logicalCode, self.devNo)
  3410. def __update_status(self):
  3411. Device.get_device_status_cache(self)
  3412. def __getitem__(self, k):
  3413. if k in self:
  3414. return super(DeviceDict, self).__getitem__(k)
  3415. if k in ['online', 'status', 'signal', 'offTime', 'statusInfo', 'updateTime', 'offTime', 'deviceWarning']:
  3416. assert 'logicalCode' in self, 'must has logicalCode field'
  3417. self.__update_status()
  3418. elif k == 'majorDeviceType':
  3419. self['majorDeviceType'] = Device.utils_major_type(self)
  3420. elif k in ['lbs', 'lat', 'lng']:
  3421. location = self.get('location', None)
  3422. lbs = True
  3423. if not location:
  3424. lat = 360
  3425. lng = 360
  3426. lbs = False
  3427. else:
  3428. try:
  3429. lat = location['coordinates'][1]
  3430. except (KeyError, IndexError):
  3431. lat = 360
  3432. lbs = False
  3433. try:
  3434. lng = location['coordinates'][0]
  3435. except (KeyError, IndexError):
  3436. lng = 360
  3437. lbs = False
  3438. self.update({'lbs': lbs, 'lat': lat, 'lng': lng})
  3439. return super(DeviceDict, self).__getitem__(k)
  3440. def set_online(self, signal=None):
  3441. """
  3442. 设置设备在线,填充updateTime
  3443. 设置设备离线,填充offTime
  3444. :param signal:
  3445. :return:
  3446. """
  3447. new_online_info = Device.update_online_cache(self.devNo, DeviceOnlineStatus.DEV_STATUS_ONLINE, signal)
  3448. self.update(new_online_info)
  3449. def set_offline(self):
  3450. new_online_info = Device.update_online_cache(self.devNo, DeviceOnlineStatus.DEV_STATUS_OFFLINE)
  3451. self.update(new_online_info)
  3452. def is_authorized_to_dealer(self, dealer_id):
  3453. return self.ownerId == dealer_id
  3454. def package(self, packageId, isTemporary=False):
  3455. if isTemporary:
  3456. washConfig = self.get('tempWashConfig', {})
  3457. else:
  3458. washConfig = self.get('washConfig', {})
  3459. package = washConfig.get(packageId)
  3460. if package:
  3461. package['packageId'] = packageId
  3462. package['isTemporary'] = isTemporary
  3463. return package
  3464. def update_device_obj(self, **kwargs):
  3465. if len(kwargs.keys()) <= 0:
  3466. return
  3467. Device.get_collection().update_one({
  3468. 'devNo': self.devNo
  3469. }, {
  3470. '$set': kwargs
  3471. })
  3472. Device.invalid_device_cache(self.devNo)
  3473. try:
  3474. delattr(self, '__my_obj__')
  3475. except Exception as e:
  3476. pass
  3477. def update_other_conf(self, **kwargs):
  3478. _set = {}
  3479. for key, value in kwargs.iteritems():
  3480. _set['otherConf.{}'.format(key)] = value
  3481. self.update_device_obj(**_set)
  3482. def get_other_conf_item(self, item_name, default=None):
  3483. return self.my_obj.otherConf.get(item_name, default)
  3484. def support_dev_type_features(self, feature_name):
  3485. return self.devTypeFeatures.get(feature_name, False)
  3486. def is_port_can_use(self, port):
  3487. # TODO 追加是否能够续充的特性
  3488. canAdd = self.support_dev_type_features("canAdd")
  3489. return self.deviceAdapter.is_port_can_use(port, canAdd)
  3490. class FeedBack(Searchable):
  3491. ownerId = StringField(verbose_name = u"所有者", default = "")
  3492. openId = StringField(verbose_name = u"微信ID", default = "")
  3493. nickname = StringField(verbose_name = u"名称", max_length = 255, default = "")
  3494. description = StringField(verbose_name = u"投诉内容", max_length = 255, default = "")
  3495. status = IntField(verbose_name = u"处理状态", default = Const.FeedBackResult.UNTREATED) # 为0:未处理,1:已处理,2:驳回
  3496. feedType = StringField(verbose_name = u"反馈类型(故障,订单投诉)", default = "refund")
  3497. createTime = StringField(verbose_name = u"创建时间",
  3498. default = lambda: datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
  3499. dealTime = StringField(verbose_name = u"处理时间", default = "")
  3500. phone = StringField(verbose_name = u"联系电话", default = "")
  3501. devTypeName = StringField(verbose_name = u"设备类型", default = "")
  3502. dealerRemark = StringField(verbose_name = u"经销商回复", default = "")
  3503. imgList = ListField(verbose_name = u'图片列表(往往作用户说明作用)', default = [])
  3504. dealerImgList = ListField(verbose_name = u'经销商回复图片', default = [])
  3505. isRead = BooleanField(verbose_name = u'消息已读', default = False)
  3506. detailInfo = DictField(verbose_name = u'各投诉类型详细信息', default = None)
  3507. devNo = StringField(verbose_name = u"设备编号", default = None)
  3508. logicalCode = StringField(verbose_name = u"逻辑编码", default = None)
  3509. groupId = StringField(verbose_name = u"逻辑编码", default = None)
  3510. groupNumber = StringField(verbose_name = u"设备组内编号", default = None)
  3511. groupName = StringField(verbose_name = u"设备组内编号", default = None)
  3512. address = StringField(verbose_name = u"设备组内编号", default = None)
  3513. consumeRecordOrderNo = StringField(default = None)
  3514. coins = VirtualCoinField(verbose_name = u"操作数目,比如退几个币", default = None)
  3515. resultDesc = StringField(verbose_name = u"处理描述", default = None)
  3516. meta = {"collection": "FeedBacks", "db_alias": "logdata"}
  3517. search_fields = (
  3518. 'nickname', 'description', 'detailInfo.logicalCode', 'detailInfo.groupNumber', 'detailInfo.groupName')
  3519. @property
  3520. def detail(self):
  3521. rv = {
  3522. 'ownerId': self.ownerId,
  3523. 'nickname': self.nickname,
  3524. 'description': self.description,
  3525. 'status': self.status,
  3526. 'feedType': self.feed_type,
  3527. 'createTime': self.createTime,
  3528. 'dealTime': self.dealTime,
  3529. 'phone': self.phone,
  3530. 'dealerRemark': self.dealerRemark,
  3531. 'imgList': self.imgList,
  3532. 'dealerImgList': self.dealerImgList,
  3533. 'isRead': self.isRead,
  3534. 'detailInfo': {}
  3535. }
  3536. if self.openId:
  3537. rv['openId'] = self.openId
  3538. if self.detailInfo:
  3539. rv['detailInfo'].update(self.detailInfo)
  3540. else:
  3541. if self.consumeRecordOrderNo:
  3542. rv['detailInfo'].update({
  3543. 'orderNo': self.consumeRecordOrderNo
  3544. })
  3545. if 'orderNo' in rv['detailInfo']:
  3546. order_no = rv['detailInfo'].get('orderNo')
  3547. if order_no:
  3548. from apps.web.user.models import ConsumeRecord
  3549. order = ConsumeRecord.objects.filter(ownerId=self.ownerId, orderNo = order_no).first() # type: ConsumeRecord
  3550. rv['detailInfo'].update(order.info_for_feedback)
  3551. if 'coins' not in rv['detailInfo'] and self.coins:
  3552. rv['detailInfo']['coins'] = self.coins
  3553. if self.logicalCode:
  3554. rv['detailInfo'].update({
  3555. 'logicalCode': self.logicalCode,
  3556. 'devTypeName': self.devTypeName,
  3557. 'groupNumber': self.groupNumber,
  3558. 'groupName': self.groupName,
  3559. 'address': self.address,
  3560. })
  3561. rv['detailInfo'].pop('devNo', None)
  3562. rv['detailInfo'].pop('devTypeCode', None)
  3563. return rv
  3564. @property
  3565. def feed_type(self):
  3566. if self.consumeRecordOrderNo:
  3567. return 'netpay'
  3568. if self.feedType in ['refund', 'upper']:
  3569. return 'other'
  3570. else:
  3571. return self.feedType
  3572. @property
  3573. def summary(self):
  3574. rv = {
  3575. 'id': str(self.id),
  3576. 'nickname': self.nickname,
  3577. 'feedType': self.feed_type,
  3578. 'status': self.status,
  3579. 'description': self.description,
  3580. 'dealerRemark': self.dealerRemark,
  3581. 'createTime': self.createTime,
  3582. 'detailInfo': {}
  3583. }
  3584. if self.logicalCode:
  3585. rv['detailInfo'].update({
  3586. 'logicalCode': self.logicalCode,
  3587. 'devTypeName': self.devTypeName,
  3588. 'groupName': self.groupName
  3589. })
  3590. elif self.detailInfo and 'logicalCode' in self.detailInfo:
  3591. rv['detailInfo'].update({
  3592. 'logicalCode': self.detailInfo.get('logicalCode'),
  3593. 'devTypeName': self.detailInfo.get('devTypeName'),
  3594. 'groupName': self.detailInfo.get('groupName')
  3595. })
  3596. return rv
  3597. @classmethod
  3598. def get_unhandled_count(cls, **kwargs): # type:(Dict[str, Any])->int
  3599. return cls.objects(status = Const.FeedBackResult.UNTREATED, **kwargs).count()
  3600. @property
  3601. def message_type(self):
  3602. # type: ()->basestring
  3603. mapping = {
  3604. 'fault': u'设备故障',
  3605. 'refund': u'退币申请',
  3606. 'upper': u'申请上分'
  3607. }
  3608. return mapping.get(self.feedType, u'报告老板')
  3609. def set_handled(self, **kwargs):
  3610. return self.update(status = Const.FeedBackResult.TREATED, isRead = False, **kwargs)
  3611. def set_rejected(self, **kwargs):
  3612. return self.update(status = Const.FeedBackResult.REJECTED, isRead = False, **kwargs)
  3613. def handle(self, action, **kwargs):
  3614. if action == 'reject':
  3615. self.set_rejected(**kwargs)
  3616. else:
  3617. self.set_handled(**kwargs)
  3618. @property
  3619. def my_logicalCode(self):
  3620. if self.detailInfo and 'logicalCode' in self.detailInfo:
  3621. return self.detailInfo['logicalCode']
  3622. else:
  3623. return self.logicalCode
  3624. @property
  3625. def my_group_id(self):
  3626. if self.groupId:
  3627. return self.groupId
  3628. else:
  3629. if self.detailInfo:
  3630. return self.detailInfo.get('groupId', None)
  3631. else:
  3632. return None
  3633. class GroupDict(dict):
  3634. """
  3635. 组的缓存表示
  3636. """
  3637. def __repr__(self):
  3638. return '<GroupDict id=%s>' % (self.get('groupId', 'unknown'),)
  3639. @property
  3640. def v(self):
  3641. return dict(self)
  3642. @property
  3643. def ownerId(self):
  3644. return self['ownerId']
  3645. @property
  3646. def owner(self):
  3647. # type:()->Dealer
  3648. if hasattr(self, '__owner__'):
  3649. return getattr(self, '__owner__')
  3650. Dealer = import_string('apps.web.dealer.models.Dealer')
  3651. dealer = Dealer.objects(id=self.ownerId).first()
  3652. if dealer:
  3653. setattr(self, '__owner__', dealer)
  3654. return dealer
  3655. @property
  3656. def object(self): # type() -> Group
  3657. group = getattr(self, '__object__', None)
  3658. if not group:
  3659. group = Group.objects.get(id=self.id)
  3660. setattr(self, '__object__', group)
  3661. return group
  3662. @property
  3663. def id(self):
  3664. return ObjectId(self['groupId'])
  3665. @property
  3666. def groupId(self):
  3667. return self['groupId']
  3668. @property
  3669. def groupName(self):
  3670. return self.get('groupName')
  3671. @property
  3672. def address(self):
  3673. return self.get('address', '')
  3674. @property
  3675. def partners(self):
  3676. return self.partnersDict.values()
  3677. @property
  3678. def otherConf(self):
  3679. return self.get("otherConf", dict())
  3680. @property
  3681. def elecFee(self):
  3682. return RMB(self.otherConf.get("elecFee", 0))
  3683. @property
  3684. def partnersDict(self):
  3685. return self.get("partnerDict", {})
  3686. @property
  3687. def ruleDict(self): # type:() -> dict
  3688. return self.get("ruleDict", dict())
  3689. def rule_is_accepted(self, ruleId): # type:(str) -> bool
  3690. return ruleId in self.ruleDict
  3691. def get_accepted_rule(self, ruleId): # type:(str) -> str
  3692. return self.ruleDict.get("ruleId")
  3693. @property
  3694. def occupied_numbers(self):
  3695. # type: ()->Set[str]
  3696. return set(
  3697. [
  3698. _['groupNumber'] for _ in Device.get_collection().find(
  3699. {'groupId': self.get('groupId')}, {'groupNumber': 1, '_id': 0})
  3700. ]
  3701. )
  3702. @property
  3703. def is_free(self):
  3704. return self.get('isFree', False)
  3705. @property
  3706. def card_rule_list(self):
  3707. rule_list = []
  3708. if not self.get("cardRuleDict"):
  3709. Dealer = import_string('apps.web.dealer.models.Dealer')
  3710. dealer = Dealer.objects.get(id = self.ownerId)
  3711. card_rule_dict = dealer.format_card_discount
  3712. else:
  3713. card_rule_dict = self.get("cardRuleDict")
  3714. for k, v in card_rule_dict.items():
  3715. rule_list.append({'payAmount': k, 'coins': v})
  3716. return rule_list
  3717. @property
  3718. def recharge_rule_list(self):
  3719. ruleDict = self.get('ruleDict', {})
  3720. res = [
  3721. {
  3722. "id": ruleId,
  3723. "payAmount": float(ruleId),
  3724. "coins": float(coins),
  3725. } for ruleId, coins in ruleDict.items()
  3726. ]
  3727. # 优惠充值界面套餐排序(根据金币)升序显示
  3728. res = sorted(res, key = lambda x: x['coins'])
  3729. return res
  3730. @property
  3731. def currencyGroup(self):
  3732. if 'currencyGroup' not in self:
  3733. Group.CacheMgr.invalid_group_cache([self.groupId])
  3734. group = Group.get_group(self.groupId) # type: GroupDict
  3735. self.update(group.v)
  3736. return self.get('currencyGroup')
  3737. @property
  3738. def identity_info(self):
  3739. return {
  3740. 'groupId': self.groupId,
  3741. 'groupName': self.groupName,
  3742. 'address': self.address
  3743. }
  3744. @property
  3745. def popPriceDescriptionButton(self):
  3746. return self.get('popPriceDescriptionButton', False)
  3747. @property
  3748. def totalShare(self): # type:() -> Percent
  3749. return sum([Percent(_['percent']) for _ in self.partners if _.get("isActive")], Percent(0))
  3750. @property
  3751. def hasPayElecFee(self):
  3752. return bool(filter(lambda x: x.get("payElecFee"), self.partners))
  3753. def remove_partner(self, partnerId):
  3754. """
  3755. 组内移除合伙人
  3756. """
  3757. self.partnersDict.pop(partnerId, None)
  3758. result = self.object.update(partnerList=self.partnersDict.values())
  3759. self.object.invalid_group_cache([str(self.id)])
  3760. self.object.__class__.CacheMgr.invalid_group_ids_of_partner_cache(partnerId)
  3761. return result
  3762. def update_partner(self, partnerId, ratio, payElecFee, isActive):
  3763. """
  3764. 更新合伙人信息
  3765. """
  3766. totalShare = self.totalShare
  3767. curShare = Percent(self.partnersDict.get(partnerId, dict()).get("percent", 0))
  3768. # 地址组的参数校验
  3769. if totalShare - curShare + Percent(ratio) > Percent(100):
  3770. raise ValueError("分成比例设置错误")
  3771. if payElecFee and self.hasPayElecFee:
  3772. raise ValueError("该地址已有电费承担方,请勿重复设置")
  3773. partnersDict = self.partnersDict
  3774. if partnerId in partnersDict:
  3775. partnersDict[partnerId].update({
  3776. 'percent': ratio,
  3777. 'id': partnerId,
  3778. 'payElecFee': payElecFee,
  3779. 'isActive': isActive
  3780. })
  3781. else:
  3782. partnersDict[partnerId] = {
  3783. 'percent': ratio,
  3784. 'id': partnerId,
  3785. 'payElecFee': payElecFee,
  3786. 'isActive': isActive
  3787. }
  3788. result = self.object.update(partnerList=partnersDict.values())
  3789. self.object.__class__.CacheMgr.invalid_group_ids_of_partner_cache(partnerId)
  3790. self.object.invalid_group_cache([str(self.id)])
  3791. return result
  3792. class RequestBodyDict(dict):
  3793. def __init__(self, *args, **kwargs):
  3794. dict.__init__(self, *args, **kwargs)
  3795. self.__dict__ = self
  3796. def __repr__(self):
  3797. return '<RequestBodyDict>'
  3798. class CheckDevice(Searchable):
  3799. logicalCode = StringField(verbose_name = u'设备逻辑码')
  3800. imei = StringField(verbose_name = u'设备电子标签', unique = True)
  3801. testTime = DateTimeField(verbose_name = u'开始测试时间')
  3802. testResult = IntField(verbose_name = u'测试结果', default = 0)
  3803. testResultDesc = StringField(verbose_name = u'测试结果描述', default = '')
  3804. bindTime = DateTimeField(verbose_name = u'绑定时间')
  3805. label = StringField(verbose_name = u'设备标记', default = '')
  3806. checkSuit = DictField(verbose_name = u'测试套件', default = {})
  3807. # 生产是先上线测试, 在挑一个模块测试, 到客户那里一些关键信息没有, 先记录下来
  3808. server = StringField(verbose_name = "server")
  3809. imsi = StringField(default = '', verbose_name = 'imsi')
  3810. iccid = StringField(default = '', verbose_name = 'iccid')
  3811. softVer = StringField(verbose_name = "软件版本", default = "")
  3812. mf = StringField(verbose_name = "固件版本", default = "")
  3813. coreVer = StringField(default = '', verbose_name = u'核心版本')
  3814. driverCode = StringField(default = '', verbose_name = 'driverCode')
  3815. driverVersion = StringField(default = '', verbose_name = 'driverVersion')
  3816. meta = {"collection": "check_devices", "db_alias": "logdata"}
  3817. class StockRecord(Searchable):
  3818. token = StringField(verbose_name = 'unique token', default = lambda: str(uuid.uuid4()))
  3819. logicCode = StringField(verbose_name = '设备逻辑码')
  3820. imei = StringField(verbose_name = '设备电子标签')
  3821. stockType = StringField(verbose_name = '操作方式', default = '') # 新增、消耗
  3822. stockTime = StringField(verbose_name = '库存变动时间', default = '')
  3823. number = IntField(verbose_name = '数目', default = 0)
  3824. more = StringField(verbose_name = '备注', default = '')
  3825. meta = {
  3826. "collection": "StockRecord",
  3827. "db_alias": "logdata",
  3828. 'indexes': ['logicCode', 'imei', 'stockType', 'stockTime', 'number', 'more'],
  3829. # 'shard_key':('logicalCode',)
  3830. }
  3831. def __repr__(self): return '<StockRecord id=%s>' % (self.id,)
  3832. class FaultRecord(Searchable):
  3833. """
  3834. 告警记录
  3835. """
  3836. logicalCode = StringField(verbose_name = u'设备逻辑码')
  3837. imei = StringField(verbose_name = u'设备电子标签')
  3838. portNo = IntField(verbose_name = u'端口号', default = 0)
  3839. groupName = StringField(verbose_name = u'地址名称', default = '')
  3840. address = StringField(verbose_name = u'地址', default = '')
  3841. faultCode = StringField(verbose_name = u'故障码', default = '') # 告警的恢复是通过故障码 +故障源匹配,然后进行恢复
  3842. title = StringField(verbose_name = u'标题', default = "")
  3843. description = StringField(verbose_name = u'故障描述', default = '')
  3844. dealerId = ObjectIdField(verbose_name = u'经销商ID')
  3845. createdTime = DateTimeField(verbose_name = u'收到时间', default = datetime.datetime.now)
  3846. status = StringField(verbose_name = u'状态', choices = FAULT_RECORD_STATUS.choices(),
  3847. default = FAULT_RECORD_STATUS.INIT)
  3848. count = IntField(default = 0)
  3849. more = StringField(verbose_name = u'其他信息', default = '')
  3850. detail = DictField(verbose_name = u'详情')
  3851. level = StringField(verbose_name = u'告警状态', choices = FAULT_LEVEL.choices(), default = FAULT_LEVEL.NORMAL)
  3852. alarmEventId = StringField(verbose_name = "告警ID", default = "")
  3853. dealedTime = DateTimeField(verbose_name = u'处理时间', default = datetime.datetime.now)
  3854. dealedDetail = StringField(verbose_name = u'处理信息', default = '')
  3855. meta = {
  3856. "collection": "FaultRecord",
  3857. "db_alias": "logdata",
  3858. 'ordering': ['-createdTime']
  3859. # "shard_key":("imei",)
  3860. }
  3861. def set_status(self, status, **kwargs):
  3862. choices = FAULT_RECORD_STATUS.choices()
  3863. if status not in choices:
  3864. raise NotInChoices('%s not in %s' % (status, choices))
  3865. else:
  3866. return self.update(status = status, **kwargs)
  3867. def to_dict(self):
  3868. return {
  3869. 'id': str(self.id),
  3870. 'logicalCode': self.logicalCode,
  3871. # 'imei': self.imei,
  3872. # 'faultCode': self.faultCode,
  3873. 'description': self.description,
  3874. 'title': self.title or self.logicalCode + u' 告警',
  3875. 'createdTime': self.createdTime.strftime(Const.DATETIME_FMT),
  3876. # 'dealerId': str(self.dealerId),
  3877. 'status': self.status,
  3878. # 'more': self.more,
  3879. # 'detail': self.detail,
  3880. # 'count': self.count,
  3881. 'level': self.level,
  3882. 'groupName': self.groupName,
  3883. # 'address':self.address,
  3884. 'dealedTime': self.dealedTime.strftime(Const.DATETIME_FMT),
  3885. 'dealedDetail': self.dealedDetail,
  3886. 'canCheck': True
  3887. }
  3888. @classmethod
  3889. def unhandled_count_by_dealer(cls, dealerId):
  3890. # type:(ObjectId)->int
  3891. return cls.objects(dealerId = dealerId, status = FAULT_RECORD_STATUS.INIT).count()
  3892. @classmethod
  3893. def record_xf(cls, logicalCode, port, description, faultCode, createdTime, groupId, alarmEventId):
  3894. """
  3895. 记录消防队相关信息
  3896. :return:
  3897. """
  3898. # 过滤掉5分钟以内重复发送的信息
  3899. record = cls.objects.filter(
  3900. logicalCode = logicalCode,
  3901. port = port,
  3902. faultCode = faultCode,
  3903. description = description,
  3904. createdTime__gt = createdTime - datetime.timedelta(minutes = 5)
  3905. )
  3906. if record:
  3907. raise Exception("重复数据")
  3908. group = Group.get_group(groupId)
  3909. devNo = Device.get_devNo_by_logicalCode(logicalCode)
  3910. device = Device.get_dev(devNo)
  3911. record = cls(
  3912. logicalCode = logicalCode,
  3913. imei = devNo,
  3914. portNo = port,
  3915. faultCode = faultCode,
  3916. description = description,
  3917. groupName = group.get("groupName", ""),
  3918. address = group.get("address", ""),
  3919. alarmEventId = alarmEventId,
  3920. dealerId = device.get("ownerId", ""),
  3921. createdTime = createdTime
  3922. )
  3923. record.save()
  3924. def __repr__(self):
  3925. return '<FaultRecord id=%s>' % (self.id,)
  3926. class DeviceEvent(Searchable):
  3927. """
  3928. 对应设备上报的由设备管理存储的设备事件表,可用于统计和在一定程度上恢复线下投币等数据
  3929. 命令码
  3930. 200 握手
  3931. 201 查询设备信息
  3932. 202 参数设置
  3933. 203 移动支付
  3934. 204 移动支付上报事件
  3935. 205 硬币投币事件上报
  3936. 207 心跳包
  3937. 该表不允许任何业务逻辑使用, 仅用来对账和恢复数据
  3938. """
  3939. cmd = IntField(verbose_name = '命令码')
  3940. devNo = StringField(verbose_name = '设备号')
  3941. money = IntField(verbose_name = '投币数额')
  3942. time = IntField(verbose_name = '上报时间戳')
  3943. meta = {'collection': 'events', 'db_alias': 'logdata'}
  3944. class DeviceCommandParam(EmbeddedDocument):
  3945. id = ObjectIdField(default = ObjectId)
  3946. description = StringField()
  3947. key = StringField()
  3948. default = StringField()
  3949. allow_change = BooleanField(default = False)
  3950. type = StringField(default='string')
  3951. def __repr__(self):
  3952. return '<DeviceCommandParam> key=%s default=%s' % (self.key, self.default)
  3953. def to_dict(self):
  3954. return {
  3955. "id": str(self.id),
  3956. "description": self.description,
  3957. "key": self.key,
  3958. "default": self.default,
  3959. "allow_change": self.allow_change
  3960. }
  3961. def to_payload(self, value):
  3962. if not self.allow_change:
  3963. value = self.default
  3964. # 避免字符串的转义 将json 以及 bool 类型的数据统统处理掉
  3965. try:
  3966. if self.type == 'string':
  3967. value = str(value)
  3968. else:
  3969. value = json.loads(value)
  3970. except Exception:
  3971. value = value
  3972. return {str(self.key): value}
  3973. class DeviceCommand(Searchable):
  3974. """
  3975. 直接对模块发送指令 一半适用于 管理平台 或者 厂商平台
  3976. 增添身份 对于该指令的支持
  3977. """
  3978. # 用于区分设备的两个字段 common 优先级大于devTypeCode
  3979. devTypeCode = StringField(verbose_name = u'设备类型编码', default = '')
  3980. common = BooleanField(verbose_name = u'是否所有设备通用', default = False)
  3981. description = StringField(verbose_name = "指令描述", default = u"指令")
  3982. # 对于模板的一些内容
  3983. topic_pre = StringField(verbose_name = "topic前缀", default = "smartBox")
  3984. cmd = IntField(verbose_name = u"指令的cmd", default = 201)
  3985. params = EmbeddedDocumentListField(document_type = DeviceCommandParam, default = [])
  3986. # 命令使用者的身份控制
  3987. active = BooleanField(verbose_name = u"是否启用该指令", default = True)
  3988. clientId = StringField(verbose_name = u"调用方的Id", default = "")
  3989. role = StringField(verbose_name = u"身份", choices = ROLE.choices(), default = "supermanager")
  3990. dateTimeAdded = DateTimeField(verbose_name = u"指令添加时间", default = datetime.datetime.now)
  3991. meta = {'collection': 'DeviceCommands', 'db_alias': 'default'}
  3992. search_fields = ('cmd', 'devTypeCode')
  3993. def __repr__(self):
  3994. return '<DeviceCommand name=%s, identifier=%s, debType=%s>' % (self.description, self.cmd, self.devTypeCode)
  3995. @classmethod
  3996. def common_and_type_specific(cls, logicalCode, commander):
  3997. """
  3998. :param logicalCode:
  3999. :param commander:
  4000. :return:
  4001. """
  4002. def _is_legal(cmd, commanderId):
  4003. if cmd.role == ROLE.supermanager:
  4004. return True
  4005. else:
  4006. return str(commanderId) == cmd.clientId
  4007. dev = Device.get_dev_by_l(logicalCode)
  4008. if not dev:
  4009. return list()
  4010. devTypeCode = dev.devType.get("code")
  4011. cmdQuery = cls.objects(Q(devTypeCode = devTypeCode) | Q(common = True), role = commander.role, active = True)
  4012. dataList = list()
  4013. for _item in cmdQuery:
  4014. if not _is_legal(_item, str(commander.id)):
  4015. continue
  4016. data = _item.get_one()
  4017. data.update({"IMEI": dev.devNo})
  4018. dataList.append(data)
  4019. return dataList
  4020. def to_dict(self):
  4021. return {
  4022. "id": str(self.id),
  4023. "devTypeCode": self.devTypeCode,
  4024. "common": self.common,
  4025. "description": self.description,
  4026. "topic_pre": self.topic_pre,
  4027. "active": self.active,
  4028. "cmd": self.cmd,
  4029. "clientId": self.clientId,
  4030. "role": self.role,
  4031. "params": [_param.to_dict() for _param in self.params]
  4032. }
  4033. def get_one(self):
  4034. """获取指令"""
  4035. return {
  4036. "id": str(self.id),
  4037. "description": self.description,
  4038. "topic_pre": self.topic_pre,
  4039. "cmd": self.cmd,
  4040. "params": [_param.to_dict() for _param in self.params]
  4041. }
  4042. def package_command(self, dev, params):
  4043. """
  4044. 将指令经过一系列校验之后 打包成指定的格式
  4045. :param dev:
  4046. :param params:
  4047. :return:
  4048. """
  4049. # 首先拼接载体部分
  4050. payload = {"IMEI": dev.devNo, "cmd": self.cmd}
  4051. for _param in params:
  4052. paramId = _param.get("id")
  4053. value = _param.get("default")
  4054. param = self.params.filter(id = paramId).first()
  4055. if not param:
  4056. continue
  4057. payload.update(param.to_payload(value))
  4058. return payload
  4059. def supports(self, device): return True
  4060. class Comment(Searchable):
  4061. devNo = StringField(verbose_name = "设备编号", min_length = 1)
  4062. logicalCode = StringField(verbose_name = "逻辑编码", min_length = 1)
  4063. groupId = StringField(verbose_name = "逻辑编码", min_length = 1)
  4064. groupNumber = StringField(verbose_name = "设备组内编号", default = "")
  4065. groupName = StringField(verbose_name = "设备组内编号", default = "")
  4066. address = StringField(verbose_name = "设备组内编号", default = "")
  4067. ownerId = StringField(verbose_name = "所有者", default = "")
  4068. openId = StringField(verbose_name = "微信ID", default = "")
  4069. nickname = StringField(verbose_name = "名称", max_length = 255, default = "")
  4070. ratingList = ListField(verbose_name = "得分", default = [])
  4071. description = StringField(verbose_name = "用户留言", max_length = 255, default = "")
  4072. createTime = StringField(verbose_name = "创建时间",
  4073. default = lambda: datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
  4074. meta = {"collection": "Comment", "db_alias": "logdata"}
  4075. class SIMCard(Searchable):
  4076. iccid = StringField(verbose_name = "iccid", unique = True)
  4077. imsi = StringField(verbose_name = "imsi")
  4078. supplier = StringField(verbose_name = "供应商")
  4079. provider = StringField(verbose_name = "运营商",default = u'移动')
  4080. activeTime = DateTimeField(verbose_name = "激活时间")
  4081. expireTime = DateTimeField(verbose_name = "过期时间")
  4082. chargeTime = DateTimeField(verbose_name = "充值时间")
  4083. channel = StringField(verbose_name = u'通道号', default = '')
  4084. meta = {"collection": "SIMCard", "db_alias": "logdata"}
  4085. class Cell(Searchable):
  4086. logicalCode = StringField(verbose_name = "设备编号", min_length = 1)
  4087. cellNo = StringField(verbose_name = "格子编号", min_length = 1)
  4088. boardNo = IntField(verbose_name = "板地址", default = 0)
  4089. lockNo = IntField(verbose_name = "锁地址", default = 0)
  4090. itemTitle = StringField(verbose_name = "商品标题", default = '')
  4091. itemDesc = StringField(verbose_name = "商品描述", default = '')
  4092. itemPicUrl = StringField(verbose_name = "商品图片URL", default = '')
  4093. itemPrice = IntField(verbose_name = "商品价格,单位分", default = 0)
  4094. lockStatus = StringField(verbose_name = "门锁状态", default = 'close')
  4095. itemStatus = StringField(verbose_name = "商品状态", default = 'empty')
  4096. meta = {"collection": "Cell", "db_alias": "default"}
  4097. @staticmethod
  4098. def update_dev_quantity_from_cell(dev):
  4099. quantity = Cell.objects.filter(logicalCode = dev['logicalCode'], itemStatus = 'full').count()
  4100. consumptionQuantity = Cell.objects.filter(logicalCode = dev['logicalCode'], itemStatus = 'empty').count()
  4101. Device.update_field(dev_no = dev['devNo'],
  4102. update = True,
  4103. quantity = quantity,
  4104. consumptionQuantity = consumptionQuantity)
  4105. class Part(Searchable):
  4106. class Status(IterConstant):
  4107. IDLE = Const.DEV_WORK_STATUS_IDLE
  4108. WORKING = Const.DEV_WORK_STATUS_WORKING
  4109. FORBIDDEN = Const.DEV_WORK_STATUS_FORBIDDEN # 结束运行的状态
  4110. FAULT = Const.DEV_WORK_STATUS_FAULT
  4111. class OnlineStatus(IterConstant):
  4112. ONLINE = 'online'
  4113. OFFLINE = 'offline'
  4114. logicalCode = StringField(verbose_name = "设备编号", min_length = 1)
  4115. ownerId = StringField(verbose_name = "ownerId", min_length = 1)
  4116. partNo = StringField(verbose_name = "部件编码", min_length = 1)
  4117. partName = StringField(verbose_name = "部件名称", min_length = 1)
  4118. partType = StringField(verbose_name = "部件类型编码", default = '5001', min_length = 1) # 部件类型,根据各个对接业务,自己定义
  4119. attachParas = DictField(verbose_name="其余参数", default={})
  4120. dateTimeAdded = DateTimeField(default = datetime.datetime.now, verbose_name = '添加进来的时间')
  4121. dateTimeUpdated = DateTimeField(default = datetime.datetime.now, verbose_name = '更新时间')
  4122. expiredTime = DateTimeField(verbose_name = u'维保过期时间',
  4123. default = datetime.datetime.now() + datetime.timedelta(days = Const.MAINTENANCE_DAYS))
  4124. status = IntField(verbose_name = u'状态',default = Const.DEV_WORK_STATUS_IDLE)
  4125. onlineStatus = StringField(verbose_name = u'在线情况',default = 'online')
  4126. meta = {"collection": "Part", "db_alias": "default"}
  4127. @staticmethod
  4128. def upsert_part(logicalCode, ownerId, partNo, partName, partType):
  4129. # 先把原来一样的part 删除掉
  4130. Part.objects.filter(logicalCode = logicalCode, partName = partName, partNo__ne = partNo).delete()
  4131. count = Part.objects.filter(logicalCode = logicalCode, partNo = partNo).count()
  4132. if count == 0: # 如果没有,说明是首次上线
  4133. if partName == u'网络板':
  4134. part = Part(
  4135. logicalCode = logicalCode,
  4136. ownerId = ownerId,
  4137. partNo = partNo,
  4138. partName = partName,
  4139. partType = partType,
  4140. expiredTime = datetime.datetime.now() + datetime.timedelta(days = 365)
  4141. )
  4142. else:
  4143. part = Part(
  4144. logicalCode = logicalCode,
  4145. ownerId = ownerId,
  4146. partNo = partNo,
  4147. partName = partName,
  4148. partType = partType,
  4149. )
  4150. part.save()
  4151. else:
  4152. return
  4153. @staticmethod
  4154. def insert_part_if_not_exist(logicalCode, ownerId, partNo, partName,partType='',partStatus = Const.DEV_WORK_STATUS_IDLE):
  4155. part = Part.objects(logicalCode = logicalCode,ownerId = ownerId,partNo = str(partNo)).first()
  4156. if part is None:
  4157. part = Part(logicalCode = logicalCode,ownerId = ownerId,partNo = str(partNo),partName = partName,partType = partType,partStatus = partStatus)
  4158. try:
  4159. part.save()
  4160. except Exception,e:
  4161. return None
  4162. return part
  4163. @staticmethod
  4164. def update_part_work_status(logicalCode,partNo,workStatus):
  4165. part = Part.objects(logicalCode = logicalCode,partNo = str(partNo)).first()
  4166. if part is None:
  4167. return
  4168. part.status = workStatus
  4169. try:
  4170. part.save()
  4171. except Exception,e:
  4172. return
  4173. @staticmethod
  4174. def update_part_network_status(logicalCode,partNo=None,onlineStatus='online'):
  4175. if partNo:
  4176. part = Part.objects(logicalCode = logicalCode,partNo = str(partNo)).first()
  4177. if part is None:
  4178. return
  4179. part.onlineStatus = onlineStatus
  4180. try:
  4181. part.save()
  4182. except Exception,e:
  4183. return
  4184. else:
  4185. for part in Part.objects(logicalCode = logicalCode):
  4186. part.onlineStatus = onlineStatus
  4187. try:
  4188. part.save()
  4189. except Exception,e:
  4190. continue
  4191. @staticmethod
  4192. def delete_dev(logicalCode):
  4193. Part.objects(logicalCode= logicalCode).delete()
  4194. class Town(Searchable):
  4195. name = StringField(verbose_name = 'name', min_length = 1)
  4196. level = StringField(verbose_name = 'level', min_length = 1) # 级别,1:镇级别,2:村级别
  4197. code = StringField(verbose_name = 'level', min_length = 1) # 编码
  4198. townDict = {}
  4199. villageDict = {}
  4200. @staticmethod
  4201. def load_in_mem_if_not_exist():
  4202. if Town.townDict or Town.villageDict:
  4203. return
  4204. for town in Town.objects.filter(level = '1'):
  4205. Town.townDict[town.name] = town.code
  4206. for village in Town.objects.filter(level = '2'):
  4207. Town.villageDict[village.name] = village.code
  4208. @staticmethod
  4209. def analyze_town_village(address):
  4210. Town.load_in_mem_if_not_exist()
  4211. townCode, villageCode = None, None
  4212. for k, v in Town.townDict.items():
  4213. if k in address:
  4214. townCode = v
  4215. break
  4216. for k, v in Town.villageDict.items():
  4217. if k in address:
  4218. villageCode = v
  4219. break
  4220. return townCode, villageCode
  4221. # 设备的状态记录表,用于汇总设备的状态报表
  4222. class DevStatusRecord(Searchable):
  4223. devNo = StringField(verbose_name = "devNo", min_length = 1)
  4224. status = StringField(verbose_name = "status", min_length = 1) # offline,offlineBusy,online
  4225. startTime = DateTimeField(default = datetime.datetime.now, verbose_name = '状态开始时间')
  4226. endTime = DateTimeField(default = datetime.datetime.now, verbose_name = '状态结束时间')
  4227. duration = IntField(verbose_name = "持续时长", default = 0) # 单位秒
  4228. valueDict = DictField(
  4229. verbose_name = "附带数据,比如信号量") # 'signalUsages':[{'time':'2010-01-01 00:00:00','signal':9,'usage':0-100(设备使用率)}]
  4230. meta = {'collection': 'dev_status_record', 'db_alias': 'logdata',
  4231. 'unique_together': {'devNo', 'startTime', 'endTime'}}
  4232. class PortReport(Searchable):
  4233. logicalCode = StringField(verbose_name = "设备编号", min_length = 1)
  4234. temperature = IntField(verbose_name = "温度信息", min_length = 1)
  4235. time = IntField(verbose_name = "时间信息", min_length = 1)
  4236. portInfo = DictField(verbose_name = "端口信息", default = {})
  4237. meta = {"collection": "port_report", "db_alias": "default"}
  4238. class ManagerInputDev(Searchable):
  4239. logicalCode = StringField(verbose_name = "二维码编号", unique = True)
  4240. devNo = StringField(verbose_name = "设备编号", unique = True)
  4241. managerId = StringField(verbose_name = "厂商ID")
  4242. inputTime = DateTimeField(default = lambda: datetime.datetime.now(), verbose_name = '录入时间')
  4243. meta = {
  4244. "collection": "ManagerInputDev",
  4245. "db_alias": "default"
  4246. }
  4247. # 用于记录微付乐单板的事件1、用于全网分析,也不会被日志冲掉;2、不用memcach,用数据库记录关键数据
  4248. class WeifuleDeviceOrder(Searchable):
  4249. orderNo = StringField(verbose_name = 'orderNo')
  4250. funCode = StringField(verbose_name = 'funCode')
  4251. dateTimeAdded = DateTimeField(verbose_name = 'dateTimeAdded', default = datetime.datetime.now())
  4252. event = DictField(verbose_name = u'消息体内容', default = {})
  4253. meta = {
  4254. "collection": "weifule_device_order",
  4255. "db_alias": "logdata"
  4256. }
  4257. class SerialTimeOut(Searchable):
  4258. logicalCode = StringField(verbose_name = 'logicalCode', default = '')
  4259. devNo = StringField(verbose_name = 'devNo', default = '')
  4260. ownerId = StringField(verbose_name = 'ownerId', default = '')
  4261. dateTimeAdded = DateTimeField(verbose_name = 'time', default = datetime.datetime.now)
  4262. devTypeCode = StringField(verbose_name = 'devTypeCode', default = '')
  4263. packet = StringField()
  4264. meta = {
  4265. "collection": "serial_time_out",
  4266. "db_alias": "logdata"
  4267. }
  4268. @classmethod
  4269. def new_one(cls, device, fun_code, data):
  4270. # type:(DeviceDict,str,str)->None
  4271. try:
  4272. SerialTimeOut(
  4273. logicalCode = device.logicalCode,
  4274. devNo = device.devNo,
  4275. ownerId = device.ownerId,
  4276. devTypeCode = device.get('devType', '').get('code', ''),
  4277. packet = u'{}_{}'.format(fun_code, data)).save()
  4278. except Exception as e:
  4279. logger.exception(e)
  4280. class MqttErrorLog(DynamicDocument):
  4281. logicalCode = StringField(verbose_name='logicalCode', default='')
  4282. devNo = StringField(verbose_name='devNo', default='')
  4283. ownerId = StringField(verbose_name='ownerId', default='')
  4284. dateTimeAdded = DateTimeField(verbose_name='time', default=datetime.datetime.now)
  4285. devTypeCode = StringField(verbose_name='devTypeCode', default='')
  4286. payload = StringField()
  4287. rst = StringField()
  4288. meta = {
  4289. "collection": "mqtt_error_log",
  4290. "db_alias": "logdata"
  4291. }
  4292. @classmethod
  4293. def new_one(cls, device, payload, rst):
  4294. # type:(DeviceDict,dict,str)->None
  4295. try:
  4296. MqttErrorLog(
  4297. logicalCode=device.logicalCode,
  4298. devNo=device.devNo,
  4299. ownerId=device.ownerId,
  4300. devTypeCode=device.devTypeCode,
  4301. payload=json_dumps(payload), rst=str(rst)).save()
  4302. except Exception as e:
  4303. logger.exception(e)
  4304. class DeviceMqttStatics(DynamicDocument):
  4305. devNo = StringField(verbose_name='IMEI', default='')
  4306. total = LongField(verbose_name=u'总共执行次数', default=0)
  4307. uartTimeout = LongField(verbose_name=u'串口错误', default=0)
  4308. connFail = LongField(verbose_name=u'串口错误', default=0)
  4309. otherError = LongField(verbose_name=u'串口错误', default=0)
  4310. meta = {
  4311. 'indexes': [
  4312. {
  4313. 'fields': ['devNo'], 'unique': True
  4314. },
  4315. ],
  4316. "collection": "device_mqtt_statics",
  4317. "db_alias": "logdata"
  4318. }
  4319. @classmethod
  4320. def update(cls, device, total, uart_error, conn_error, other_error):
  4321. cls.objects(devNo=device.devNo).upsert_one(devNo=device.devNo, inc__total=total, inc__uartTimeout=uart_error,
  4322. inc__connFail=conn_error, inc__otherError=other_error)
  4323. class DevicePortReport(Searchable):
  4324. """
  4325. 粤万通的设备端口 10分钟 上报一次的数据 用于结算使用金额
  4326. """
  4327. devNo = StringField(verbose_name = "设备编号")
  4328. port = StringField(verbose_name = "上报端口号")
  4329. orderNo = StringField(verbose_name = "订单号")
  4330. openId = StringField(verbose_name = "端口使用者")
  4331. # 粤万通的充电柜 即时充电完成 但是订单没有结束之前 还是会上报电量 这个地方就放置多计费
  4332. isBilling = BooleanField(verbose_name = "是否参与电量计费", default = True)
  4333. voltage = IntField(verbose_name = "电压")
  4334. power = IntField(verbose_name = "功率")
  4335. elec = IntField(verbose_name = "电量")
  4336. chargeTime = IntField(verbose_name = "充电时间")
  4337. stayTime = IntField(verbose_name = "占位时间", default = 0)
  4338. stageTime = IntField(verbose_name = "该阶段的充电时间")
  4339. dateTimeAdded = DateTimeField(verbose_name = "生成时间", default = datetime.datetime.now)
  4340. meta = {
  4341. "collection": "DevicePortReport",
  4342. "db_alias": "logdata",
  4343. "index": [
  4344. "orderNo"
  4345. ]
  4346. }
  4347. @classmethod
  4348. def last_one(cls, orderNo):
  4349. return cls.objects.filter(orderNo = orderNo).order_by("-dateTimeAdded").first()
  4350. @classmethod
  4351. def last_billing_one(cls, orderNo):
  4352. return cls.objects.filter(orderNo = orderNo, isBilling = True).order_by("-dateTimeAdded").first()
  4353. @classmethod
  4354. def create(cls, devNo, port, orderNo, openId, voltage, power, elec, chargeTime, stayTime = None, **kwargs):
  4355. if not stayTime:
  4356. stayTime = 0
  4357. lastOne = cls.last_one(orderNo)
  4358. leftChargeTime = lastOne.chargeTime if lastOne else 0
  4359. report = cls(
  4360. devNo = devNo,
  4361. port = port,
  4362. orderNo = orderNo,
  4363. openId = openId,
  4364. voltage = voltage,
  4365. power = power,
  4366. elec = elec,
  4367. chargeTime = chargeTime,
  4368. stageTime = chargeTime - leftChargeTime,
  4369. stayTime = stayTime,
  4370. **kwargs
  4371. )
  4372. try:
  4373. report.save()
  4374. except Exception as e:
  4375. logger.error(e)
  4376. return
  4377. return report
  4378. @classmethod
  4379. def billing_records(cls, orderNo):
  4380. return cls.objects.filter(orderNo = orderNo, isBilling = True).all()
  4381. @classmethod
  4382. def stay_records(cls, orderNo):
  4383. return cls.objects.filter(orderNo = orderNo, isBilling = False).all()
  4384. @classmethod
  4385. def calculate(cls, records, intervalMap):
  4386. """
  4387. 计算记录的
  4388. :param records:
  4389. :param intervalMap:
  4390. :return:
  4391. """
  4392. intervalMap = copy.deepcopy(intervalMap)
  4393. for record in records:
  4394. cls.add_power_time(intervalMap, record.power, record.stageTime)
  4395. # 根据interval_map的累加值计算钱
  4396. consume = 0
  4397. for _, item in intervalMap.items():
  4398. unitPrice = item.get("unitPrice") # 单位是小时 元
  4399. _time = item.get("time") # 单位是分钟 需要转换
  4400. consume += unitPrice * _time / 60.0
  4401. return consume
  4402. @classmethod
  4403. def calculate_consume(cls, orderNo, allChargeTime, lastPower, interval_map, devNo, port, openId, voltage, elec):
  4404. """
  4405. 计算消费金钱数据 并将最后一次的主动查询或上报数据保存
  4406. :param orderNo:
  4407. :param allChargeTime:
  4408. :param lastPower:
  4409. :param interval_map:
  4410. :param devNo: 用于记录数据
  4411. :param port: 用于记录数据
  4412. :param openId: 用于记录数据
  4413. :param voltage: 用于记录数据
  4414. :param elec: 用于记录数据
  4415. :return:
  4416. """
  4417. interval_map = copy.deepcopy(interval_map)
  4418. timeList = list()
  4419. totalConsume = VirtualCoin(0)
  4420. # 依次累加功率段的时间
  4421. for record in cls.objects.filter(orderNo = orderNo):
  4422. timeList.append(record.chargeTime)
  4423. cls.add_power_time(interval_map, record.power, record.stageTime)
  4424. # 计算最后一次上报到结束消费这之间的消费金额
  4425. try:
  4426. lastChargeTime = max(timeList)
  4427. except ValueError as e:
  4428. lastChargeTime = 0
  4429. chargeTime = allChargeTime - lastChargeTime
  4430. cls.add_power_time(interval_map, lastPower, chargeTime)
  4431. # 把最后一次的数据也记录上去
  4432. lastRecord = cls(
  4433. devNo = devNo,
  4434. port = port,
  4435. orderNo = orderNo,
  4436. openId = openId,
  4437. voltage = voltage,
  4438. power = lastPower,
  4439. elec = elec,
  4440. chargeTime = allChargeTime,
  4441. stageTime = chargeTime
  4442. )
  4443. try:
  4444. lastRecord.save()
  4445. except Exception as e:
  4446. logger.error(e)
  4447. # 根据interval_map的累加值计算钱
  4448. for _, item in interval_map.items():
  4449. unitPrice = item.get("unitPrice")
  4450. _time = item.get("time")
  4451. totalConsume += unitPrice * _time / 60.0
  4452. return totalConsume
  4453. @staticmethod
  4454. def add_power_time(interval_map, power, chargeTime):
  4455. """
  4456. 获取功率区间的单价
  4457. :param interval_map: 功率区间
  4458. :param power: 该阶段功率
  4459. :param chargeTime: 该阶段充电时间
  4460. :return: Ratio
  4461. """
  4462. for interval, item in interval_map.items():
  4463. if int(power) in interval:
  4464. item.update({
  4465. "time": item["time"] + chargeTime
  4466. })
  4467. class DevicePortLastReport(Searchable):
  4468. """
  4469. 关键信息 端口号 + 设备号 唯一
  4470. """
  4471. orderNo = StringField(verbose_name = "订单编号")
  4472. devNo = StringField(verbose_name = u"设备编号")
  4473. port = StringField(verbose_name = u"端口号")
  4474. power = IntField(verbose_name = "功率", default = 0)
  4475. elec = FloatField(verbose_name = "已充入电量", default = 0.0)
  4476. chargeTime = IntField(verbose_name = u"充电时间", default = 0)
  4477. stayTime = IntField(verbose_name = u"占位时间", default = 0)
  4478. chargeConsume = AccuracyMoneyField(verbose_name = u"目前为止的充电费用", default = AccuracyRMB(0))
  4479. stayConsume = AccuracyMoneyField(verbose_name = u"到目前为止的占位费用", default = AccuracyRMB(0))
  4480. totalConsume = AccuracyMoneyField(verbose_name = u"目前为止累计的总消费", default = AccuracyRMB(0))
  4481. datetimeUpdated = DateTimeField(verbose_name = u"更新时间", default = datetime.datetime.now)
  4482. dateTimeAdded = DateTimeField(verbose_name = "生成时间", default = datetime.datetime.now)
  4483. meta = {'collection': 'device_port_last_report', 'db_alias': 'logdata'}
  4484. @classmethod
  4485. def null(cls):
  4486. return cls()
  4487. @classmethod
  4488. def save_last(cls, devNo, port, **kwargs):
  4489. """
  4490. 将设备上报的信息 存储方式为复写
  4491. :param devNo:
  4492. :param port:
  4493. :param kwargs:
  4494. :return:
  4495. """
  4496. try:
  4497. obj = cls.objects.get(devNo = devNo, port = port)
  4498. except DoesNotExist:
  4499. obj = cls(devNo = devNo, port = port)
  4500. obj.power = kwargs.get("power")
  4501. obj.elec = kwargs.get("elec")
  4502. obj.chargeTime = kwargs.get("chargeTime")
  4503. obj.stayTime = kwargs.get("stayTime")
  4504. orderNo = kwargs.get("orderNo")
  4505. # 订单号不一致 说明是覆盖之前的记录 更新一下记录的时间
  4506. nowTime = datetime.datetime.now()
  4507. if obj.orderNo != orderNo:
  4508. obj.chargeConsume = AccuracyRMB(0)
  4509. obj.stayConsume = AccuracyRMB(0)
  4510. obj.totalConsume = AccuracyRMB(0)
  4511. obj.dateTimeAdded = nowTime
  4512. obj.orderNo = orderNo
  4513. obj.datetimeUpdated = nowTime
  4514. return obj.save()
  4515. @classmethod
  4516. def get_last(cls, devNo, port, orderNo):
  4517. """
  4518. 获取该 订单的上次上报的信息
  4519. :param devNo:
  4520. :param port:
  4521. :param orderNo:
  4522. :return:
  4523. """
  4524. try:
  4525. obj = cls.objects.get(devNo = devNo, port = port)
  4526. except DoesNotExist:
  4527. return cls.null()
  4528. if obj.orderNo != orderNo:
  4529. return cls.null()
  4530. return obj
  4531. @classmethod
  4532. def get_last_by_order(cls, orderNo):
  4533. """
  4534. 获取消费的金额
  4535. :param orderNo:
  4536. :return:
  4537. """
  4538. try:
  4539. obj = cls.objects.get(orderNo = orderNo)
  4540. except DoesNotExist:
  4541. obj = cls.null()
  4542. return obj
  4543. def update_consume(self, chargeConsume, stayConsume):
  4544. """更新消费金额 精确到0.1厘"""
  4545. chargeConsume = AccuracyRMB(chargeConsume) + self.chargeConsume
  4546. stayConsume = AccuracyRMB(stayConsume)
  4547. totalConsume = chargeConsume + stayConsume
  4548. self.update(chargeConsume = chargeConsume, stayConsume = stayConsume, totalConsume = totalConsume)
  4549. class OfflineCoinStatistics(Searchable):
  4550. logicalCode = StringField(verbose_name = u'设备编号')
  4551. devNo = StringField(verbose_name = u"IMEI")
  4552. count = IntField(verbose_name = u'投币次数')
  4553. groupId = StringField(verbose_name = u'地址ID')
  4554. dateTimeAdded = DateTimeField(verbose_name = u"添加时间", default = datetime.datetime.now)
  4555. meta = {
  4556. "collection": "offline_coin_statistics",
  4557. "db_alias": "logdata",
  4558. "index": [
  4559. "logicalCode"
  4560. ]
  4561. }
  4562. @classmethod
  4563. def recordCoinEvent(cls, logicalCode, devNo, count, groupId):
  4564. report = cls(
  4565. logicalCode = logicalCode,
  4566. devNo = devNo,
  4567. count = count,
  4568. groupId = groupId
  4569. )
  4570. try:
  4571. report.save()
  4572. except Exception as e:
  4573. logger.error(e)
  4574. return
  4575. class OfflineReportDealers(DynamicDocument):
  4576. """
  4577. 投币的经销商统计 只要有投币的经销商 以ID+DATE为键存入
  4578. """
  4579. ownerId = StringField(verbose_name = "经销商id", required = True)
  4580. reportDay = StringField(verbose_name = "report日期", required = True)
  4581. datetimeAdded = DateTimeField(verbose_name = "记录时间", default = datetime.datetime.now)
  4582. meta = {
  4583. "collection": "offline_report_dealers",
  4584. "db_alias": "logdata",
  4585. 'indexes': [
  4586. {
  4587. 'fields': ['ownerId', 'reportDay'], 'unique': True
  4588. },
  4589. {
  4590. 'fields': ['datetimeAdded'],
  4591. # 保留 7 天的数据 方便经销商的追溯
  4592. 'expireAfterSeconds': 24 * 3600 * 7
  4593. }
  4594. ],
  4595. }
  4596. @classmethod
  4597. def record_dealer(cls, dealerId, dateStr = None):
  4598. """
  4599. 有投币的经销商统计一下
  4600. :param dealerId:
  4601. :param dateStr: 时间
  4602. :return:
  4603. """
  4604. if dateStr is None:
  4605. dateStr = datetime.datetime.today().strftime("%Y-%m-%d")
  4606. if not dealerId:
  4607. logger.error('dealer id is null.')
  4608. return
  4609. try:
  4610. cls(ownerId = dealerId, reportDay = dateStr).save()
  4611. except NotUniqueError:
  4612. return
  4613. except Exception as e:
  4614. logger.exception(e)
  4615. @classmethod
  4616. def get_rpt_dealIds(cls, dateStr = None):
  4617. if dateStr is None:
  4618. dateStr = datetime.datetime.today().strftime("%Y-%m-%d")
  4619. return [_rpt.ownerId for _rpt in cls.objects.filter(reportDay = dateStr).all()]
  4620. class Battery(Searchable):
  4621. batterySn = StringField(verbose_name = "电池的SN编号", regex = r"\d{15}")
  4622. dealerId = StringField(verbose_name = "经销商的ID")
  4623. devNo = StringField(verbose_name = "电池存放的设备编号", default = "")
  4624. portNo = StringField(verbose_name = "电池存放的设备端口号", default = "")
  4625. openId = StringField(verbose_name = "取走电池的用户", default = "")
  4626. normal = BooleanField(verbose_name = "电池是否正常", default = True)
  4627. dateTimeAdded = DateTimeField(verbose_name = "电池加入系统的时间", default = datetime.datetime.now)
  4628. dateTimeUpdated = DateTimeField(verbose_name = "电池信息更新的时间", default = datetime.datetime.now)
  4629. meta = {
  4630. "collection": "Battery"
  4631. }
  4632. search_fields = ("devNo", "batterySn")
  4633. def save(self, **kwargs):
  4634. self.dateTimeUpdated = datetime.datetime.now()
  4635. return super(Battery, self).save(**kwargs)
  4636. @staticmethod
  4637. def is_battery_sn_format(batterySn):
  4638. """
  4639. 是否是正确的电池编号格式
  4640. :param batterySn:
  4641. :return:
  4642. """
  4643. try:
  4644. result = batterySn.isdigit() and len(batterySn) == 15
  4645. except (AttributeError, TypeError):
  4646. result = False
  4647. return result
  4648. @classmethod
  4649. def add_from_device(cls, batterySn, devNo, port, dealerId):
  4650. """
  4651. 从设备侧读取的电池编号信息入库
  4652. :param batterySn:
  4653. :param devNo:
  4654. :param port:
  4655. :param dealerId:
  4656. :return:
  4657. """
  4658. battery = cls(batterySn = batterySn, devNo = devNo, portNo = port, dealerId = dealerId)
  4659. try:
  4660. record = battery.save()
  4661. except NotUniqueError:
  4662. return None
  4663. return record
  4664. @classmethod
  4665. def add_from_enter(cls, batterySn, dealerId):
  4666. """
  4667. 手动录入电池信息
  4668. :param batterySn:
  4669. :param dealerId:
  4670. :return:
  4671. """
  4672. battery = cls(batterySn = batterySn, dealerId = dealerId)
  4673. try:
  4674. record = battery.save()
  4675. except NotUniqueError:
  4676. return None
  4677. return record
  4678. @classmethod
  4679. def delete_one(cls, dealerId, batterySn):
  4680. logger.info("delete battery dealer is <{}>, batterySn is <{}>".format(dealerId, batterySn))
  4681. battery = cls.objects.filter(dealerId = dealerId, batterySn = batterySn)
  4682. if not battery:
  4683. return False
  4684. try:
  4685. battery.delete()
  4686. except Exception as e:
  4687. logger.exception("dealerId is <{}>, batterySn is <{}>, error is {}".format(dealerId, batterySn, e))
  4688. return False
  4689. return True
  4690. @classmethod
  4691. def get_one(cls, dealerId, batterySn):
  4692. return cls.objects.filter(dealerId = dealerId, batterySn = batterySn).first()
  4693. def is_owner(self, dealerId):
  4694. return self.dealerId == dealerId
  4695. def to_dict(self):
  4696. # TODO zjl 持有信息需要修改
  4697. if self.openId:
  4698. from apps.web.user.models import MyUser
  4699. user = MyUser.objects.filter(openId = self.openId).first()
  4700. lastOwner = "{}".format(user.nickname)
  4701. elif self.devNo:
  4702. logicalCode = Device.get_dev(self.devNo).logicalCode
  4703. lastOwner = "{}-{}".format(logicalCode, self.portNo)
  4704. else:
  4705. # 刚刚添加的设备 或者是被清除掉openId的电池
  4706. lastOwner = u""
  4707. data = {
  4708. "batterySn": self.batterySn,
  4709. "dealerId": self.dealerId,
  4710. "dateTimeUpdated": self.dateTimeUpdated.strftime("%Y-%m-%d %H:%M:%S"),
  4711. "lastOwner": lastOwner,
  4712. "disable": self.disable
  4713. }
  4714. return data
  4715. def update_dev_info(self, devNo, port):
  4716. self.devNo = devNo
  4717. self.portNo = port
  4718. self.openId = ""
  4719. try:
  4720. self.save()
  4721. except Exception as e:
  4722. logger.exception(
  4723. "batterySn is <{}>, devNo is <{}>, port is <{}>, error is <{}>".format(self.batterySn, devNo, port, e))
  4724. return False
  4725. return True
  4726. def update_user_info(self, openId):
  4727. """
  4728. 同一个用户同义时间只能拥有一块电池 在更新用户的时候 需要将用户之前拥有过的电池都清除掉
  4729. :param openId:
  4730. :return:
  4731. """
  4732. self.__class__.objects.filter(openId = openId).update(openId = "")
  4733. self.openId = openId
  4734. self.devNo = ""
  4735. self.portNo = ""
  4736. try:
  4737. self.save()
  4738. except Exception as e:
  4739. logger.exception("batterySn is <{}>, openId is <{}>, error is <{}>".format(self.batterySn, openId, e))
  4740. return False
  4741. return True
  4742. @classmethod
  4743. def get_user_last_battery_sn(cls, openId, dealerId):
  4744. battery = cls.objects.filter(openId = openId, dealerId = dealerId).first()
  4745. return battery.batterySn if battery else None
  4746. @property
  4747. def disable(self):
  4748. return not self.normal
  4749. @disable.setter
  4750. def disable(self, value):
  4751. if not isinstance(value, bool):
  4752. raise TypeError(u"type of value must be bool, value is <{}>, battery is <{}>".format(value, self))
  4753. if not self.dealerId:
  4754. raise ValueError(u"no dealer battery can not set disable, battery is <{}>".format(self))
  4755. self.update(normal = not value)
  4756. # TODO capped collection 固有集合 默认 不可删除,不可修改(但非StringField可以修改),只能迭代,目前保留三万条
  4757. class DeviceUploadInfo(Searchable):
  4758. device_imei = StringField(verbose_name = "设备IMEI号")
  4759. order_id = StringField(verbose_name = "事件ID", default = None)
  4760. order_type = StringField(verbose_name = "事件类型", default = None)
  4761. money = FloatField(verbose_name = "使用的金额(分)", default = None)
  4762. left_money = FloatField(verbose_name = "当前剩余的金额(分)", default = None)
  4763. amount = FloatField(verbose_name = "本单的总金额", default = None)
  4764. create_time = FloatField(verbose_name = "创建订单时间", default = None)
  4765. exec_time = FloatField(verbose_name = "开始充电时间", default = None)
  4766. time = FloatField(verbose_name = "已使用时间", default = None)
  4767. elec = FloatField(verbose_name = "已使用电量(毫度)", default = None)
  4768. status = StringField(verbose_name = "当前设备状态码", default = None)
  4769. last_clock = FloatField(verbose_name = "最近的时钟信息", default = None)
  4770. last_ecnt = FloatField(verbose_name = "最近的计量值", default = None)
  4771. last_update_time = DateTimeField(verbose_name = "最近一次更新数据时间", default = datetime.datetime.now())
  4772. meta = {
  4773. "collection": "device_upload_info",
  4774. "db_alias": "logdata"
  4775. }
  4776. class DeviceCmdStatics(DynamicDocument):
  4777. devNo = StringField(verbose_name = u"设备IMEI号")
  4778. cmd = StringField(verbose_name = u"事件ID")
  4779. count = IntField(verbose_name = u'计数', default = 0)
  4780. meta = {
  4781. "collection": "device_cmd_statics",
  4782. "db_alias": "logdata"
  4783. }
  4784. @classmethod
  4785. def get_collection(cls):
  4786. return cls._get_collection()
  4787. @classmethod
  4788. def record(cls, devNo, cmd):
  4789. cls.get_collection().update_one(
  4790. filter = {'devNo': devNo, 'cmd': cmd},
  4791. update = {'$inc': {'count': 1}},
  4792. upsert = True)
  4793. class DeviceRentOrderDetail(EmbeddedDocument):
  4794. status = BooleanField(verbose_name=u"结算是否成功", require=True)
  4795. reason = StringField(verbose_name=u"结算失败的原因", default="")
  4796. dateTime = DateTimeField(verbose_name=u"结算时间", require=True)
  4797. sourceKey = StringField(verbose_name=u"扣款的source")
  4798. def to_dict(self):
  4799. return {
  4800. "dateTime": self.dateTime.strftime("%Y-%m-%d %H:%M:%S"),
  4801. "status": self.status,
  4802. "reason": self.reason
  4803. }
  4804. class DeviceRentOrder(Searchable):
  4805. """
  4806. 设备的日出租的订单
  4807. """
  4808. orderNo = StringField(verbose_name=u"订单编号", required=True)
  4809. devNo = StringField(verbose_name=u"账单设备", require=True)
  4810. # 以账单产生时候的经销商ID为准
  4811. dealerId = StringField(verbose_name=u"账单所有者", require=True)
  4812. billDate = DateField(verbose_name=u"账单日期", required=True)
  4813. billAmount = MonetaryField(verbose_name=u"账单金额", require=True)
  4814. status = BooleanField(verbose_name=u"是否已经结算", default=False)
  4815. dateTimeAdded = DateTimeField(verbose_name=u"订单添加时间", default=datetime.datetime.now)
  4816. detail = EmbeddedDocumentListField(document_type=DeviceRentOrderDetail, verbose_name=u"详情详情")
  4817. meta = {
  4818. "collection": "DeviceRentOrder",
  4819. "db_alias": "logdata"
  4820. }
  4821. @staticmethod
  4822. def make_no(date, devNo):
  4823. return "{}{}".format(devNo, date.strftime("%Y%m%d%H%M%S"))
  4824. @classmethod
  4825. def create_by_device(cls, device, date=None): # type:(Device, datetime.date) -> DeviceRentOrder
  4826. """
  4827. 创建设备的日订单 默认是当日的订单
  4828. :param device:
  4829. :param date:
  4830. :return:
  4831. """
  4832. date = date or datetime.date.today()
  4833. try:
  4834. order = cls.objects.get(devNo=device.devNo, billDate=date)
  4835. except DoesNotExist:
  4836. order = cls(
  4837. orderNo=cls.make_no(date, device.devNo),
  4838. devNo=device.devNo,
  4839. dealerId=device.ownerId,
  4840. billDate=date,
  4841. billAmount=device.rentMoney
  4842. ).save()
  4843. return order
  4844. @classmethod
  4845. def get_by_device(cls, device): # type:(Device) -> QuerySet
  4846. """
  4847. 获取所有经销商的日租订单
  4848. :param device:
  4849. :return:
  4850. """
  4851. return cls.objects.filter(
  4852. dealerId=device.ownerId,
  4853. devNo=device.devNo,
  4854. ).order_by("-dateTimeAdded")
  4855. @classmethod
  4856. def get_not_paid_by_dealer(cls, dealer): # type:(Dealer) -> QuerySet
  4857. """
  4858. 获取经销商所有没有结算的订单
  4859. :param dealer:
  4860. :return:
  4861. """
  4862. return cls.objects.filter(
  4863. dealerId=str(dealer.id),
  4864. status=False,
  4865. ).order_by("dateTimeAdded")
  4866. @classmethod
  4867. def get_not_paid_by_device(cls, device): # type:(Device) -> QuerySet
  4868. """
  4869. 获取设备没有完成的订单
  4870. :param device:
  4871. :return:
  4872. """
  4873. return cls.objects.filter(
  4874. devNo=device.devNo,
  4875. status=False,
  4876. ).order_by("dateTimeAdded")
  4877. @property
  4878. def dealer(self): # type:() -> Dealer
  4879. return Dealer.objects.get(id=self.dealerId)
  4880. def to_dict(self):
  4881. return {
  4882. "orderNo": self.orderNo,
  4883. "billDate": self.billDate.strftime("%Y-%m-%d"),
  4884. "billAmount": self.billAmount,
  4885. "status": self.status,
  4886. "detail": [_.to_dict() for _ in self.detail]
  4887. }
  4888. def update_for_success(self, dateTime, source):
  4889. """
  4890. 结算成功的更新
  4891. 添加支付信息 添加扣款信息 更换状态
  4892. :param dateTime:
  4893. :param source:
  4894. :return:
  4895. """
  4896. assert not self.status, u"状态更新失败"
  4897. detail = DeviceRentOrderDetail(
  4898. status=True,
  4899. sourceKey=source,
  4900. dateTime=dateTime
  4901. )
  4902. detailList = self.detail or list()
  4903. detailList.append(detail)
  4904. # 只能更新状态为False的
  4905. self.__class__.objects.filter(
  4906. id=self.id,
  4907. status=False
  4908. ).update(
  4909. status=True,
  4910. detail=detailList
  4911. )
  4912. def update_for_fail(self, dateTime, reason=u""):
  4913. """
  4914. 结算失败的状态更新
  4915. 添加支付信息 添加失败原因
  4916. :param dateTime:
  4917. :param reason:
  4918. :return:
  4919. """
  4920. # 订单状态只能从单项 即失败 ---> 成功
  4921. assert not self.status, u"状态更新失败"
  4922. detail = DeviceRentOrderDetail(
  4923. status=False,
  4924. reason=reason,
  4925. dateTime=dateTime
  4926. )
  4927. detailList = self.detail or list()
  4928. detailList.append(detail)
  4929. # 只能更新状态为False的
  4930. self.__class__.objects.filter(
  4931. id=self.id,
  4932. status=False
  4933. ).update(
  4934. status=False,
  4935. detail=detailList
  4936. )
  4937. class EventTimes(Searchable):
  4938. """
  4939. 统计 MQTT 100事件上报的频率
  4940. """
  4941. devNo = StringField(verbose_name=u"设备编号")
  4942. driverCode = StringField(verbose_name=u"驱动编码")
  4943. driverVersion = StringField(verbose_name="驱动版本")
  4944. devTypeCode = StringField(verbose_name=u"设备类型")
  4945. server = StringField(verbose_name=u"服务器")
  4946. times = IntField(verbose_name=u"事件次数")
  4947. date = StringField(verbose_name="统计时间")
  4948. meta = {
  4949. "collection": "EventTimes",
  4950. "db_alias": "logdata"
  4951. }
  4952. class Picture(EmbeddedDocument):
  4953. IsCover = IntField(verbose_name = u'是否为封面 ',default=0) # 是否为封面,0:否,1:是
  4954. PicID = IntField(verbose_name = u'PicID')
  4955. Url = StringField(verbose_name = u'图片网址 ')
  4956. Title = StringField(verbose_name = u'图片标题', default = '')
  4957. TitleForShow = IntField(verbose_name = u'前台界面用于展现的枚举值,不作为业务用')
  4958. SrcType = StringField(verbose_name = u'图片来源',default = '')
  4959. class PriceCharging(EmbeddedDocument):
  4960. FeeTime = StringField(verbose_name = u'收费时间段',default = '00:00-24:00')
  4961. ElectricityFee = FloatField(verbose_name = u'站点充电费',default = 0.0000)
  4962. ServiceFee = FloatField(verbose_name = u'站点服务费',default = 0.0000)
  4963. class DiscountPriceCharging(EmbeddedDocument): #站点充电优惠价格 和高德的字段定义统一,这里再重新定义一个
  4964. DiscountTime = StringField(verbose_name = u'时间段描述',default = '00:00-24:00')
  4965. DiscountElectricityFee = FloatField(verbose_name = u'站点充电费优惠价',default = 0.0000)
  4966. DiscountServiceFee = FloatField(verbose_name = u'站点服务费优惠价',default = 0.0000)
  4967. class ChargeTag(EmbeddedDocument):
  4968. tagId = IntField(verbose_name = u'标签Id')
  4969. tagType = IntField(verbose_name = u'标签类型(0:普通标签,1:停车标签)',default = 0)
  4970. tagDesc = StringField(verbose_name = u'标签描述',default = '')
  4971. tagOrder = IntField(verbose_name = u'排序',default = 0)
  4972. tagName = StringField(verbose_name = u'标签名称')
  4973. color = StringField(verbose_name = u'标签颜色')
  4974. class SwapGroup(Searchable):
  4975. """
  4976. 互联互通数据
  4977. """
  4978. groupId = StringField(verbose_name="groupId", unique = True)
  4979. StationID = StringField(verbose_name = u"充电站ID", unique = True)
  4980. ownerId = StringField(verbose_name="ownerId")
  4981. swapFlag = BooleanField(verbose_name = u'是否打开互联互通',default = False)
  4982. location = PointField(verbose_name = '经纬度',default = None )
  4983. gcjLng = FloatField(verbose_name = u'gcj版本lng坐标',default = None)
  4984. gcjLat = FloatField(verbose_name = u'gcj版本lat坐标',default = None)
  4985. BusineHours = StringField(verbose_name=u"营业时间",default='00:00-24:00')#eg 10:00-15:00
  4986. SiteGuide = StringField(verbose_name = u'站点引导',default='')
  4987. Construction = IntField(verbose_name = u'建设场所',default = 1)
  4988. SupportOrder = IntField(verbose_name = u'是否支持预约',default = 0)
  4989. Pictures = EmbeddedDocumentListField(document_type = Picture, verbose_name = u'站点照片 ',default=[])
  4990. MatchCars = StringField(verbose_name = u'使用车型描述',default = '')
  4991. ParkInfo = StringField(verbose_name = u'车位楼层及数量描述',default = '')
  4992. StationStatus = IntField(verbose_name = u'站点状态 ',default = 50)# 0:未知 1:建设中 5:关闭下线 6:维护中 50:正常使用
  4993. ParkNums = IntField(verbose_name = u'车位数量 ',default = 0)#
  4994. originalAlternateFeeRemark = StringField(verbose_name = u'慢充原价描述',default = '')
  4995. alternateFeeRemark = StringField(verbose_name = u'慢充价格描述',default = '')
  4996. originalDirectFeeRemark = StringField(verbose_name = u'快充原价描述',default = '')
  4997. directFeeRemark = StringField(verbose_name = u'快充价格描述',default = '')
  4998. PriceChargingInfo = EmbeddedDocumentListField(document_type = PriceCharging, verbose_name = u'站点收费价格明细 ')
  4999. DiscountPriceChargingInfo = EmbeddedDocumentListField(document_type = DiscountPriceCharging, verbose_name = u'站点收费价格明细_优惠价')
  5000. ParkFee = StringField(verbose_name = u'停车费率描述',default=u'')
  5001. RightTag = StringField(verbose_name = u'车主权益',default=u'')
  5002. ChargeTagList = EmbeddedDocumentListField(document_type = ChargeTag, verbose_name = u'站标签列表')
  5003. StationTel = StringField(verbose_name = u'站点电话',default = '')
  5004. ServiceTel = StringField(verbose_name = u'服务电话',default = '')
  5005. StationType = IntField(verbose_name = u'站点类型 ',default = 1)#
  5006. Remark = StringField(verbose_name = u'备注',default = '')
  5007. joinedTime = DateTimeField(default = None, verbose_name = u'加入互联互通的时间')
  5008. deviceChangedTime = DateTimeField(default = datetime.datetime.now, verbose_name = u'站下面设备变化的最新时间')
  5009. # 实时统计的部分信息,这里放数据库里,根据设备的事件进行状态更新
  5010. chargeType = IntField(verbose_name = u'充电类型 ',default = 0) # 0:快慢充都有,1:快充、2:慢充
  5011. dcPortsSum = DictField(verbose_name = u'直流快充端口数统计 ',default = {'allPorts':0,'usedPorts':0,'usePorts':0})
  5012. acPortsSum = DictField(verbose_name = u'交流快充端口数统计 ',default = {'allPorts':0,'usedPorts':0,'usePorts':0})
  5013. exceptSum = DictField(verbose_name = u'异常设备统计 ',default = {'offline':0,'fault':0})
  5014. deviceNum = IntField(verbose_name = u'设备数量',default = 0)
  5015. @staticmethod
  5016. def make_stationID(groupId):
  5017. h = hashlib.md5()
  5018. h.update(groupId.encode('utf-8'))
  5019. return h.hexdigest()[8:24]
  5020. @staticmethod
  5021. def find_one_device_cur_fee(groupId):
  5022. devs = Device.get_devices_by_group([groupId])
  5023. devNo = None
  5024. device = None
  5025. for dev in devs.values():
  5026. device = dev
  5027. if dev.majorDeviceType and (u'交流' in dev.majorDeviceType or u'直流' in dev.majorDeviceType):
  5028. devNo = dev['devNo']
  5029. break
  5030. if devNo is None :
  5031. return None
  5032. # 各个业务记录的电费和服务费的形式可能不一样,所以放到设备类型中
  5033. box = ActionDeviceBuilder.create_action_device(device)
  5034. return box.get_cur_fee()
  5035. def get_tag_desc_list(self):
  5036. self.ChargeTagList.sort(key=lambda x:x.tagOrder)
  5037. return [ tag.tagDesc for tag in self.ChargeTagList if tag]
  5038. @staticmethod
  5039. def get_tag_desc_list_for_dict(swapInfo):
  5040. swapInfo['ChargeTagList'].sort(key=lambda x:x['tagOrder'])
  5041. result = []
  5042. for tag in swapInfo['ChargeTagList']:
  5043. if not tag:
  5044. continue
  5045. if tag['tagDesc'] and tag['tagName']:
  5046. result.append('%s:%s' %(tag['tagName'],tag['tagDesc']))
  5047. elif tag['tagName']:
  5048. result.append(tag['tagName'])
  5049. return result
  5050. @staticmethod
  5051. def recount_devnum(groupId):
  5052. result = 0
  5053. devs = Device.get_devices_by_group([groupId])
  5054. for dev in devs.values():
  5055. if dev.majorDeviceType and (u'交流' in dev.majorDeviceType or u'直流' in dev.majorDeviceType):
  5056. result += 1
  5057. continue
  5058. swap = SwapGroup.objects(groupId = groupId).first()
  5059. if swap:
  5060. swap.deviceChangedTime = datetime.datetime.now()
  5061. swap.deviceNum = result
  5062. try:
  5063. swap.save()
  5064. except Exception,e:
  5065. return
  5066. @staticmethod
  5067. def update_swap_time_and_num(groupId,devNum=0):
  5068. swap = SwapGroup.objects(groupId = groupId).first()
  5069. if swap:
  5070. swap.deviceChangedTime = datetime.datetime.now()
  5071. swap.deviceNum += devNum
  5072. if swap.deviceNum <0:
  5073. swap.deviceNum = 0
  5074. try:
  5075. swap.save()
  5076. except Exception,e:
  5077. return
  5078. @staticmethod
  5079. def delete_group(groupId):
  5080. return SwapGroup.objects(groupId = groupId).delete()
  5081. @property
  5082. def lng(self):
  5083. return self.location['coordinates'][0]
  5084. @property
  5085. def lat(self):
  5086. return self.location['coordinates'][1]
  5087. @property
  5088. def pictures(self):
  5089. return [{'IsCover':pic.IsCover,'Url':pic.Url,'Title':pic.Title,'SrcType':pic.SrcType} for pic in self.Pictures]
  5090. @staticmethod
  5091. def bd09_to_gcj02(lng, lat):
  5092. """
  5093. 百度坐标系到google坐标系的经纬度转换
  5094. :param lng: 百度经度
  5095. :param lat: 百度维度
  5096. :return:
  5097. """
  5098. if lng == 0.0 or lat == 0.0:
  5099. return lng, lat
  5100. x_pi = 3.14159265358979324 * 3000.0 / 180.0
  5101. x = lng - 0.0065
  5102. y = lat - 0.006
  5103. z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * x_pi)
  5104. theta = math.atan2(y, x) - 0.000003 * math.cos(x * x_pi)
  5105. gg_lng = z * math.cos(theta)
  5106. gg_lat = z * math.sin(theta)
  5107. return [gg_lng, gg_lat]
  5108. @staticmethod
  5109. def get_cur_fee(priceInfoList):
  5110. nowTime = datetime.datetime.now().strftime('%H:%M')
  5111. for priceInfo in priceInfoList:
  5112. tempList = priceInfo['FeeTime'].split('-')
  5113. startTime = tempList[0]
  5114. endTime = tempList[1]
  5115. if nowTime >= startTime and nowTime <= endTime:
  5116. return {'curElecFee':priceInfo['ElectricityFee'],'curServiceFee':priceInfo['ServiceFee']}
  5117. return {'curElecFee':'-','curServiceFee':'-'}
  5118. @staticmethod
  5119. def get_stats(groupId):
  5120. lcs = Device.get_logicalCode_by_groupId(groupId)
  5121. parts = Part.objects(logicalCode__in = lcs)
  5122. dcAllPorts,dcUsedPorts,acAllPorts,acUsedPorts=0,0,0,0
  5123. for part in parts:
  5124. if part.status not in [Part.Status.IDLE,Part.Status.WORKING]:
  5125. continue
  5126. if part.partType == 'dc':
  5127. dcAllPorts += 1
  5128. if part.status == Part.Status.WORKING:
  5129. dcUsedPorts +=1
  5130. continue
  5131. if part.partType == 'ac':
  5132. acAllPorts += 1
  5133. if part.status == Part.Status.WORKING:
  5134. acUsedPorts +=1
  5135. offlineNum,faultNum = 0,0
  5136. for lc in lcs:
  5137. dev = Device.get_dev_by_l(lc)
  5138. if dev is None:
  5139. continue
  5140. if not dev.devType or not dev.devType['majorDeviceType']:
  5141. continue
  5142. if not (u'直流' in dev.devType['majorDeviceType'] or u'交流' in dev.devType['majorDeviceType']):
  5143. continue
  5144. if not dev.online:
  5145. offlineNum += 0
  5146. if dev.status == Const.DEV_WORK_STATUS_FAULT:
  5147. faultNum += 1
  5148. return {
  5149. 'dcAllPorts':dcAllPorts,'dcUsedPorts':dcUsedPorts,'dcUsePorts':dcAllPorts-dcUsedPorts,
  5150. 'acAllPorts':acAllPorts,'acUsedPorts':acUsedPorts,'acUsePorts':acAllPorts-acUsedPorts,
  5151. 'offline':offlineNum,'fault':faultNum
  5152. }