UnicomComboController.py 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348
  1. # -*- encoding: utf-8 -*-
  2. """
  3. @File : UnicomComboController.py
  4. @Time : 2022/6/23 9:18
  5. @Author : stephen
  6. @Email : zhangdongming@asj6.wecom.work
  7. @Software: PyCharm
  8. """
  9. import datetime
  10. import json
  11. import logging
  12. import time
  13. import traceback
  14. from decimal import Decimal
  15. from django.db import transaction
  16. from django.db.models import Q
  17. from django.http import HttpResponse, JsonResponse
  18. from django.views.generic.base import View
  19. from Ansjer.config import LOGGER
  20. from Model.models import UnicomDeviceInfo, UnicomCombo, Pay_Type, Order_Model, Store_Meal, AiStoreMeal, \
  21. UnicomComboOrderInfo, UnicomComboExperienceHistory, UnicomDeviceStatusChangePush, SysMsgModel, LogModel, \
  22. DeviceLiveRestrict, OrderPayLog
  23. from Object.EIoTClubObject import EIoTClubObject
  24. from Object.Enums.WXOperatorEnum import WXOperatorEnum
  25. from Object.RedisObject import RedisObject
  26. from Object.ResponseObject import ResponseObject
  27. from Object.TelecomObject import TelecomObject
  28. from Object.TokenObject import TokenObject
  29. from Object.UnicomObject import UnicomObjeect
  30. from Object.WXTechObject import WXTechObject
  31. from Object.utils import LocalDateTimeUtil
  32. from Object.utils.PayUtil import PayService
  33. from Service.CommonService import CommonService
  34. from Service.QuecCloudService import QuecCloudService
  35. # 三大运营商ICCID前6位前缀字典(key:运营商名称,value:前缀集合)
  36. OPERATOR_ICCID_PREFIX = {
  37. "中国移动": {'898600', '898602', '898604', '898607'},
  38. "中国联通": {'898601', '898606', '898609'},
  39. "中国电信": {'898603', '898611'}
  40. }
  41. # 单独提取各运营商前缀(按需使用,保持原代码兼容性)
  42. CHINA_MOBILE_ICCID_PREFIX = OPERATOR_ICCID_PREFIX["中国移动"] # 中国移动前缀集合
  43. CHINA_UNICOM_ICCID_PREFIX = OPERATOR_ICCID_PREFIX["中国联通"] # 中国联通前缀集合
  44. CHINA_TELECOM_ICCID_PREFIX = OPERATOR_ICCID_PREFIX["中国电信"] # 中国电信前缀集合
  45. class UnicomComboView(View):
  46. def get(self, request, *args, **kwargs):
  47. request.encoding = 'utf-8'
  48. operation = kwargs.get('operation')
  49. return self.validation(request.GET, request, operation)
  50. def post(self, request, *args, **kwargs):
  51. request.encoding = 'utf-8'
  52. operation = kwargs.get('operation')
  53. return self.validation(request.POST, request, operation)
  54. def validation(self, request_dict, request, operation):
  55. response = ResponseObject('cn')
  56. if operation == 'query-usage-history':
  57. return self.query_device_usage_history(request_dict, response)
  58. elif operation == 'sim-order': # 用户套餐信息查询
  59. return self.create_experience_order(response)
  60. elif operation == 'test-notify':
  61. order_id = request_dict.get('orderId', None)
  62. activate_type = request_dict.get('activateType', 0)
  63. iccid = request_dict.get('iccid', None)
  64. combo_id = request_dict.get('comboId', None)
  65. self.create_combo_order_info(order_id, int(activate_type), iccid, int(combo_id))
  66. return HttpResponse('SUCCESS')
  67. elif operation == 'device-queue-monitoring':
  68. return self.device_queue_monitoring_push(request_dict, request)
  69. elif operation == 'device-status-change': # SIM卡修改状态,异步通知接口
  70. return self.device_status_change_push(request_dict, request)
  71. elif operation == 'device-bind': # 服务器保存设备的ICCID
  72. return self.iccid_bind_serial_no(request, request_dict, response)
  73. elif operation == 'device-status': # PC调用解绑SIM卡用户,清除流量套餐数据
  74. return self.update_device_status(request, request_dict, response)
  75. elif operation == 'update-card': # 更新SIM类型
  76. return self.update_device_card_type(request_dict, response)
  77. elif operation == 'xxx-sign': # 获取签名用于测试
  78. return self.get_test_sign(request_dict, response)
  79. elif operation == 'getTimestamp':
  80. return self.get_test_sign(request_dict, response)
  81. elif operation == 'getSimBySerialNumber':
  82. return self.get_sim_by_serial_number(request_dict, response)
  83. else:
  84. token = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
  85. lang = request_dict.get('lang', token.lang)
  86. response = ResponseObject(lang)
  87. if token.code != 0:
  88. return response.json(token.code)
  89. user_id = token.userID
  90. if operation == 'combo-save': # 创建套餐
  91. return self.save_unicom_combo(request_dict, response)
  92. elif operation == 'combo-pay': # 套餐支付
  93. return self.buy_unicom_combo(user_id, request_dict, request, response)
  94. elif operation == 'combo-list': # 获取套餐列表
  95. return self.query_package_list(response)
  96. elif operation == 'get-device-info': # 获取SIM卡信息
  97. return self.get_device_info(request_dict, response)
  98. elif operation == 'user-combo-query': # 用户套餐信息查询
  99. return self.user_combo_query(user_id, request_dict, response)
  100. elif operation == 'getDeviceLiveRestrictList':
  101. return self.get_device_live_restrict_list(request_dict, response)
  102. elif operation == 'getDevice4GPackage':
  103. return self.get_device_4G_package(request_dict, response)
  104. else:
  105. return response.json(0)
  106. @classmethod
  107. def get_device_live_restrict_list(cls, request_dict, response):
  108. """
  109. 获取直播限制表
  110. @return: 直播限制列表
  111. """
  112. live_restrict_qs = DeviceLiveRestrict.objects.filter(is_del=False)
  113. live_restrict_list = []
  114. if not live_restrict_qs.exists():
  115. return response.json(0, live_restrict_list)
  116. for item in live_restrict_qs:
  117. live_restrict_list.append({
  118. 'deviceName': item.device_name,
  119. 'deviceType': item.device_type,
  120. 'deviceInfo': item.device_info,
  121. 'createdTime': item.created_time
  122. })
  123. return response.json(0, live_restrict_list)
  124. @classmethod
  125. def user_combo_query(cls, user_id, request_dict, response):
  126. """
  127. 查询套餐流量列表与正在使用流量详情
  128. @param user_id:
  129. @param request_dict:
  130. @param response:
  131. @return:
  132. """
  133. try:
  134. iccid = request_dict.get('iccid', None)
  135. if not iccid:
  136. return response.json(444)
  137. unicom_device_info_qs = UnicomDeviceInfo.objects.filter(iccid=iccid)
  138. if not unicom_device_info_qs.exists():
  139. return response.json(173)
  140. if not unicom_device_info_qs[0].user_id: # 用户SIM卡未绑定用户则进行自动绑定
  141. serial_no = unicom_device_info_qs[0].serial_no
  142. cls.experience_order_4G(iccid, serial_no, user_id) # 生成4G体验订单
  143. unicom_api = UnicomObjeect()
  144. card_type = unicom_device_info_qs[0].card_type
  145. # 查询正在生效套餐
  146. combo_order_qs = UnicomComboOrderInfo.objects.filter(iccid=iccid, status=1, is_del=False) \
  147. .values('iccid', 'status', 'combo__status', 'combo__combo_name', 'combo__combo_type',
  148. 'combo__flow_total', 'combo__remark', 'combo__expiration_days', 'combo__expiration_type',
  149. 'year', 'month', 'flow_total_usage', 'expire_time', 'activation_time', 'combo__is_unlimited')
  150. if combo_order_qs.exists():
  151. combo_order = combo_order_qs.first()
  152. flow_details = {
  153. 'flowInvalid': 0,
  154. 'iccid': iccid,
  155. 'status': combo_order['status'],
  156. 'isUnlimited': combo_order['combo__is_unlimited'],
  157. 'comboName': combo_order['combo__combo_name'],
  158. 'comboType': combo_order['combo__combo_type'],
  159. 'flowTotal': combo_order['combo__flow_total'],
  160. 'comboRemark': combo_order['combo__remark'],
  161. 'expirationDays': combo_order['combo__expiration_days'],
  162. 'expirationType': combo_order['combo__expiration_type'],
  163. 'flowTotalUsage': combo_order['flow_total_usage'],
  164. 'activationTime': combo_order['activation_time'],
  165. 'expireTime': -1 if combo_order['combo__remark'] == 'LIFETIME_FREE' else combo_order['expire_time'],
  166. 'year': combo_order['year'],
  167. 'month': combo_order['month'],
  168. }
  169. activate_flow = float(flow_details['flowTotalUsage'])
  170. # 获取卡号历史总流量
  171. flow_total_usage = float(unicom_api.get_flow_usage_total(iccid, card_type))
  172. flow = 0 if flow_total_usage <= 0 else flow_total_usage - activate_flow
  173. # 因APP问题,usableFlow可用流量替换为,已用流量值
  174. flow_details['usableFlow'] = 0 if flow == 0 else flow
  175. flow_details['usableFlow'] = flow_details['flowTotal'] \
  176. if flow_details['usableFlow'] > flow_details['flowTotal'] \
  177. else flow_details['usableFlow']
  178. flow_details['usableFlow'] = Decimal(flow_details['usableFlow']).quantize(Decimal('0.00'))
  179. flow_details.pop('flowTotalUsage')
  180. cls.update_combo_order_sort(iccid) # 排序
  181. flow_details['comboList'] = cls.get_combo_order_list(iccid) # 获取当前上架套餐
  182. return response.json(0, flow_details)
  183. else:
  184. flow_details = {'iccid': iccid, 'flowInvalid': 1, 'comboList': cls.get_combo_order_list(iccid)}
  185. cls.update_combo_order_sort(iccid)
  186. return response.json(0, flow_details)
  187. except Exception as e:
  188. logging.info('异常错误,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  189. return response.json(177, e)
  190. @classmethod
  191. def experience_order_4G(cls, icc_id, serial_no, user_id, is_user=True):
  192. """
  193. 保存订单信息
  194. @param is_user: 是否真实用户
  195. @param icc_id: SIM卡20位iccid
  196. @param serial_no: 序列号
  197. @param user_id: userID
  198. @return: True | False
  199. """
  200. try:
  201. while transaction.atomic():
  202. n_time = int(time.time())
  203. # 获取套餐信息
  204. combo_info_qs = UnicomCombo.objects.filter(combo_type=1, status=0, is_del=False) \
  205. .values('id', 'combo_name', 'price', 'virtual_price', 'remark').order_by('sort')
  206. if not combo_info_qs.exists():
  207. return False
  208. combo_info_vo = combo_info_qs[0]
  209. # 获取套餐订单信息
  210. combo_order_qs = UnicomComboOrderInfo.objects.filter(iccid=icc_id, combo_id=combo_info_vo['id'])
  211. if not combo_order_qs.exists():
  212. return False
  213. c_time = combo_order_qs[0].created_time
  214. # 根据序列号获取UID
  215. uid = CommonService.get_uid_by_serial_number(serial_no)
  216. order_id = CommonService.createOrderID()
  217. rank_id, ai_rank_id = cls.get_cloud_or_ai_combo() # 生成订单必须添加该字段
  218. order_dict = {'orderID': order_id, 'UID': uid, 'rank_id': rank_id, 'ai_rank_id': ai_rank_id,
  219. 'userID_id': user_id, 'desc': combo_info_vo['combo_name'], 'payType': 10,
  220. 'payTime': c_time, 'price': combo_info_vo['price'], 'addTime': c_time,
  221. 'updTime': c_time, 'status': 1,
  222. 'unify_combo_id': str(combo_info_vo['id']), 'order_type': 2,
  223. 'store_meal_name': combo_info_vo['combo_name']
  224. }
  225. order_qs = Order_Model.objects.filter(UID=uid, userID=user_id, order_type=2,
  226. unify_combo_id=str(combo_info_vo['id']))
  227. if not order_qs.exists():
  228. Order_Model.objects.create(**order_dict)
  229. combo_order_qs.update(order_id=order_id)
  230. if is_user:
  231. UnicomDeviceInfo.objects.filter(iccid=icc_id).update(user_id=user_id, updated_time=n_time)
  232. return True
  233. except Exception as e:
  234. print('生成4G体验订单异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  235. logging.info('生成4G体验订单异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  236. return False
  237. @classmethod
  238. def get_combo_order_list(cls, iccid):
  239. """
  240. 查询套餐列表
  241. @param iccid:
  242. @return:
  243. """
  244. combo_list = []
  245. now_time = int(time.time())
  246. before_days = LocalDateTimeUtil.get_before_days_timestamp(now_time, 90)
  247. combo_order_qs = UnicomComboOrderInfo.objects.filter(iccid=iccid, is_del=False, created_time__gt=before_days) \
  248. .values('iccid', 'status', 'combo__combo_name', 'combo__flow_total',
  249. 'combo__remark', 'combo__expiration_days', 'combo__expiration_type', 'flow_total_usage',
  250. 'expire_time', 'combo__is_unlimited').order_by('-expire_time')
  251. for item in combo_order_qs:
  252. combo_list.append({
  253. 'iccid': iccid,
  254. 'status': item['status'],
  255. 'comboName': item['combo__combo_name'],
  256. 'isUnlimited': item['combo__is_unlimited'],
  257. 'flowTotal': item['combo__flow_total'],
  258. 'comboRemark': item['combo__remark'],
  259. 'expirationDays': 0,
  260. 'expirationType': item['combo__expiration_type'],
  261. 'expireTime': -1 if item['combo__remark'] == 'LIFETIME_FREE' else item['expire_time']
  262. })
  263. return combo_list
  264. @classmethod
  265. def update_combo_order_sort(cls, iccd):
  266. """
  267. 修改套餐排序
  268. @param iccd: 联通20位ICCID
  269. @return:
  270. """
  271. combo_order_qs = UnicomComboOrderInfo.objects.filter(iccid=iccd, is_del=False)
  272. if combo_order_qs.exists():
  273. unused_qs = combo_order_qs.filter(status=0)
  274. if unused_qs.exists():
  275. unused_qs.update(sort=50)
  276. used_qs = combo_order_qs.filter(status=1)
  277. if used_qs.exists():
  278. used_qs.update(sort=1)
  279. expire_qs = combo_order_qs.filter(status=2)
  280. if expire_qs.exists():
  281. expire_qs.update(sort=100)
  282. @classmethod
  283. def update_device_status(cls, request, request_dict, response):
  284. """
  285. 重置SIM卡绑定状态修改为测试完成,以及重置流量,删除订单信息、删除系统消息
  286. """
  287. logger = logging.getLogger('info')
  288. serial_no = request_dict.get('serialNo', None)
  289. time_stamp = request_dict.get('timeStamp', None)
  290. sign = request_dict.get('sign', None)
  291. if not all([serial_no, sign, time_stamp]):
  292. return response.json(444)
  293. logger.info('PC工具进入重置SIM卡{}'.format(serial_no))
  294. try:
  295. return response.json(10072)
  296. except Exception as e:
  297. print(e.args)
  298. ex = traceback.format_exc()
  299. print(ex)
  300. logger.info('PC工具重置异常ICCID{},msg={}'.format(serial_no, ex))
  301. return response.json(177, ex)
  302. @staticmethod
  303. def reset_telecom_user(serial_no):
  304. """
  305. 重置电信用户 消息记录
  306. @param serial_no:
  307. @return:
  308. """
  309. sys_msg_qs = SysMsgModel.objects.filter(uid=serial_no)
  310. if sys_msg_qs.exists():
  311. sys_msg_qs.delete()
  312. return True
  313. @classmethod
  314. def update_device_card_type(cls, request_dict, response):
  315. """
  316. 修改设备卡类型(0:内置卡,1:外插卡)
  317. """
  318. serial_no = request_dict.get('serialNo', None)
  319. time_stamp = request_dict.get('timeStamp', None)
  320. sign = request_dict.get('sign', None)
  321. main_card = request_dict.get('type', None)
  322. if not all([serial_no, main_card, sign, time_stamp]):
  323. return response.json(444)
  324. try:
  325. if not CommonService.check_time_stamp_token(sign, time_stamp):
  326. return response.json(13)
  327. now_time = int(time.time())
  328. with transaction.atomic():
  329. unicom_device_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_no)
  330. if not unicom_device_qs.exists():
  331. return response.json(173)
  332. unicom_device_qs.update(main_card=int(main_card), updated_time=now_time)
  333. return response.json(0)
  334. except Exception as e:
  335. print(e.args)
  336. ex = traceback.format_exc()
  337. print(ex)
  338. return response.json(177, ex)
  339. @classmethod
  340. def get_device_info(cls, request_dict, response):
  341. """
  342. 获取设备信息
  343. @param request_dict:
  344. @param response:
  345. @return:
  346. """
  347. iccid = request_dict.get('iccid', None)
  348. if not iccid:
  349. return response.json(444)
  350. unicom_device_info_qs = UnicomDeviceInfo.objects.filter(iccid=iccid).values()
  351. if not unicom_device_info_qs.exists():
  352. return response.json(173)
  353. return response.json(0, dict(unicom_device_info_qs.first()))
  354. @classmethod
  355. def iccid_bind_serial_no(cls, request, request_dict, response):
  356. """
  357. iccid绑定设备序列号
  358. """
  359. iccid = request_dict.get('iccid', None)
  360. serial_no = request_dict.get('serialNo', None)
  361. time_stamp = request_dict.get('timeStamp', None)
  362. sign = request_dict.get('sign', None)
  363. sim = int(request_dict.get('sim', 1))
  364. logger = logging.getLogger('info')
  365. logger.info('--->设备调用4G注册接口{}'.format(request_dict))
  366. logger.info('iccid:{},serial_no:{}'.format(iccid, serial_no))
  367. if not all([iccid, serial_no, sign, time_stamp]):
  368. return response.json(444)
  369. # 时间戳token校验
  370. if not CommonService.check_time_stamp_token(sign, time_stamp):
  371. return response.json(13)
  372. n_time = int(time.time())
  373. try:
  374. ip = CommonService.get_ip_address(request)
  375. logger.info('--->参数验证通过,sign验证通过{}:{}'.format(serial_no, ip))
  376. # 待完善代码 根据uid与用户id验证系统设备mdcmd
  377. unicom_device_qs = UnicomDeviceInfo.objects.filter(iccid=iccid)
  378. if unicom_device_qs.exists():
  379. if unicom_device_qs.first().serial_no != serial_no:
  380. unicom_device_qs.update(main_card=sim, updated_time=n_time, serial_no=serial_no)
  381. cls.create_operation_log('unicom/api/device-bind',
  382. ip, request_dict, '4G序列号{}新绑定{}'.format(serial_no, iccid))
  383. elif unicom_device_qs.first().main_card != sim:
  384. unicom_device_qs.update(main_card=sim, updated_time=n_time)
  385. return response.json(0)
  386. params = {'iccid': iccid, 'serial_no': serial_no, 'updated_time': n_time,
  387. 'created_time': n_time, 'main_card': sim}
  388. if sim == 0: # 1:贴片卡,0:拔插卡
  389. if cls.is_dingxin_iot(iccid): # 鼎芯物联卡
  390. params['card_type'] = 5
  391. params['status'] = 2
  392. UnicomDeviceInfo.objects.create(**params)
  393. cls.create_operation_log('unicom/api/device-bind',
  394. ip, request_dict, '4G序列号{}新绑定鼎芯{}'.format(serial_no, iccid))
  395. return response.json(0)
  396. logger.error("{}外置卡或判断鼎芯国际卡异常".format(serial_no))
  397. return response.json(0, '外置卡不保存相关信息{}'.format(serial_no))
  398. if cls.is_unicom_sim(iccid): # 联通卡
  399. UnicomDeviceInfo.objects.create(**params)
  400. result = cls.activate_test_flow_package(serial_no)
  401. cls.create_operation_log('unicom/api/device-bind',
  402. ip, request_dict,
  403. '4G序列号{}绑定{},testFlowPackage{}'.format(serial_no, iccid, result))
  404. return response.json(0)
  405. elif (len(iccid) >= 6 and iccid[:6] in CHINA_TELECOM_ICCID_PREFIX
  406. and QuecCloudService.is_quec_cloud_sim(iccid)): # 移远电信
  407. params['card_type'] = 6
  408. params['status'] = 2
  409. params['iccid'] = iccid[0:19]
  410. UnicomDeviceInfo.objects.create(**params)
  411. result = cls.activate_test_flow_package(serial_no)
  412. cls.create_operation_log('unicom/api/device-bind',
  413. ip, request_dict,
  414. f"移远电信4G序列号{serial_no}绑定{iccid},testFlowPackage{result}")
  415. return response.json(0)
  416. elif cls.is_telecom_sim(iccid): # 鼎芯电信
  417. params['card_type'] = 3
  418. params['status'] = 2
  419. access_number = cls.get_access_number(iccid)
  420. if access_number:
  421. params['access_number'] = access_number
  422. UnicomDeviceInfo.objects.create(**params)
  423. result = cls.activate_test_flow_package(serial_no) # 激活测试流量套餐
  424. cls.create_operation_log('unicom/api/device-bind',
  425. ip, request_dict,
  426. '4G序列号{}绑定{},testFlowPackage{}'.format(serial_no, iccid, result))
  427. return response.json(0)
  428. elif cls.is_dingxin_iot(iccid): # 鼎芯物联卡
  429. params['card_type'] = 5 # 国际
  430. params['status'] = 2
  431. UnicomDeviceInfo.objects.create(**params)
  432. return response.json(0)
  433. elif cls.check_iccid(iccid): # 五兴物联卡
  434. params['card_type'] = 1
  435. params['status'] = 2
  436. UnicomDeviceInfo.objects.create(**params)
  437. return response.json(0)
  438. else:
  439. logger.info('--->设备请求绑定{}验证失败'.format(iccid))
  440. return response.json(173)
  441. except Exception as e:
  442. LOGGER.info('*****UnicomComboView.iccid_bind_serial_no:serial_number:{}, errLine:{}, errMsg:{}'
  443. .format(serial_no, e.__traceback__.tb_lineno, repr(e)))
  444. return response.json(177, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  445. @classmethod
  446. def get_access_number(cls, iccid):
  447. """
  448. 根据19位数ICCID查询接入号码
  449. @param iccid: 20位ICCID
  450. @return: 11位接入号码
  451. """
  452. telecom = TelecomObject()
  453. result = telecom.get_telephone(iccid[0:19])
  454. if not result:
  455. return None
  456. if result['RESULT'] == '0':
  457. return result['SMSG']
  458. return None
  459. @classmethod
  460. def is_telecom_sim(cls, iccid):
  461. """
  462. 判断是否电信SIM卡
  463. @param iccid: iccid
  464. @return: 是否鼎芯电信卡
  465. """
  466. try:
  467. telecom = TelecomObject()
  468. result = telecom.query_card_main_status(iccid[0:19])
  469. return result['resultCode'] == '0'
  470. except Exception as e:
  471. LOGGER.info('*****UnicomComboView.is_telecom_sim*****error_line:{}, error_msg:{}'
  472. .format(e.__traceback__.tb_lineno, repr(e)))
  473. return False
  474. @classmethod
  475. def is_unicom_sim(cls, iccid):
  476. """
  477. 判断是否联通SIM卡
  478. @param iccid: iccid
  479. @return: 是否联通卡结果
  480. """
  481. result = UnicomObjeect().verify_device(iccid=iccid)
  482. if result.status_code == 200 and result.text:
  483. res_dict = json.loads(result.text)
  484. if res_dict['success'] and res_dict['data']['status'] != 0:
  485. return True
  486. return False
  487. @classmethod
  488. def is_dingxin_iot(cls, iccid):
  489. """
  490. 根据iccid判断是否鼎芯国际卡
  491. """
  492. try:
  493. dx_iot = EIoTClubObject()
  494. params = {'iccid': iccid[0:19]}
  495. result = dx_iot.get_cards_info('v3', **params)
  496. if result['code'] == '900911' and len(iccid) == 20:
  497. params = {'iccid': iccid}
  498. result = dx_iot.get_cards_info('v3', **params)
  499. assert result['code'] == '200'
  500. return True
  501. except Exception as e:
  502. LOGGER.error("{}iccid判断是否鼎芯国际卡异常{}".format(iccid, repr(e)))
  503. return False
  504. @classmethod
  505. def check_iccid(cls, iccid):
  506. """
  507. 检查ICCID是否是五兴科技卡
  508. @return: True or False
  509. """
  510. if not iccid:
  511. return False
  512. iccid = iccid[0:6]
  513. arr_list = ['898603', '898611']
  514. if iccid in arr_list:
  515. return True
  516. return False
  517. @classmethod
  518. def user_activate_flow(cls, iccid):
  519. """
  520. 用户激活初始化流量套餐
  521. @param iccid:
  522. @return:
  523. """
  524. logger = logging.getLogger('info')
  525. try:
  526. while transaction.atomic():
  527. now_time = int(time.time())
  528. unicom_device_info_qs = UnicomDeviceInfo.objects.filter(iccid=iccid)
  529. if not unicom_device_info_qs.exists():
  530. return False
  531. unicom_device_info_qs = unicom_device_info_qs.first()
  532. if unicom_device_info_qs.status != 1:
  533. logger.info('---->用户激活iccid={},业务系统状态为{}'.format(iccid, unicom_device_info_qs.status))
  534. return False
  535. # 联通业务逻辑
  536. unicom_api = UnicomObjeect()
  537. unicom_api.change_device_to_activate(iccid)
  538. # 查看是否体验过免费套餐
  539. experience_history_qs = UnicomComboExperienceHistory.objects.filter(iccid=iccid)
  540. if not experience_history_qs.exists():
  541. logger.info('---->用户首次激活iccid={}'.format(iccid))
  542. combo_qs = UnicomCombo.objects.filter(combo_type=1, status=0, is_del=False) \
  543. .values('id', 'expiration_type', 'expiration_days', 'combo_type')
  544. if combo_qs.exists():
  545. combo_qs = combo_qs.first()
  546. # 保存体验记录
  547. experience_history_vo = {'iccid': iccid, 'experience_type': 0, 'do_time': now_time}
  548. UnicomComboExperienceHistory.objects.create(**experience_history_vo)
  549. # 保存套餐激活信息
  550. cls.create_combo_order_info('', 0, iccid, combo_qs['id'])
  551. # 修改业务联通卡设备激活信息
  552. UnicomDeviceInfo.objects.filter(iccid=iccid).update(status=2, updated_time=now_time,
  553. created_time=now_time)
  554. return True
  555. except Exception as e:
  556. print(e)
  557. ex = traceback.format_exc()
  558. logger.info('--->用户首次激活异常:{}'.format(ex))
  559. return False
  560. @classmethod
  561. def save_unicom_combo(cls, request_dict, response):
  562. """
  563. 联通套餐保存
  564. @param request_dict:
  565. @param response:
  566. @return:
  567. """
  568. combo_id = request_dict.get('id', None)
  569. combo_name = request_dict.get('comboName', None)
  570. flow_total = request_dict.get('flowTotal', None)
  571. expiration_days = request_dict.get('expirationDays', None)
  572. expiration_type = request_dict.get('expirationType', None)
  573. price = request_dict.get('price', None)
  574. remark = request_dict.get('remark', None)
  575. pay_type = request_dict.get('payType', '').split(',')
  576. if not all([pay_type, combo_name, flow_total, expiration_days, expiration_type, price]):
  577. return response.json(444)
  578. try:
  579. flow_total = int(flow_total)
  580. expiration_days = int(expiration_days)
  581. expiration_type = int(expiration_type)
  582. with transaction.atomic():
  583. re_data = {
  584. 'combo_name': combo_name,
  585. 'flow_total': flow_total,
  586. 'expiration_days': expiration_days,
  587. 'expiration_type': expiration_type,
  588. 'price': price,
  589. }
  590. if remark:
  591. re_data['remark'] = remark
  592. if combo_id:
  593. UnicomCombo.objects.filter(id=combo_id).update(**re_data)
  594. UnicomCombo.objects.get(id=combo_id).pay_type.set(pay_type)
  595. return response.json(0)
  596. UnicomCombo.objects.create(**re_data).pay_type.set(pay_type)
  597. return response.json(0)
  598. except Exception as e:
  599. print(e)
  600. return response.json(177, repr(e))
  601. @classmethod
  602. def query_package_list(cls, response):
  603. """
  604. 查询套餐列表
  605. @return:
  606. """
  607. try:
  608. combo_qs = UnicomCombo.objects.filter(is_show=1, status=0, is_del=False) \
  609. .order_by('sort').values('id', 'combo_name',
  610. 'flow_total',
  611. 'expiration_days',
  612. 'expiration_type', 'price',
  613. 'remark', 'virtual_price')
  614. if not combo_qs.exists():
  615. return response.json(0, [])
  616. combo_list = []
  617. for item in combo_qs:
  618. # 获取支付方式列表
  619. pay_type_qs = Pay_Type.objects.filter(unicomcombo=item['id']).values('id', 'payment')
  620. combo_list.append({
  621. 'id': item['id'],
  622. 'comboName': item['combo_name'],
  623. 'flowTotal': item['flow_total'],
  624. 'expirationDays': item['expiration_days'],
  625. 'expirationType': item['expiration_type'],
  626. 'price': item['price'],
  627. 'virtualPrice': item['virtual_price'] if item['virtual_price'] else '',
  628. 'remark': item['remark'],
  629. 'payTypes': list(pay_type_qs),
  630. })
  631. return response.json(0, combo_list)
  632. except Exception as e:
  633. print(e)
  634. return response.json(177, repr(e))
  635. @classmethod
  636. def buy_unicom_combo(cls, user_id, request_dict, request, response):
  637. """
  638. 购买联通套餐
  639. @return:
  640. """
  641. logger = logging.getLogger('info')
  642. try:
  643. with transaction.atomic():
  644. iccid = request_dict.get('iccid', None)
  645. combo_id = request_dict.get('id', None)
  646. pay_type = request_dict.get('payType', None)
  647. activate_type = request_dict.get('activateType', 0)
  648. if not all([iccid, combo_id, pay_type]):
  649. return response.json(444)
  650. combo_id = int(combo_id)
  651. pay_type = int(pay_type)
  652. now_time = int(time.time())
  653. unicom_combo_qs = UnicomCombo.objects.filter(id=combo_id, pay_type=pay_type, is_show=1, is_del=False,
  654. status=0) \
  655. .values('id', 'combo_name', 'price', 'remark')
  656. if not unicom_combo_qs.exists():
  657. return response.json(173)
  658. unicom_device_qs = UnicomDeviceInfo.objects.filter(iccid=iccid) \
  659. .values('serial_no', 'card_type')
  660. if not unicom_device_qs.exists():
  661. return response.json(173)
  662. unicom_combo_qs = unicom_combo_qs.first()
  663. price = unicom_combo_qs['price']
  664. if not price:
  665. return response.json(173)
  666. unicom_device_qs = unicom_device_qs.first()
  667. device_uid = CommonService.get_uid_by_serial_number(unicom_device_qs['serial_no'])
  668. order_id = CommonService.createOrderID()
  669. rank_id, ai_rank_id = cls.get_cloud_or_ai_combo()
  670. CARD_TO_ORDER_TYPE = {
  671. 0: 2,
  672. 6: 6
  673. }
  674. # 从字典获取,默认返回5(处理其他所有情况)
  675. order_type = CARD_TO_ORDER_TYPE.get(unicom_device_qs['card_type'], 5)
  676. order_dict = {'rank_id': rank_id, 'ai_rank_id': ai_rank_id, 'orderID': order_id, 'UID': device_uid,
  677. 'userID_id': user_id, 'desc': unicom_combo_qs['combo_name'], 'payType': pay_type,
  678. 'payTime': now_time, 'price': price, 'currency': 'CNY', 'addTime': now_time,
  679. 'updTime': now_time,
  680. 'unify_combo_id': str(unicom_combo_qs['id']), 'order_type': order_type,
  681. 'store_meal_name': unicom_combo_qs['combo_name']
  682. }
  683. params = 'lang=cn' + '&activateType=' + activate_type
  684. logger.info('激活类型:{}'.format(activate_type))
  685. serial_number = unicom_device_qs['serial_no']
  686. result = {'result_code': 0, 'reason': 'success', 'error_code': 0}
  687. if pay_type == 2: # 支付宝
  688. pay_price = PayService.get_two_float(price, 2)
  689. notify_url = 'unicom/wap/pay/ali-notify'
  690. order_dict['pay_url'] = PayService.create_alipay_payment(params, order_id, pay_price,
  691. unicom_combo_qs['combo_name'],
  692. notify_url,
  693. unicom_combo_qs['remark'], response)
  694. res_data = {'redirectUrl': order_dict['pay_url'], 'orderID': order_id}
  695. cls.create_order_pay_log(order_id, f'{serial_number}购买联通4G套餐', notify_url, 'aliPay',
  696. 'SUCCESS')
  697. elif pay_type == 3: # 微信支付
  698. notify_url = 'unicom/wap/pay/wechat-notify'
  699. ip = CommonService.get_ip_address(request)
  700. params = 'activateType=' + activate_type
  701. product_name = unicom_combo_qs['combo_name'] + unicom_combo_qs['remark']
  702. sign_params = PayService.create_wechat_payment(params, order_id,
  703. price, ip,
  704. notify_url,
  705. product_name,
  706. response)
  707. result['result'] = sign_params
  708. cls.create_order_pay_log(order_id, f'{serial_number}购买联通4G套餐', notify_url, 'wechatPay',
  709. 'SUCCESS')
  710. else:
  711. return response.json(444, {'param': 'pay_type'})
  712. Order_Model.objects.create(**order_dict)
  713. if pay_type == 3:
  714. return JsonResponse(status=200, data=result)
  715. return response.json(0, res_data)
  716. except Exception as e:
  717. print(e)
  718. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  719. @staticmethod
  720. def get_cloud_or_ai_combo():
  721. """
  722. 获取云存或者AI套餐id
  723. @return:
  724. """
  725. rank_id = Store_Meal.objects.all().order_by('sort').values('id')[0]['id']
  726. ai_rank_id = AiStoreMeal.objects.all().values('id')[0]['id']
  727. return rank_id, ai_rank_id
  728. @classmethod
  729. def query_device_usage_history(cls, request_dict, response):
  730. """
  731. 查询实时已用总流量API
  732. @return:
  733. """
  734. iccid = request_dict.get('iccid', None)
  735. if not iccid:
  736. return response.json(444)
  737. sim_card_qs = UnicomDeviceInfo.objects.filter(iccid=iccid).values('card_type')
  738. card_type = 0
  739. if sim_card_qs.exists():
  740. card_type = sim_card_qs[0]['card_type']
  741. unicom_api = UnicomObjeect()
  742. flow = unicom_api.get_flow_usage_total(iccid, card_type)
  743. return response.json(0, flow)
  744. @staticmethod
  745. def package_callback_notify(request_dict, request):
  746. """
  747. 异步套餐订购回调
  748. @param request_dict:
  749. @param request:
  750. @return:
  751. """
  752. logger = logging.getLogger('info')
  753. try:
  754. logger.info('联通异步套餐订购回调参数{}'.format(request_dict))
  755. body = request.body.decode("utf-8")
  756. if body:
  757. dict_data = json.loads(body)
  758. sign = dict_data['sign']
  759. logger.info('设备订购异步回调请求参数{}'.format(dict_data))
  760. dict_data.pop('sign')
  761. unicom_obj = UnicomObjeect()
  762. generate_sign = unicom_obj.createSign(**dict_data)
  763. logger.info('设备订购请求签名{}'.format(sign))
  764. logger.info('设备订购生成签名{}'.format(generate_sign))
  765. r_data = {'success': True, 'msg': '成功'}
  766. return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
  767. except Exception as e:
  768. print(repr(e))
  769. r_data = {'success': False, 'msg': '失败'}
  770. return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
  771. @staticmethod
  772. def device_queue_monitoring_push(request_dict, request):
  773. """
  774. 设备套餐队列用完或者到期推送
  775. @param request_dict:
  776. @param request:
  777. @return:
  778. """
  779. logger = logging.getLogger('info')
  780. try:
  781. logger.info('设备套餐队列推送{}'.format(request_dict))
  782. body = request.body.decode("utf-8")
  783. if body:
  784. dict_data = json.loads(body)
  785. sign = dict_data['sign']
  786. logger.info('设备套餐队列回调请求参数{}'.format(dict_data))
  787. dict_data.pop('sign')
  788. unicom_obj = UnicomObjeect()
  789. generate_sign = unicom_obj.createSign(**dict_data)
  790. logger.info('设备套餐队列请求签名{}'.format(sign))
  791. logger.info('设备套餐队列生成签名{}'.format(generate_sign))
  792. r_data = {'success': True, 'msg': '成功'}
  793. return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
  794. except Exception as e:
  795. print(repr(e))
  796. r_data = {'success': False, 'msg': '失败'}
  797. return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
  798. @staticmethod
  799. def device_status_change_push(request_dict, request):
  800. """
  801. 设备状态变更推送执行场景说明
  802. @param request_dict:
  803. @param request:
  804. @return:
  805. """
  806. logger = logging.getLogger('info')
  807. try:
  808. logger.info('设备状态变更推送{}'.format(request_dict))
  809. body = request.body.decode("utf-8")
  810. if body:
  811. dict_data = json.loads(body)
  812. sign = dict_data['sign']
  813. logger.info('设备状态变更推送请求参数{}'.format(dict_data))
  814. dict_data.pop('sign')
  815. unicom_obj = UnicomObjeect()
  816. generate_sign = unicom_obj.createSign(**dict_data)
  817. logger.info('联通设备状态变更推送请求签名{}'.format(sign))
  818. logger.info('联通设备状态变更推送生成签名{}'.format(generate_sign))
  819. # assert generate_sign == sign
  820. now_time = int(time.time())
  821. re_data = {
  822. 'iccid': dict_data['iccid'],
  823. 'sign': sign,
  824. 'type': dict_data['status'],
  825. 'time': dict_data['time'],
  826. 'serial_no': dict_data['operationId'],
  827. 'updated_time': now_time,
  828. 'created_time': now_time
  829. }
  830. UnicomDeviceStatusChangePush.objects.create(**re_data)
  831. r_data = {'success': True, 'msg': '成功'}
  832. return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
  833. except Exception as e:
  834. logger.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  835. r_data = {'success': False, 'msg': '失败'}
  836. return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
  837. @classmethod
  838. def create_combo_order_info(cls, order_id, activate_type, iccid, combo_id):
  839. """
  840. 创建套餐生效记录
  841. @param order_id: 订单id
  842. @param activate_type: 激活类型
  843. @param iccid: 联通20位iccid
  844. @param combo_id: 套餐id
  845. @return: True Or False
  846. """
  847. logger = logging.getLogger('info')
  848. logger.info('创建联通订单套餐信息,订单id{}'.format(order_id))
  849. try:
  850. today = datetime.datetime.today()
  851. year = today.year
  852. month = today.month
  853. with transaction.atomic():
  854. unicom_combo_qs = UnicomCombo.objects.filter(id=int(combo_id)).values()
  855. if unicom_combo_qs.exists():
  856. unicom_combo = unicom_combo_qs.first()
  857. now_time = int(time.time())
  858. combo_order_qs = UnicomComboOrderInfo.objects.filter(status=1, iccid=iccid)
  859. status = 0
  860. if not combo_order_qs.exists():
  861. status = 1
  862. combo_order_data = {'iccid': iccid, 'status': status, 'combo_id': int(combo_id),
  863. 'updated_time': now_time,
  864. 'created_time': now_time,
  865. 'year': year, 'month': month}
  866. if order_id:
  867. combo_order_data['order_id'] = order_id
  868. # 有效期类型 1 等于自然月,0天数
  869. if unicom_combo['expiration_type'] == 1:
  870. # 激活类型 1=下月激活 否则等于当月激活
  871. if activate_type == 1:
  872. combo_order_data['next_month_activate'] = True
  873. next_start_time, end_time = cls.get_next_month_data_time()
  874. combo_order_data['activation_time'] = next_start_time
  875. combo_order_data['expire_time'] = end_time
  876. combo_order_data['status'] = 0
  877. else:
  878. start_time, month_end_time = cls.get_month_start_and_end_time()
  879. combo_order_data['activation_time'] = now_time
  880. combo_order_data['expire_time'] = month_end_time
  881. elif unicom_combo['expiration_type'] == 0:
  882. days = unicom_combo['expiration_days']
  883. if activate_type == 1:
  884. combo_order_data['next_month_activate'] = True
  885. start_time, end_time = cls.get_times(days)
  886. combo_order_data['activation_time'] = start_time
  887. combo_order_data['expire_time'] = end_time
  888. combo_order_data['status'] = 0
  889. else:
  890. zero_today, end_time = cls.get_data_time(days)
  891. combo_order_data['activation_time'] = now_time
  892. combo_order_data['expire_time'] = end_time
  893. logger.info('激活类型{}'.format(activate_type))
  894. # 调用联通API查询物联卡是否已激活,未激活则修改为激活状态
  895. unicom_api = UnicomObjeect()
  896. if status == 1: # 激活当前使用的套餐,检查卡商网络状态是否为激活
  897. card_info = UnicomDeviceInfo.objects.filter(iccid=iccid).values('card_type', 'access_number')
  898. if card_info[0]['card_type'] == 3:
  899. reason = '激活' + unicom_combo['combo_name']
  900. unicom_api.change_device_to_activate(iccid, 3, card_info[0]['access_number'], reason)
  901. elif card_info[0]['card_type'] == 6: # 判断移远卡状态
  902. QuecCloudService.resume_card(iccid=iccid)
  903. else:
  904. unicom_api.change_device_to_activate(iccid)
  905. flow_total_usage = unicom_api.get_flow_usage_total(iccid, card_info[0]['card_type']) # 获取套餐总流量
  906. if flow_total_usage > 0:
  907. flow_total_usage = Decimal(flow_total_usage)
  908. flow_total_usage = flow_total_usage.quantize(Decimal('0.00'))
  909. else:
  910. flow_total_usage = 0
  911. combo_order_data['flow_total_usage'] = str(flow_total_usage)
  912. UnicomComboOrderInfo.objects.create(**combo_order_data)
  913. logger.info('保存套餐支付信息success')
  914. return True
  915. except Exception as e:
  916. error_msg = f"{iccid}创建4G订单套餐记录失败: {str(e)}"
  917. LOGGER.error(f"{error_msg} 行号: {e.__traceback__.tb_lineno}")
  918. return False
  919. @staticmethod
  920. def get_next_month_data_time():
  921. """
  922. 获取下个月开始时间与结束时间戳
  923. @return: next_start_time,end_time
  924. """
  925. next_month_start = LocalDateTimeUtil.get_next_month_start()
  926. next_start_time, next_end_time = LocalDateTimeUtil.get_start_and_end_time(next_month_start, '%Y-%m-%d')
  927. next_month_end = LocalDateTimeUtil.get_next_month_end()
  928. start_time, end_time = LocalDateTimeUtil.get_start_and_end_time(next_month_end, '%Y-%m-%d')
  929. return next_start_time, end_time
  930. @staticmethod
  931. def get_data_time(days):
  932. """
  933. 获取今天开始时间以及days后日期结束时间戳
  934. @return: next_start_time,end_time
  935. """
  936. zero_today, last_today = LocalDateTimeUtil.get_today_date(True)
  937. now_time = int(time.time())
  938. after_time = LocalDateTimeUtil.get_after_days_timestamp(now_time, days)
  939. time_array = time.localtime(after_time)
  940. start_time, end_time = LocalDateTimeUtil.get_start_and_end_time(time.strftime("%Y-%m-%d", time_array),
  941. '%Y-%m-%d')
  942. return zero_today, end_time
  943. @staticmethod
  944. def get_times(days_after):
  945. """
  946. 获取下月开始时间与指定天数后结束时间
  947. @return:
  948. """
  949. next_start_time, end_time = UnicomComboView.get_next_month_data_time()
  950. after_time = LocalDateTimeUtil.get_after_days_timestamp(next_start_time, days_after)
  951. time_array = time.localtime(after_time)
  952. start_time, end_time = LocalDateTimeUtil.get_start_and_end_time(time.strftime("%Y-%m-%d", time_array),
  953. '%Y-%m-%d')
  954. return next_start_time, end_time
  955. @staticmethod
  956. def get_month_start_and_end_time():
  957. """
  958. 获取当天开始时间与当月结束时间戳
  959. @return:
  960. """
  961. zero_today, last_today = LocalDateTimeUtil.get_today_date(True)
  962. month_end = LocalDateTimeUtil.get_cur_month_end()
  963. start_time, month_end_time = LocalDateTimeUtil.get_start_and_end_time(month_end, '%Y-%m-%d')
  964. return zero_today, month_end_time
  965. @classmethod
  966. def get_test_sign(cls, request_dict, response):
  967. """
  968. 测试盐加密解密
  969. @param request_dict:
  970. @param response:
  971. @return:
  972. """
  973. verify = request_dict.get('verify', False)
  974. if verify:
  975. sign = request_dict.get('sign')
  976. time_stamp = request_dict.get('timeStamp')
  977. sign = CommonService.check_time_stamp_token(sign, time_stamp)
  978. if not sign:
  979. return response.json(13)
  980. return response.json(0)
  981. now_time = int(time.time())
  982. sign = CommonService.encode_data(str(now_time))
  983. return response.json(0, {'sign': sign, 'timeStamp': now_time})
  984. @classmethod
  985. def create_experience_order(cls, response):
  986. """
  987. 创建体验订单
  988. """
  989. u_order_qs = UnicomComboOrderInfo.objects.filter(Q(order_id__isnull=True) | Q(order_id=''))
  990. u_order_qs = u_order_qs.filter(combo__combo_type=1).values('id', 'iccid')
  991. if not u_order_qs.exists():
  992. return response.json(0)
  993. for item in u_order_qs:
  994. u_device_qs = UnicomDeviceInfo.objects.filter(iccid=item['iccid'], status=2) \
  995. .values('serial_no', 'user_id')
  996. if not u_device_qs.exists() or not u_device_qs[0]['user_id']:
  997. continue
  998. cls.experience_order_4G(item['iccid'], u_device_qs[0]['serial_no'], u_device_qs[0]['user_id'], False)
  999. return response.json(0)
  1000. @classmethod
  1001. def create_operation_log(cls, url, ip, request_dict, describe):
  1002. """
  1003. 创建操作日志
  1004. @param url: 请求路径
  1005. @param describe: 描述
  1006. @param ip: 当前IP
  1007. @param request_dict: 请求参数
  1008. @return: True | False
  1009. """
  1010. try:
  1011. # 记录操作日志
  1012. content = json.loads(json.dumps(request_dict))
  1013. log = {
  1014. 'ip': ip,
  1015. 'user_id': 1,
  1016. 'status': 200,
  1017. 'time': int(time.time()),
  1018. 'content': json.dumps(content),
  1019. 'url': url,
  1020. 'operation': describe,
  1021. }
  1022. LogModel.objects.create(**log)
  1023. return True
  1024. except Exception as e:
  1025. print('日志异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  1026. return False
  1027. @classmethod
  1028. def get_device_4G_package(cls, request_dict, response):
  1029. """
  1030. 获取设备流量套餐
  1031. """
  1032. try:
  1033. serial_number = request_dict.get('serialNumber')
  1034. if not serial_number:
  1035. return response.json(0)
  1036. card_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_number)
  1037. if not card_qs.exists():
  1038. return response.json(0)
  1039. card_info = card_qs.first()
  1040. if card_info.card_type == 0: # 联通
  1041. card_order_qs = UnicomComboOrderInfo.objects.filter(iccid=card_info.iccid, status=1)
  1042. if not card_order_qs:
  1043. LOGGER.info(f'error{card_info.serial_no}该设备没有有效套餐')
  1044. return response.json(10069)
  1045. return response.json(0)
  1046. elif card_info.card_type == 1: # 电信
  1047. wx_tech = WXTechObject()
  1048. data = {'iccid': card_info.iccid, 'operator': WXOperatorEnum.TELECOM}
  1049. result = wx_tech.get_package_order_record(**data)
  1050. if not result:
  1051. return response.json(0)
  1052. data = result['data']
  1053. status = any(item['state'] == 1 for item in data)
  1054. return response.json(10069) if not status else response.json(0)
  1055. return response.json(0)
  1056. except Exception as e:
  1057. print('日志异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  1058. return response.json(0)
  1059. @classmethod
  1060. def activate_test_flow_package(cls, serial_number):
  1061. """
  1062. 激活测试流量套餐(100M)
  1063. @return: 成功 | 失败
  1064. """
  1065. flow_combo_qs = UnicomCombo.objects.filter(combo_type=4, is_del=False)
  1066. if not flow_combo_qs:
  1067. return False
  1068. package_id = flow_combo_qs.first().id
  1069. return cls.generate_flow_package(serial_number, package_id, '151564262337939513800138001')
  1070. @classmethod
  1071. def generate_flow_package(cls, serial_number, package_id, user_id):
  1072. """
  1073. 生成联通流量套餐包
  1074. @param serial_number: 序列号
  1075. @param package_id: 套餐id
  1076. @param user_id: 用户id
  1077. @return: True | False
  1078. """
  1079. try:
  1080. # 查询珠海联通与鼎芯电信4G卡
  1081. u_device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_number, card_type__in=[0, 3, 6])
  1082. if not u_device_info_qs.exists():
  1083. LOGGER.info(f'{serial_number}生成联通流量套餐iccid未绑定')
  1084. return False
  1085. combo_qs = UnicomCombo.objects.filter(id=package_id) \
  1086. .values('id', 'combo_name', 'price', 'virtual_price', 'remark').order_by('sort')
  1087. if not combo_qs.exists():
  1088. LOGGER.info(f'{serial_number}生成联通流量套餐不存在')
  1089. return False
  1090. # 创建订单信息记录
  1091. now_time = int(time.time())
  1092. combo_info_vo = combo_qs[0]
  1093. u_device_info = u_device_info_qs.first()
  1094. rank_id, ai_rank_id = UnicomComboView.get_cloud_or_ai_combo() # 生成订单必须添加该字段
  1095. uid = CommonService.get_uid_by_serial_number(serial_number)
  1096. if u_device_info.user_id:
  1097. user_id = u_device_info.user_id
  1098. order_id = CommonService.createOrderID()
  1099. # 定义映射关系,键为card_type,值为对应的order_type
  1100. CARD_TO_ORDER_TYPE = {
  1101. 0: 2,
  1102. 6: 6
  1103. }
  1104. # 从字典获取,默认返回5(处理其他所有情况)
  1105. order_type = CARD_TO_ORDER_TYPE.get(u_device_info.card_type, 5)
  1106. order_dict = {'orderID': order_id, 'UID': uid, 'rank_id': rank_id, 'ai_rank_id': ai_rank_id,
  1107. 'userID_id': user_id, 'desc': combo_info_vo['combo_name'], 'payType': 10,
  1108. 'payTime': now_time, 'price': combo_info_vo['price'], 'addTime': now_time,
  1109. 'updTime': now_time, 'status': 1,
  1110. 'unify_combo_id': str(combo_info_vo['id']), 'order_type': order_type,
  1111. 'store_meal_name': combo_info_vo['combo_name']
  1112. }
  1113. orderID = Order_Model.objects.create(**order_dict)
  1114. LOGGER.info(f'4G套餐订单创建成功 orderID:{orderID}, orders表写入数据')
  1115. # 创建4G套餐信息记录
  1116. UnicomComboView.create_combo_order_info(order_id, 0, u_device_info.iccid, package_id)
  1117. if u_device_info.status != 2:
  1118. UnicomDeviceInfo.objects.filter(iccid=u_device_info.iccid).update(status=2, updated_time=now_time)
  1119. LOGGER.info(f'{serial_number}生成流量套餐包成功,createdBy:{user_id}')
  1120. return True
  1121. except Exception as e:
  1122. LOGGER.info('UnicomManageControllerView.order_flow_package,{}errLine:{}, errMsg:{}'
  1123. .format(serial_number, e.__traceback__.tb_lineno, repr(e)))
  1124. return False
  1125. @staticmethod
  1126. def is_4g_device(serial_number, request_dict, request):
  1127. """
  1128. 序列号未绑定UID时调用
  1129. 判断是否4G设备(如卡停用,判断是否符合激活测试流量)
  1130. 为了解决序列号解绑UID后,测试流量用完客户出现无法添加
  1131. 增加赠送5M测试流量
  1132. """
  1133. try:
  1134. serial_no = serial_number[0:9]
  1135. key = f'ASJ:UNICOM:CARD:ACTIVATE:{serial_no}'
  1136. redis = RedisObject()
  1137. LOGGER.info(f'UnicomComboView.is_4g_device:{serial_no}')
  1138. if redis.get_data(key):
  1139. return True
  1140. # 根据序列号查询联通iccid
  1141. unicom_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_no, card_type=0) \
  1142. .values('iccid', 'status')
  1143. if not unicom_qs.exists():
  1144. return False
  1145. # 针对库存设备,此步骤激活测试流量
  1146. unicom_qs = unicom_qs[0]
  1147. order_package = UnicomComboOrderInfo.objects.filter(iccid=unicom_qs['iccid'], status=1)
  1148. if not order_package: # 当前iccid不存在正在使用的套餐
  1149. # 查询出厂其它测试流量(特殊套餐5M为了解决客户停卡添加设备)
  1150. flow_combo_qs = UnicomCombo.objects.filter(combo_type=5, is_del=False)
  1151. if not flow_combo_qs:
  1152. return False
  1153. package_id = flow_combo_qs.first().id
  1154. UnicomComboView().generate_flow_package(serial_no, package_id, '151564262337939513800138001')
  1155. redis.CONN.setnx(key, str(unicom_qs['iccid']))
  1156. redis.CONN.expire(key, 3600) # 当天赠送过测试流量的设备缓存24小时
  1157. ip = CommonService.get_ip_address(request)
  1158. describe = '{}获取uid请求激活4G卡,{}'.format(serial_no, unicom_qs['iccid'])
  1159. UnicomComboView().create_operation_log('serialNumber/get-uid', ip, request_dict, describe)
  1160. return True
  1161. LOGGER.info(f'{serial_no}有正在使用的套餐')
  1162. return True
  1163. except Exception as e:
  1164. LOGGER.info(
  1165. '{}判断是否4G设备异常,errLine:{}, errMsg:{}'.format(serial_number, e.__traceback__.tb_lineno, repr(e)))
  1166. return False
  1167. @classmethod
  1168. def update_package_order(cls, request_dict, response):
  1169. iccid = request_dict.get('iccid', None)
  1170. result = cls.update_flow_package_order_by_iccid(iccid)
  1171. print(result)
  1172. return response.json(0)
  1173. @classmethod
  1174. def update_flow_package_order_by_iccid(cls, iccid):
  1175. """
  1176. 延长无限流量套餐
  1177. """
  1178. try:
  1179. LOGGER.info(f'更新流量套餐包有效期:iccid={iccid}')
  1180. package_info_qs = UnicomComboOrderInfo.objects.filter(iccid=iccid) \
  1181. .filter(~Q(combo__combo_type=4), ~Q(status=2)).order_by('created_time')
  1182. if not package_info_qs.exists():
  1183. return False
  1184. if package_info_qs.count() > 1:
  1185. a_time = 0
  1186. is_unlimited = 0
  1187. for item in package_info_qs:
  1188. if is_unlimited == 1 and item.combo.is_unlimited == 1:
  1189. activate_time = a_time - (3600 * 12)
  1190. expire_time = LocalDateTimeUtil.get_after_days_timestamp(a_time, item.combo.expiration_days)
  1191. UnicomComboOrderInfo.objects.filter(id=item.id) \
  1192. .update(activation_time=activate_time, expire_time=expire_time,
  1193. updated_time=int(time.time()))
  1194. LOGGER.info(f'有更新:iccid={iccid}')
  1195. is_unlimited = item.combo.is_unlimited
  1196. a_time = item.expire_time
  1197. return True
  1198. except Exception as e:
  1199. LOGGER.info(
  1200. '{}update_flow_package_order_by_iccid,errLine:{}, errMsg:{}'.format(iccid, e.__traceback__.tb_lineno,
  1201. repr(e)))
  1202. return False
  1203. @staticmethod
  1204. def create_order_pay_log(order_id, business_name, api_url, sender, access_result):
  1205. """
  1206. 订单支付日志
  1207. @param order_id: 订单ID
  1208. @param business_name: 业务名称
  1209. @param api_url: 回调api地址
  1210. @param sender: 发送方/调用方
  1211. @param access_result: 获取支付请求结果
  1212. @return: True | False
  1213. """
  1214. try:
  1215. LOGGER.info(f'***创建订单支付日志order_id={order_id}')
  1216. now_time = int(time.time())
  1217. params = {
  1218. 'order_id': order_id,
  1219. 'business_name': business_name,
  1220. 'api_url': api_url, 'sender': sender, 'access_result': access_result, 'created_time': now_time,
  1221. 'updated_time': now_time,
  1222. }
  1223. OrderPayLog.objects.create(**params)
  1224. return True
  1225. except Exception as e:
  1226. LOGGER.info('{}create_order_pay_log,errLine:{}, errMsg:{}'.
  1227. format(order_id, e.__traceback__.tb_lineno, repr(e)))
  1228. return False
  1229. @staticmethod
  1230. def save_order_pay_log(order_id, trade_no, api_url, sender, access_result, response_content):
  1231. """
  1232. 保存订单支付日志
  1233. @param order_id: 订单ID
  1234. @param trade_no: 交易流水号
  1235. @param api_url: 异步回调API
  1236. @param sender: 发送方/调用方
  1237. @param access_result: 调用结果
  1238. @param response_content: 响应内容
  1239. @return: True | False
  1240. """
  1241. try:
  1242. LOGGER.info(f'***保存支付回调记录order_id={order_id},流水号={trade_no}')
  1243. now_time = int(time.time())
  1244. params = {
  1245. 'access_result': access_result,
  1246. 'updated_time': now_time,
  1247. 'trans_serial_no': trade_no,
  1248. 'response_content': response_content
  1249. }
  1250. pay_log_qs = OrderPayLog.objects.filter(order_id=order_id)
  1251. if pay_log_qs.exists():
  1252. pay_log_qs.update(**params)
  1253. return True
  1254. params['order_id'] = order_id
  1255. params['api_url'] = api_url
  1256. params['sender'] = sender
  1257. params['created_time'] = now_time
  1258. OrderPayLog.objects.create(**params)
  1259. return True
  1260. except Exception as e:
  1261. LOGGER.info('{}save_order_pay_log,errLine:{}, errMsg:{}'.
  1262. format(order_id, e.__traceback__.tb_lineno, repr(e)))
  1263. return False
  1264. @classmethod
  1265. def get_sim_by_serial_number(cls, request_dict, response):
  1266. try:
  1267. serial_number = request_dict.get('serialNumber', None)
  1268. if not serial_number:
  1269. return response.json(444)
  1270. sim_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_number[:9])
  1271. if not sim_info_qs.exists():
  1272. return response.json(173)
  1273. if sim_info_qs.count() > 1:
  1274. return response.json(15)
  1275. return response.json(0)
  1276. except Exception as e:
  1277. LOGGER.info('get_sim_by_serial_number,errLine:{}, errMsg:{}'.
  1278. format(e.__traceback__.tb_lineno, repr(e)))
  1279. return response.json(503)