policy_common.py 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import json
  5. import logging
  6. import re
  7. from mongoengine import Q
  8. from typing import TYPE_CHECKING
  9. from apilib.monetary import RMB
  10. from apilib.utils_datetime import to_datetime
  11. from apps.web.common.proxy import ClientConsumeModelProxy
  12. from apps.web.constant import Const, DeviceCmdCode, MQTT_TIMEOUT, CONSUMETYPE
  13. from apps.web.core.adapter.base import SmartBox
  14. from apps.web.core.exceptions import ServiceException, InvalidParameter
  15. from apps.web.core.networking import MessageSender
  16. from apps.web.dealer.models import Dealer
  17. from apps.web.device.models import Device
  18. from apps.web.user.constant2 import StartDeviceType
  19. from apps.web.user.models import ConsumeRecord, MyUser
  20. logger = logging.getLogger(__name__)
  21. if TYPE_CHECKING:
  22. pass
  23. class PolicyPackageInit(SmartBox):
  24. INIT_POLICY = {
  25. 'forIdcard': {
  26. 'policyType': 'time',
  27. 'billingMethod': 'prepaid',
  28. 'autoRefund': True,
  29. 'money': 1,
  30. "minAfterStartCoins": 0,
  31. "rule": {
  32. 'prices': [
  33. {
  34. "price": 0.25,
  35. "power": 150
  36. },
  37. {
  38. "price": 0.36,
  39. "power": 250
  40. },
  41. {
  42. "price": 0.54,
  43. "power": 350
  44. },
  45. {
  46. "price": 0.72,
  47. "power": 500
  48. },
  49. {
  50. "price": 0.90,
  51. "power": 700
  52. },
  53. {
  54. "price": 1.08,
  55. "power": 990
  56. },
  57. ],
  58. 'price': 1
  59. }
  60. },
  61. 'forApps': {
  62. "policyType": "time",
  63. "rule": {
  64. "prices": [
  65. {
  66. "price": 0.25,
  67. "power": 150
  68. },
  69. {
  70. "price": 0.36,
  71. "power": 250
  72. },
  73. {
  74. "price": 0.54,
  75. "power": 350
  76. },
  77. {
  78. "price": 0.72,
  79. "power": 500
  80. },
  81. {
  82. "price": 0.90,
  83. "power": 700
  84. },
  85. {
  86. "price": 1.08,
  87. "power": 990
  88. },
  89. ],
  90. "price": 1
  91. }
  92. }
  93. }
  94. def _generate_id(self, ids):
  95. i = 1
  96. while True:
  97. if str(i) in ids:
  98. i += 1
  99. else:
  100. return str(i)
  101. def _sort_by_sn(self):
  102. # 调整sn顺序
  103. for item in self.ruleList:
  104. item["sn"] = self.ruleList.index(item)
  105. def _formart_ruleList(self, isTemp=False):
  106. if not isTemp and not filter(lambda _: _.get('switch') == True, self.ruleList):
  107. raise ServiceException(
  108. {'result': 0, 'description': '没有可供用户选择的套餐, 请新增或启用 至少一个用户套餐',
  109. 'payload': {}})
  110. ids = [str(rule['id']) for rule in self.ruleList if 'id' in rule]
  111. for i, rule in enumerate(self.ruleList):
  112. ruleId = str(rule.get('id', ''))
  113. if not ruleId:
  114. ruleId = self._generate_id(ids)
  115. ids.append(ruleId)
  116. # 充满自停套餐
  117. if ruleId == 'autoPackage':
  118. rule['time'] = float(rule.get('time') or 0)
  119. # 自定义输入套餐
  120. if ruleId == 'customPackage':
  121. rule['time'] = float(rule.get('time') or 0)
  122. self.washConfig[ruleId] = {
  123. 'name': rule.get('name') or '套餐{}'.format(i + 1),
  124. 'price': round(RMB(rule.get('price') or 0), 2),
  125. 'coins': round(RMB(rule.get('price') or 0), 2)
  126. }
  127. if 'switch' in rule:
  128. self.washConfig[ruleId].update({'switch': rule.get('switch', True)})
  129. if 'time' in rule:
  130. self.washConfig[ruleId].update({'time': round(float(rule.get('time') or 0), 2)})
  131. if 'unit' in rule:
  132. self.washConfig[ruleId].update({'unit': rule.get('unit')})
  133. if 'sn' in rule:
  134. self.washConfig[ruleId].update({'sn': rule['sn']})
  135. if 'autoStop' in rule:
  136. self.washConfig[ruleId]['autoStop'] = rule['autoStop']
  137. if 'autoRefund' in rule:
  138. self.washConfig[ruleId]['autoRefund'] = rule.get('autoRefund', False)
  139. # 此处有可能传入空字符串 加一个or判断为0
  140. if 'minAfterStartCoins' in rule:
  141. minAfterStartCoins = round(RMB(rule['minAfterStartCoins'] or 0), 2)
  142. if minAfterStartCoins > 0 and minAfterStartCoins < self.washConfig[ruleId]['coins']:
  143. ServiceException(
  144. {'result': 0, 'description': '套餐({})最小启动金额需要大于套餐金额{}'.format(self.washConfig[ruleId]['name'], minAfterStartCoins), 'payload': {}})
  145. self.washConfig[ruleId]['minAfterStartCoins'] = minAfterStartCoins
  146. # 此处有可能传入空字符串 加一个or判断为0
  147. if 'minFee' in rule:
  148. self.washConfig[ruleId]['minFee'] = round(RMB(rule['minFee'] or 0), 2)
  149. if isTemp:
  150. self.washConfig[ruleId]['billingMethod'] = 'prepaid'
  151. else:
  152. self.washConfig[ruleId]['billingMethod'] = 'postpaid'
  153. # 检验部分
  154. if RMB(rule.get('price') or 0) > self.dealer.maxPackagePrice:
  155. raise ServiceException(
  156. {'result': 0, 'description': '套餐支付金额( {}元 )超过最大限制'.format(rule['name']), 'payload': {}})
  157. def _formart_policy_rule(self, policy):
  158. # 时间计费参数
  159. prices = policy.get('rule', {}).get('prices', [])
  160. # 电量计费参数
  161. price = policy.get('rule', {}).get('price')
  162. # 检验传过来的参数是否完整
  163. policyType = policy.get('policyType')
  164. if policyType == 'time':
  165. if prices:
  166. pass
  167. else:
  168. raise ServiceException(
  169. {'result': 0, 'description': '按时间计费规则不可为空, 请填写计费规则',
  170. 'payload': {}})
  171. if price:
  172. price = round(float(price), 2)
  173. else:
  174. price = round(self.INIT_POLICY['forApps']['rule']['price'], 2)
  175. elif policyType == 'elec':
  176. if prices:
  177. pass
  178. else:
  179. prices = self.INIT_POLICY['forApps']['rule']['prices']
  180. if price:
  181. price = round(float(price), 2)
  182. else:
  183. raise ServiceException(
  184. {'result': 0, 'description': '按电量计费参数不可为空, 请填写计费参数',
  185. 'payload': {}})
  186. else:
  187. raise ServiceException(
  188. {'result': 0, 'description': '计费方式不存在',
  189. 'payload': {}})
  190. # 时间计费部分
  191. if not prices:
  192. raise ServiceException(
  193. {'result': 0, 'description': '按时间计费规则不可为空, 请填写计费规则',
  194. 'payload': {}})
  195. for item in prices:
  196. item['power'] = int(float(item.get('power', 0)))
  197. item['price'] = round(float(item.get('price', 0)), 2)
  198. if RMB(item['price']) > self.dealer.maxPackagePrice:
  199. raise ServiceException(
  200. {'result': 0, 'description': '计费规则(功率: {}, 价格: {})金额超限'.format(item['power'], item['price']),
  201. 'payload': {}})
  202. prices = sorted(prices, key=lambda _: _['power'])
  203. # 电量计费部分
  204. if price > 10:
  205. raise ServiceException(
  206. {'result': 0, 'description': '电量模式: 电费单价金额超限(电费单价不得大于10元/度)'.format(price),
  207. 'payload': {}})
  208. return {'prices': prices, 'price': price}
  209. def _formart_apps(self):
  210. forApps = self.policyTemp.get('forApps', {})
  211. forApps['rule'] = self._formart_policy_rule(forApps)
  212. forApps['policyType'] = forApps.get('policyType')
  213. return forApps
  214. def _formart_Idcard(self):
  215. forIdcard = self.policyTemp.get('forIdcard', {})
  216. forIdcard['policyType'] = forIdcard.get('policyType', 'time')
  217. forIdcard['rule'] = self._formart_policy_rule(forIdcard)
  218. forIdcard['billingMethod'] = forIdcard.get('billingMethod', 'prepaid')
  219. if forIdcard['billingMethod'] == 'prepaid':
  220. forIdcard['money'] = round(float(forIdcard.get('money', 1)), 2)
  221. if RMB(forIdcard['money']) > self.dealer.maxPackagePrice:
  222. raise ServiceException(
  223. {'result': 0, 'description': '刷一次卡扣费金额( {} )超限'.format(forIdcard['money']), 'payload': {}})
  224. forIdcard['autoRefund'] = forIdcard.get('autoRefund', True)
  225. elif forIdcard['billingMethod'] == 'postpaid':
  226. forIdcard['minAfterStartCoins'] = round(float(forIdcard.get('minAfterStartCoins', 1)), 2)
  227. return forIdcard
  228. def _formart_policy(self):
  229. self.policyTemp = {'forApps': self._formart_apps(), 'forIdcard': self._formart_Idcard()}
  230. def _get_ruleList(self, isTemp=False):
  231. if isTemp:
  232. config = self.device.get('tempWashConfig', {})
  233. else:
  234. config = self.device['washConfig']
  235. ruleList = []
  236. for packageId, rule in config.items():
  237. item = {
  238. 'id': packageId,
  239. 'name': rule['name'],
  240. 'coins': rule.get('price'),
  241. 'price': rule.get('price'),
  242. 'time': rule.get('time', 20),
  243. 'description': rule.get('description', ''),
  244. 'imgList': rule.get('imgList', []),
  245. 'unit': rule.get('unit', u'分钟'),
  246. 'switch': rule.get('switch', True),
  247. }
  248. if 'sn' in rule:
  249. item['sn'] = rule['sn']
  250. if 'autoStop' in rule:
  251. item['autoStop'] = rule['autoStop']
  252. if 'autoRefund' in rule:
  253. item['autoRefund'] = rule['autoRefund']
  254. if 'minAfterStartCoins' in rule:
  255. item['minAfterStartCoins'] = rule['minAfterStartCoins']
  256. if 'minFee' in rule:
  257. item['minFee'] = rule['minFee']
  258. if 'billingMethod' in rule:
  259. item['billingMethod'] = rule['billingMethod']
  260. ruleList.append(item)
  261. return sorted(ruleList, key=lambda x: (x.get('sn'), x.get('id')))
  262. def _get_displaySwitch(self, isTemp=False):
  263. displaySwitchs = {
  264. "displayCoinsSwitch": False,
  265. "displayPriceSwitch": isTemp,
  266. "displayTimeSwitch": True,
  267. "setBasePriceAble": False,
  268. "setPulseAble": False
  269. }
  270. return displaySwitchs
  271. def _get_policy(self):
  272. return self.device.policyTemp or self.INIT_POLICY
  273. def get_reg_model(self, dealer, devTypeId, isTemp=False, **kw):
  274. if isTemp:
  275. ruleList = []
  276. else:
  277. ruleList = [
  278. {
  279. 'id': 'autoPackage',
  280. 'autoRefund': False,
  281. 'autoStop': True,
  282. 'billingMethod': 'postpaid',
  283. 'coins': 0.0,
  284. 'minAfterStartCoins': 3.0,
  285. 'minFee': 0.1,
  286. "name": "充满自停",
  287. 'policyType': 'time',
  288. 'price': 0.0,
  289. 'sn': 0,
  290. 'switch': True,
  291. 'time': 720.0,
  292. "unit": "分钟",
  293. },
  294. {
  295. 'id': 'customPackage',
  296. 'autoRefund': False,
  297. 'autoStop': True,
  298. 'billingMethod': 'postpaid',
  299. 'coins': 0.0,
  300. 'minAfterStartCoins': 3.0,
  301. 'minFee': 0.1,
  302. "name": "自定义",
  303. 'policyType': 'time',
  304. 'price': 0.0,
  305. 'sn': 1,
  306. 'switch': True,
  307. 'time': 720.0,
  308. "unit": "分钟",
  309. },
  310. {
  311. 'autoRefund': False,
  312. 'autoStop': True,
  313. 'billingMethod': 'postpaid',
  314. 'coins': 0.0,
  315. 'minAfterStartCoins': 1.0,
  316. 'minFee': 0.0,
  317. "name": "60分钟",
  318. 'policyType': 'time',
  319. 'price': 0.0,
  320. 'sn': 2,
  321. 'switch': True,
  322. 'time': 60.0,
  323. "unit": "分钟",
  324. },
  325. ]
  326. payload = {'ruleList': ruleList, 'displaySwitchs': self._get_displaySwitch(isTemp=isTemp),
  327. 'policyTemp': self.INIT_POLICY}
  328. if devTypeId in dealer.defaultWashConfig:
  329. dealerDefaultWashConfig = dealer.defaultWashConfig[devTypeId]
  330. if dealerDefaultWashConfig.get('policyTemp'):
  331. payload.update({'policyTemp': dealerDefaultWashConfig['policyTemp']})
  332. if dealerDefaultWashConfig.get('displaySwitchs'):
  333. payload.update({'displaySwitchs': dealerDefaultWashConfig['displaySwitchs']})
  334. if dealerDefaultWashConfig.get('ruleList') and not isTemp:
  335. payload.update({'ruleList': dealerDefaultWashConfig['ruleList']})
  336. return payload
  337. def reg_model(self, owner, ruleList, policyTemp, devType):
  338. self.dealer = owner # type: Dealer
  339. self.ruleList = ruleList
  340. self.devType = devType
  341. # self.displaySwitchs = self._get_displaySwitch
  342. self.policyTemp = policyTemp
  343. self.washConfig = {}
  344. # 1.根据sn排序
  345. self._sort_by_sn()
  346. # 2 计费规则 policy 格式化
  347. self._formart_policy()
  348. # 3.套餐 ruleList 格式话
  349. self._formart_ruleList(False)
  350. payload = {'ruleList': ruleList, 'policyTemp': policyTemp}
  351. owner.defaultWashConfig[str(devType['id'])] = payload
  352. owner.save()
  353. return self.washConfig, self.policyTemp
  354. def get_show_package(self, dev, isTemp=False):
  355. self.device = dev # type: DeviceDict
  356. group = self.device.group # type: GroupDict
  357. # 探测是否地址为免费活动组,默认为否
  358. is_free_service = group.is_free
  359. if isTemp:
  360. config = self.device.get('tempWashConfig', {})
  361. else:
  362. config = self.device['washConfig']
  363. packages = []
  364. for packageId, rule in config.items():
  365. # 没有启用的套餐 直接掠过
  366. if not rule.get("switch", True):
  367. continue
  368. price = rule['price']
  369. item = {
  370. 'id': packageId,
  371. 'coins': rule['coins'],
  372. 'name': rule['name'],
  373. 'time': rule['time'],
  374. 'price': price,
  375. 'unit': rule.get('unit', u'分钟'),
  376. 'sn': rule.get('sn')
  377. }
  378. if 'minFee' in rule and rule['minFee'] and float(rule['minFee']) > 0:
  379. item.update({'minFee': rule.get('minFee')})
  380. if 'minAfterStartCoins' in rule and rule['minAfterStartCoins'] and float(rule['minAfterStartCoins']) > 0:
  381. item.update({'minAfterStartCoins': rule.get('minAfterStartCoins')})
  382. if is_free_service:
  383. item.update({'description': '当前处于免费时段'})
  384. else:
  385. item.update({'description': self._get_policy_text()})
  386. if 'policyType' in rule:
  387. item.update({'policyType': rule.get('policyType')})
  388. packages.append(item)
  389. return sorted(packages, key=lambda x: (x.get('sn'), x.get('id')))
  390. def format_device_package(self, isTemp=False, **kw):
  391. self.dealer = self.device.owner # type: Dealer
  392. self.ruleList = kw['serviceData']
  393. self.displaySwitchs = kw['displaySwitchs']
  394. self.policyTemp = kw['policyTemp']
  395. self.washConfig = {}
  396. if kw['logicalCode'].__class__.__name__ == 'list':
  397. devNoList = [Device.get_devNo_by_logicalCode(lc) for lc in kw['logicalCode']]
  398. else:
  399. devNoList = [Device.get_devNo_by_logicalCode(kw['logicalCode'])]
  400. devDict = Device.get_dev_by_nos(devNoList)
  401. if not devDict:
  402. raise ServiceException({'result': 2, 'description': u'找不到设备'})
  403. devList = devDict.keys()
  404. if isTemp:
  405. # 1.根据sn排序
  406. self._sort_by_sn()
  407. # 2.套餐 ruleList 格式话
  408. self._formart_ruleList(isTemp)
  409. # 3. 更新数据
  410. Device.objects.filter(devNo__in=devList, ownerId=str(self.dealer.id)).update(tempWashConfig=self.washConfig)
  411. else:
  412. # 1.根据sn排序
  413. self._sort_by_sn()
  414. # 2 计费规则 policy 格式化
  415. self._formart_policy()
  416. # 3.套餐 ruleList 格式话
  417. self._formart_ruleList(isTemp)
  418. # 4 更新数据
  419. Device.objects.filter(devNo__in=devList, ownerId=str(self.dealer.id)).update(washConfig=self.washConfig,
  420. policyTemp=self.policyTemp)
  421. # 清理缓存
  422. Device.invalid_many_device_cache(devList)
  423. Device.get_many_dev_control_cache(devList)
  424. def get(self, dev, isTemp=False):
  425. self.device = dev # type: DeviceDict
  426. # 1. 获取ruleList 套餐
  427. ruleList = self._get_ruleList(isTemp)
  428. # 2. 获取displacySwitch 显示开关
  429. # displaySwitchs = dev.otherConf.get('displaySwitchs') or self._get_displaySwitch(isTemp)
  430. # 3. 获取policy 计费规则
  431. policyTemp = self._get_policy()
  432. return {'ruleList': ruleList, 'policyTemp': policyTemp}
  433. def dealer_show_package(self, isTemp=False, **kw):
  434. displaySwitchs = self._get_displaySwitch(isTemp)
  435. try:
  436. # 1. 获取ruleList 套餐
  437. ruleList = self._get_ruleList(isTemp)
  438. # 2. 获取policy 计费规则
  439. policyTemp = self._get_policy()
  440. except:
  441. return {'displaySwitchs': displaySwitchs, 'policyTemp': self.INIT_POLICY,
  442. 'ruleList': []}
  443. return { 'displaySwitchs': displaySwitchs, 'policyTemp': policyTemp, 'ruleList': ruleList}
  444. def user_show_package(self, isTemp=False):
  445. group = self.device.group # type: GroupDict
  446. # 探测是否地址为免费活动组,默认为否
  447. is_free_service = group.is_free
  448. if isTemp:
  449. config = self.device.get('tempWashConfig', {})
  450. else:
  451. config = self.device['washConfig']
  452. if "displaySwitchs" in self.device.otherConf:
  453. displaySwitchs = self.device.otherConf.get('displaySwitchs')
  454. displaySwitchs = dict(filter(lambda x: "display" in x[0], displaySwitchs.items()))
  455. else:
  456. displaySwitchs = {'displayCoinsSwitch': True,
  457. 'displayTimeSwitch': True,
  458. 'displayPriceSwitch': True,
  459. }
  460. packages = []
  461. for packageId, rule in config.items():
  462. # 没有启用的套餐 直接掠过
  463. if not rule.get("switch", True):
  464. continue
  465. item = {
  466. 'id': packageId
  467. }
  468. if 'name' in rule:
  469. item['name'] = rule['name']
  470. if 'coins' in rule:
  471. item['coins'] = rule['coins']
  472. if 'price' in rule:
  473. item['price'] = rule['price']
  474. if 'time' in rule:
  475. item['time'] = rule['time']
  476. if 'description' in rule:
  477. item['description'] = rule['description']
  478. if 'unit' in rule:
  479. item['unit'] = rule['unit']
  480. if 'sn' in rule:
  481. item['sn'] = rule['sn']
  482. if 'minFee' in rule and rule['minFee'] and float(rule['minFee']) > 0:
  483. item.update({'minFee': rule.get('minFee')})
  484. if 'minAfterStartCoins' in rule and rule['minAfterStartCoins'] and float(rule['minAfterStartCoins']) > 0:
  485. item.update({'minAfterStartCoins': rule.get('minAfterStartCoins')})
  486. if 'autoRefund' in rule:
  487. item.update({'autoRefund': rule.get('autoRefund')})
  488. if is_free_service:
  489. item.update({'description': '当前处于免费时段'})
  490. item.update({'policyType': self._get_policy_type()})
  491. item.update(displaySwitchs)
  492. packages.append(item)
  493. return sorted(packages, key=lambda x: (x.get('sn'), x.get('id')))
  494. def _get_policy_type(self):
  495. policy = self._get_policy()
  496. forApps = policy.get('forApps')
  497. return forApps.get('policyType', 'time')
  498. def _get_policy_text(self):
  499. policy = self._get_policy()
  500. forApps = policy.get('forApps')
  501. policyType = forApps.get('policyType')
  502. text = ''
  503. if policyType == 'time':
  504. text += '根据功率挡位的时长计费'
  505. elif policyType == 'elec':
  506. price = forApps.get('rule', {}).get('price')
  507. text += '根据电量({}元/度)计费'.format(price)
  508. else:
  509. pass
  510. return text
  511. @property
  512. def support_device_package(self):
  513. return True
  514. class PolicyCommon(PolicyPackageInit, SmartBox):
  515. """
  516. 子类型区别
  517. 1. 默认类型(put_people_first):
  518. 常规套餐: 1.后付费,启动前需要充值 2.账户余额不足支付, 挂起一单, 直到下次支付, 才能再次启动, 3.只能启动一单.
  519. 临时套餐: 1.预付费. 2.下发金额,费用到了会停止. 3.可以启动多单.
  520. 2. 特殊类型(look_at_money):
  521. 常规套餐: 1.后付费,启动前需要充值. 2.启动下发账户全部余额, 余额用完会停止充电. 3.只能启动一单.
  522. 临时套餐: 1.预付费. 2.下发金额,费用到了会停止. 3.可以启动多单.
  523. """
  524. def reverse_hex(self, data):
  525. # type:(str) -> str
  526. if not isinstance(data, (str, unicode)):
  527. raise TypeError
  528. return ''.join(list(reversed(re.findall(r'.{2}', data))))
  529. def send_mqtt(self, payload, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, timeout=10):
  530. """
  531. 发送mqtt 指令默认210 返回data
  532. """
  533. result = MessageSender.send(self.device, cmd,
  534. payload=payload, timeout=timeout)
  535. if cmd in [DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE]:
  536. return
  537. if 'rst' in result and result['rst'] != 0:
  538. if result['rst'] == -1:
  539. raise ServiceException(
  540. {'result': 2, 'description': u'该设备正在玩命找网络,请您稍候再试', 'rst': -1})
  541. elif result['rst'] == 1:
  542. raise ServiceException(
  543. {'result': 2, 'description': u'该设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能', 'rst': 1})
  544. elif result['rst'] == 2:
  545. raise ServiceException(
  546. {'result': 2, 'description': u'设备启动失败, 检测未在工作状态', 'rst': 2})
  547. elif result['rst'] == 3:
  548. raise ServiceException(
  549. {'result': 2, 'description': u'无启动端口信息', 'rst': 3})
  550. elif result['rst'] == 4:
  551. raise ServiceException(
  552. {'result': 2, 'description': u'设备未启动', 'rst': 4})
  553. elif result['rst'] == 5:
  554. raise ServiceException(
  555. {'result': 2, 'description': u'续充失败, 计费规则不一致', 'rst': 5})
  556. elif result['rst'] == 6:
  557. raise ServiceException(
  558. {'result': 2, 'description': u'端口正在使用中, 请选择其他端口启动充电', 'rst': 6})
  559. elif result['rst'] == 7:
  560. raise ServiceException(
  561. {'result': 2, 'description': u'启动参数有误, 请联系经销商重新配置(rule_type)', 'rst': 7})
  562. elif result['rst'] == 8:
  563. raise ServiceException(
  564. {'result': 2, 'description': u'启动参数有误, 请联系经销商重新配置(billing_method)', 'rst': 8})
  565. elif result['rst'] == 9:
  566. raise ServiceException(
  567. {'result': 2, 'description': u'启动参数有误, 请联系经销商重新配置(order_id)', 'rst': 9})
  568. elif result['rst'] == 10:
  569. raise ServiceException(
  570. {'result': 2, 'description': u'启动参数有误, 请联系经销商重新配置(open_id)', 'rst': 10})
  571. elif result['rst'] == 11:
  572. raise ServiceException(
  573. {'result': 2, 'description': u'启动参数有误, 请联系经销商重新配置(rule)', 'rst': 11})
  574. elif result['rst'] == 12:
  575. raise ServiceException(
  576. {'result': 2, 'description': u'启动参数有误, 启动时间小于1分钟, 请联系经销商调整套餐', 'rst': 12})
  577. elif result['rst'] == 13:
  578. raise ServiceException(
  579. {'result': 2, 'description': u'启动参数有误, 启动电量小于0.01kW·h, 请联系经销商调整套餐', 'rst': 13})
  580. elif result['rst'] == 14:
  581. raise ServiceException(
  582. {'result': 2, 'description': u'没有找到此订单', 'rst': 14})
  583. if result.get('data'):
  584. return result['data']
  585. else:
  586. return result
  587. def _check_package(self, package):
  588. """
  589. 获取设备启动的发送数据 根据设备的当前模式以及套餐获取
  590. :param package:
  591. :return:
  592. """
  593. unit = package.get('unit', u'分钟')
  594. _time = float(package.get('time', 0))
  595. coins = float(package.get('coins', 0))
  596. price = float(package.get('price', 0))
  597. policyType = package.get('policyType')
  598. if not policyType:
  599. raise ServiceException({'result': 2, 'description': u'套餐计费方式错误, 请重新选择后配置'})
  600. billingMethod = package.get('billingMethod', CONSUMETYPE.POSTPAID)
  601. result = {'policyType': policyType, 'coins': coins, 'price': price, 'billingMethod': billingMethod}
  602. if billingMethod == CONSUMETYPE.POSTPAID:
  603. if policyType == 'time':
  604. # 按时间计费
  605. if unit == u'小时':
  606. result.update({'needTime': _time * 60, })
  607. elif unit == u'天':
  608. result.update({'needTime': _time * 24 * 60})
  609. elif unit == u'秒':
  610. result.update({'needTime': _time / 60, })
  611. elif unit == u'分钟':
  612. result.update({'needTime': _time, })
  613. else:
  614. raise ServiceException({'result': 2, 'description': u'套餐单位错误,请联系经销商'})
  615. elif policyType == 'elec':
  616. if unit == u'度':
  617. result.update({'needElec': _time, })
  618. else:
  619. raise ServiceException({'result': 2, 'description': u'套餐单位错误,请联系经销商'})
  620. else:
  621. if coins <= 0:
  622. raise ServiceException({'result': 2, 'description': u'套餐单位错误,套餐金币不能为0'})
  623. if price <= 0:
  624. raise ServiceException({'result': 2, 'description': u'套餐单位错误,套餐金额不能为0'})
  625. if policyType == 'time':
  626. pass
  627. elif policyType == 'elec':
  628. pass
  629. else:
  630. raise ServiceException({'result': 2, 'description': u'套餐单位错误,请联系经销商'})
  631. return result
  632. def update_device_configs(self, updateDict):
  633. dev = Device.objects.get(devNo=self.device.devNo)
  634. deviceConfigs = dev.otherConf.get('deviceConfigs', {})
  635. deviceConfigs.update(updateDict)
  636. dev.otherConf['deviceConfigs'] = deviceConfigs
  637. dev.save()
  638. Device.invalid_device_cache(self.device.devNo)
  639. @property
  640. def look_at_money(self):
  641. return self.device.devTypeFeatures.get('look_at_money', False)
  642. @property
  643. def accumulate_max_power(self):
  644. return self.device.devTypeFeatures.get('accumulate_max_power', False)
  645. @property
  646. def device_configs(self):
  647. dev = Device.get_dev(self.device.devNo)
  648. deviceConfigs = dev.get('otherConf', {}).get('deviceConfigs', {})
  649. return deviceConfigs
  650. @property
  651. def server_configs(self):
  652. dev = Device.get_dev(self.device.devNo)
  653. serverConfigs = dev.get('otherConf', {}).get('serverConfigs', {})
  654. return serverConfigs
  655. def update_server_configs(self, updateDict):
  656. dev = Device.objects.get(devNo=self.device.devNo)
  657. serverConfigs = dev.otherConf.get('serverConfigs', {})
  658. serverConfigs.update(updateDict)
  659. dev.otherConf['serverConfigs'] = serverConfigs
  660. dev.save()
  661. Device.invalid_device_cache(self.device.devNo)
  662. def stop(self, port=None):
  663. return self.send_mqtt({'funCode': 'stop', 'port': int(port), 'role': 'user'})
  664. def stop_charging_port(self, port):
  665. return self.send_mqtt({'funCode': 'stop', 'port': int(port)})
  666. @property
  667. def isHaveStopEvent(self):
  668. return True
  669. def check_dev_status(self, attachParas=None):
  670. if attachParas is None:
  671. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
  672. if attachParas.get('isTempPackage') == True:
  673. washConfig = self.device.get('tempWashConfig', {})
  674. else:
  675. washConfig = self.device.get('washConfig', {})
  676. packageId = attachParas.get('packageId')
  677. if packageId: # 此时为快捷启动充电之前已经校验过一次
  678. package = washConfig.get(packageId)
  679. billingMethod = package.get('billingMethod')
  680. port = attachParas['chargeIndex']
  681. result = self.send_mqtt({'funCode': 'port_info', 'port': int(port), })
  682. if 'order_id' in result:
  683. if billingMethod == CONSUMETYPE.POSTPAID:
  684. raise ServiceException({'result': 2, 'description': u'当前端口繁忙'})
  685. else:
  686. openId = attachParas.get('openId')
  687. if result['open_id'] == openId and result['order_type'] == 'com_start' and result[
  688. 'billing_method'] == billingMethod:
  689. return
  690. else:
  691. raise ServiceException({'result': 2, 'description': u'当前端口繁忙'})
  692. def prepare_package(self, packageId, attachParas, startType=StartDeviceType.ON_LIEN):
  693. is_temp_package = 'isTempPackage' in attachParas and attachParas['isTempPackage'] is True
  694. if is_temp_package:
  695. washConfig = self._device.get('tempWashConfig', None)
  696. else:
  697. washConfig = self._device.get('washConfig', None)
  698. # 校验业务配置
  699. if not washConfig:
  700. raise ServiceException({'result': 2, 'description': u'未配置业务,请联系经销商'})
  701. # 校验套餐ID的有效性
  702. package = washConfig.get(packageId)
  703. if package is None:
  704. raise ServiceException({'result': 2, 'description': u'该套餐不存在,请联系经销商'})
  705. package['packageId'] = packageId
  706. policyType = self.device.policyTemp.get('forApps', {}).get('policyType', 'time')
  707. self.billingMethod = package.get('billingMethod', 'prepaid')
  708. if self.billingMethod == CONSUMETYPE.POSTPAID: # 后付费
  709. package = {
  710. "packageId": packageId,
  711. "name": package.get('name'),
  712. "switch": package.get('switch'),
  713. "policyType": policyType,
  714. "billingMethod": package.get('billingMethod'),
  715. "price": round(float(package.get('price', 0.0)), 2),
  716. "coins": round(float(package.get('coins', 0.0)), 2),
  717. "minAfterStartCoins": round(float(package.get('minAfterStartCoins', 0.0)), 2),
  718. "minFee": round(float(package.get('minFee', 0.0)), 2),
  719. "time": round(float(package.get('time')), 2),
  720. "unit": package.get('unit'),
  721. "sn": package.get('sn'),
  722. }
  723. if packageId == 'customPackage':
  724. customValue = float(attachParas.get('customValue') or 0)
  725. policyType = package['policyType']
  726. if policyType == 'time':
  727. unit = package['unit']
  728. if unit == '小时':
  729. customValue = customValue * 60
  730. if customValue <= 10:
  731. raise ServiceException({'result': 2, 'description': '自定义套餐充电时长不能小于10分钟'})
  732. limitTime = float(package['time']) or 720
  733. package['limitTime'] = limitTime
  734. if customValue > limitTime:
  735. raise ServiceException(
  736. {'result': 2, 'description': '自定义套餐充最大充电时长为{}分钟,请规范操作'.format(limitTime)})
  737. elif policyType == 'elec':
  738. if customValue <= 0:
  739. raise ServiceException({'result': 2, 'description': '自定义套餐充电电量不能小于0度'})
  740. limitTime = float(package['time']) or 10
  741. package['limitTime'] = limitTime
  742. if customValue > limitTime:
  743. raise ServiceException({'result': 2, 'description': '自定义套餐充最大充电量为{}度,请规范操作'.format(limitTime)})
  744. else:
  745. raise ServiceException({'result': 2, 'description': '非法自定义套餐, 请联系经销商重新配置计费规则'})
  746. package['time'] = customValue
  747. elif packageId == 'autoPackage':
  748. policyType = package['policyType']
  749. fullValue = float(package['time'])
  750. if policyType == 'time':
  751. unit = package['unit']
  752. if unit == '小时':
  753. fullValue = fullValue * 60
  754. # 最大720分钟 超过就
  755. package['fullValue'] = fullValue or 720
  756. elif policyType == 'elec':
  757. package['fullValue'] = fullValue or 10
  758. else:
  759. raise ServiceException({'result': 2, 'description': '套餐计费规则配置错误, 请联系经销商重新配置计费规则'})
  760. else:
  761. # 预付费
  762. # 1. 检验套餐设置的投币数
  763. if 'coins' not in package:
  764. raise ServiceException({'result': 2, 'description': u'套餐未设置投币数,请联系经销商'})
  765. package = {
  766. "packageId": packageId,
  767. "name": package.get('name'),
  768. "switch": package.get('switch'),
  769. "policyType": policyType,
  770. "autoRefund": package.get('autoRefund', False),
  771. "billingMethod": package.get('billingMethod'),
  772. "price": round(float(package.get('price', 0.0)), 2),
  773. "coins": round(float(package.get('coins', 0.0)), 2),
  774. "minAfterStartCoins": round(float(package.get('minAfterStartCoins', 0.0)), 2),
  775. "minFee": round(float(package.get('minFee', 0.0)), 2),
  776. "time": round(float(package.get('time')), 2),
  777. "unit": package.get('unit'),
  778. "sn": package.get('sn'),
  779. }
  780. return package
  781. def start_device_realiable(self, order):
  782. attachParas = order.attachParas
  783. package = order.package
  784. port = attachParas.get('chargeIndex')
  785. if not port:
  786. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  787. payload = {
  788. 'funCode': 'start',
  789. 'port': int(port),
  790. 'order_id': order.orderNo,
  791. 'open_id': order.openId,
  792. 'attach_paras': {},
  793. }
  794. if attachParas.get('isFree'):
  795. payload['attach_paras']['isFree'] = True
  796. if attachParas.get('onPoints'):
  797. payload['attach_paras']['onPoints'] = True
  798. self.generate_rule(package, payload)
  799. uart_source = []
  800. uart_source.append(
  801. {'write_start': json.dumps(payload, indent=4),
  802. 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
  803. result = self.send_mqtt(payload=payload, timeout=MQTT_TIMEOUT.START_DEVICE)
  804. uart_source.append(
  805. {'rece_start': json.dumps(result, indent=4), 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
  806. # 兼容远程上分 远程上分没有订单
  807. try:
  808. order.update(uart_source=uart_source)
  809. except:
  810. pass
  811. return result
  812. def stop_by_order(self, port, orderNo):
  813. """
  814. 用户扫码后, 如果订单没有结算, 点击停止按钮, 会去设备上查询, 如果真的没有查询到模块, 此单直接作废掉, 不计费, 让用户重新扫码使用
  815. """
  816. order = ClientConsumeModelProxy.get_one(shard_filter = {'ownerId': self.device.ownerId}, devNo=self.device.devNo, orderNo=orderNo, status__ne='finished') # type: ConsumeRecord
  817. if order:
  818. order_id = order.orderNo
  819. if order.remarks == '刷卡消费' or (order.startKey and order.startKey.startswith(self.device.devNo)): # 刷卡
  820. order_id = order.startKey
  821. try:
  822. self.send_mqtt({'funCode': 'stop', 'role': 'user', 'order_id': order_id, 'port': int(port)})
  823. except ServiceException as e:
  824. if e.result['rst'] == 14: # 没有找到订单, 服务器有订单 设备上没有订单, 设备上订单丢失
  825. order.update(isNormal=False, errorDesc='设备上订单已丢失')
  826. else:
  827. raise e
  828. def check_power_price_rules(self, packages):
  829. save_configs = []
  830. lastMaxPower = 0
  831. for package in packages:
  832. try:
  833. minPower = float(package.get('min'))
  834. maxPower = float(package.get('max'))
  835. price = float(package.get('price'))
  836. except Exception:
  837. raise InvalidParameter(u'价格规则填写错误,请正确的输入每个功率段')
  838. self.check_params_range(str(price), minData=0.0, maxData=10.0, desc='功率段价格')
  839. if maxPower > 9999:
  840. raise InvalidParameter(u'最大功率不能超过9999W')
  841. if minPower != lastMaxPower:
  842. raise InvalidParameter(u'功率段之间有未覆盖到的区间,请正确设置功率段')
  843. else:
  844. lastMaxPower = maxPower
  845. save_configs.append({'min': minPower, 'max': maxPower, 'price': price})
  846. return save_configs
  847. def get_power_price_rules(self):
  848. serverConfigs = self.get_server_configs()
  849. packages = serverConfigs.get('power_price_rules', [])
  850. if not packages:
  851. packages = Const.POWER_PRICE_RULES
  852. return packages
  853. def get_uart_step(self, account_type=None, is_card=False):
  854. if account_type == 'RATIO_TIME':
  855. if is_card:
  856. powerLevel = self.device.policyTemp.get('forIdcard', {}).get('rule', {}).get('ratios', [])
  857. else:
  858. powerLevel = self.device.policyTemp.get('forApps', {}).get('rule', {}).get('ratios', [])
  859. else:
  860. if is_card:
  861. powerLevel = self.device.policyTemp.get('forIdcard', {}).get('rule', {}).get('prices', [])
  862. else:
  863. powerLevel = self.device.policyTemp.get('forApps', {}).get('rule', {}).get('prices', [])
  864. account_rule = []
  865. for pp in powerLevel:
  866. if 'power' in pp and 'price' in pp:
  867. account_rule.append(
  868. '{:0>4d}-{:0>5d}'.format(int(pp['power']), int(pp['price'] * 100)))
  869. return account_rule
  870. def generate_rule(self, package, payload):
  871. data = self._check_package(package)
  872. billingMethod = data['billingMethod']
  873. policyType = data['policyType']
  874. # rule_type: 'MONEY | TIME | ELEC | TIME_MONEY | ELEC_MONEY | TIME_ELEC | TIME_ELEC_MONEY | RATIO_TIME'#8种规则
  875. account_type = 'real' # account_type(max, real, min) 计费的规则是最大功率计费,还是实时功率计费
  876. if self.accumulate_max_power:
  877. account_type = 'max'
  878. policy = {'billing_method': billingMethod}
  879. if billingMethod == CONSUMETYPE.POSTPAID: # 后付费
  880. if policyType == 'time':
  881. if self.look_at_money:
  882. policy.update({
  883. 'rule_type': 'MONEY',
  884. 'rule': {
  885. 'account_type': account_type,
  886. 'need_time': int(data['needTime'] * 60), # 精确到秒
  887. 'step': self.get_uart_step()
  888. }})
  889. open_id = payload.get('open_id')
  890. user = MyUser.objects.filter(openId=open_id).first()
  891. if user:
  892. balance = user.calc_currency_balance(self.device.owner, self.device.group)
  893. policy['rule']['amount'] = int(balance * 100)
  894. else:
  895. policy.update({
  896. 'rule_type': 'TIME_MONEY',
  897. 'rule': {
  898. 'account_type': account_type,
  899. 'need_time': int(data['needTime'] * 60), # 精确到秒
  900. 'step': self.get_uart_step()
  901. }})
  902. elif policyType == 'elec':
  903. elecFee = float(self.device.policyTemp.get('forApps', {}).get('rule', {}).get('price', 1)) # 电费单价, 用于显示金额
  904. policy.update({
  905. 'rule_type': 'ELEC',
  906. 'rule': {
  907. 'account_type': account_type,
  908. 'need_elec': int(data['needElec'] * 3600 * 1000), # 精确到焦耳
  909. 'elec_fee': int(elecFee * 100)
  910. }})
  911. else:
  912. raise ServiceException({'result': 2, 'description': u'套餐单位错误,请联系经销商'})
  913. else: # 预付费
  914. if policyType == 'time':
  915. policy.update({
  916. 'rule_type': 'MONEY',
  917. 'rule': {
  918. 'account_type': account_type,
  919. 'amount': int(data['coins'] * 100),
  920. 'step': self.get_uart_step()
  921. },
  922. 'fee': int(data['coins'] * 100), # 本单实际支付金额
  923. },
  924. )
  925. elif policyType == 'elec':
  926. elecFee = float(self.device.policyTemp.get('forApps', {}).get('rule', {}).get('price', 1)) # 电费单价, 用于显示金额
  927. policy.update({
  928. 'rule_type': 'MONEY_BY_ELEC',
  929. 'rule': {
  930. 'account_type': account_type,
  931. 'amount': int(data['coins'] * 100), # 精确到焦耳
  932. 'elec_fee': int(elecFee * 100)
  933. },
  934. 'fee': int(data['coins'] * 100), # 本单实际支付金额
  935. })
  936. else:
  937. raise ServiceException({'result': 2, 'description': u'套餐单位错误,请联系经销商'})
  938. payload.update(policy)
  939. def custom_push_url(self, order, user, **kw):
  940. """
  941. # 如果是启动, 就进入个人服务中心, 如果是结束就进入订单详细
  942. """
  943. from apps.web.utils import concat_user_center_entry_url
  944. from apps.web.utils import concat_front_end_url
  945. if order.status in [ConsumeRecord.Status.END, ConsumeRecord.Status.FINISHED]:
  946. return super(PolicyCommon, self).custom_push_url(order, user, **kw)
  947. else:
  948. return concat_user_center_entry_url(agentId=user.productAgentId, redirect=concat_front_end_url(
  949. uri='/user/index.html#/user/deviceStatus?orderId={}'.format(str(order.id))))
  950. def format_port_using_detail(self, detailDict):
  951. detailDict = super(PolicyCommon, self).format_port_using_detail(detailDict)
  952. if 'actualNeedTime' in detailDict:
  953. detailDict.pop('actualNeedTime')
  954. if 'coins' in detailDict:
  955. detailDict['coins'] = '{}元'.format(detailDict['coins'])
  956. if 'leftTime' in detailDict:
  957. detailDict.pop('leftTime')
  958. return detailDict
  959. def get_port_info(self, line):
  960. result = self.send_mqtt({'funCode': 'port_info', 'port': int(line)})
  961. port_info = {}
  962. # 主板串口传回数据
  963. if 'current_power' in result:
  964. port_info['power'] = str(result['current_power'])
  965. if 'status' in result:
  966. port_info['status'] = result['status']
  967. if 'duration' in result:
  968. port_info['usedTime'] = round(result['duration'] / 60.0, 1)
  969. if 'elec' in result:
  970. port_info['usedElec'] = round(result['elec'] / 3600000.0, 3)
  971. if 'rule' in result:
  972. rule = result['rule']
  973. if 'rule_type' in result:
  974. rule_type = result['rule_type']
  975. if rule_type == 'TIME_MONEY':
  976. if 'need_time' in rule:
  977. port_info['needTime'] = round(rule['need_time'] / 60.0, 1)
  978. port_info['actualNeedTime'] = round(rule['need_time'] / 60.0, 1)
  979. elif rule_type == 'ELEC':
  980. if 'need_elec' in rule:
  981. port_info['needElec'] = round(rule['need_elec'] / 3600000.0, 3)
  982. elif rule_type == 'MONEY':
  983. if 'amount' in rule:
  984. port_info['coins'] = round(rule['amount'] / 100.0, 2)
  985. elif rule_type == 'MONEY_BY_ELEC':
  986. if 'amount' in rule:
  987. port_info['coins'] = round(rule['amount'] / 100.0, 2)
  988. if 'need_pay' in result:
  989. if result['need_pay'] == -1:
  990. pass
  991. else:
  992. port_info['consumeMoney'] = format(result['need_pay'] / 3600.0 / 100.0, '.2f') + '元'
  993. if 'billing_method' in result:
  994. if result['billing_method'] == CONSUMETYPE.POSTPAID:
  995. port_info['consumeType'] = CONSUMETYPE.POSTPAID
  996. else:
  997. if result['order_type'] == 'com_start':
  998. port_info['consumeType'] = CONSUMETYPE.MOBILE
  999. elif result['order_type'] == 'id_start':
  1000. port_info['consumeType'] = CONSUMETYPE.CARD
  1001. if 'card_id' in result:
  1002. port_info['cardNo'] = format(int(result['card_id'], 16), 'd')
  1003. if 'sts' in result:
  1004. port_info['startTime'] = to_datetime(result['sts']).strftime('%m-%d %H:%M:%S')
  1005. attach_paras = result.get('attach_paras', {})
  1006. if 'onPoints' in attach_paras:
  1007. port_info['nickName'] = '经销商上分'
  1008. elif 'isFree' in attach_paras:
  1009. port_info.pop('coins', None)
  1010. port_info.pop('consumeMoney', None)
  1011. port_info['consumeType'] = 'isFree'
  1012. else:
  1013. if 'order_id' in result:
  1014. consumeRcd = ConsumeRecord.objects.filter(
  1015. Q(orderNo=result['order_id']) | Q(startKey=result['order_id'])).first()
  1016. user = consumeRcd.user
  1017. port_info['nickName'] = user.nickname
  1018. port_info['openId'] = user.openId
  1019. if consumeRcd.package.get('packageId', '') == 'autoPackage':
  1020. if consumeRcd.package.get('policyType') == 'time':
  1021. port_info['needTime'] = 999
  1022. port_info.pop('needElec', None)
  1023. port_info.pop('usedElec', None)
  1024. elif consumeRcd.package.get('policyType') == 'elec':
  1025. port_info['needTime'] = 999
  1026. port_info.pop('needTime', None)
  1027. else:
  1028. if consumeRcd.package.get('policyType') == 'time':
  1029. port_info.pop('needElec', None)
  1030. port_info.pop('usedElec', None)
  1031. elif consumeRcd.package.get('policyType') == 'elec':
  1032. port_info.pop('needTime', None)
  1033. port_info.pop('leftTime', None)
  1034. return port_info
  1035. def get_ports_info(self, **kw):
  1036. result = self.get_port_status_from_dev()
  1037. port_list = []
  1038. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  1039. statsMap = {Const.DEV_WORK_STATUS_IDLE: 'idle',
  1040. Const.DEV_WORK_STATUS_WORKING: 'busy',
  1041. Const.DEV_WORK_STATUS_FAULT: 'fault',
  1042. Const.DEV_WORK_STATUS_FORBIDDEN: 'ban',
  1043. Const.DEV_WORK_STATUS_CONNECTED: 'connected',
  1044. Const.DEV_WORK_STATUS_FINISHED: 'finished'}
  1045. for port, _info in result.items():
  1046. _info['index'] = port
  1047. if _info.get('status') == Const.DEV_WORK_STATUS_WORKING:
  1048. _info.update(self.get_port_using_detail(port, ctrInfo, isLazy=True))
  1049. for k, v in _info.items():
  1050. if k.lower().endswith('money'):
  1051. _info.pop(k)
  1052. _info['status'] = statsMap.get(_info['status'], 'busy')
  1053. port_list.append(_info)
  1054. return port_list
  1055. def check_order_state(self, openId):
  1056. """
  1057. 通过 openId 以及设备来鉴别 订单
  1058. :param openId:
  1059. :return:
  1060. """
  1061. dealerId = self.device.ownerId
  1062. return ClientConsumeModelProxy.get_not_finished_record(ownerId=dealerId, openId=openId,
  1063. devTypeCode=self._device["devType"]["code"],
  1064. package__billingMethod=CONSUMETYPE.POSTPAID)
  1065. def force_stop_order(self, order, **kwargs):
  1066. order.update(isNormal=False, errorDesc='经销商强制结束订单')