UnicomManageController.py 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696
  1. # Copyright (C) 2022 #
  2. # @Time : 2022/7/18 16:16
  3. # @Author : ghl
  4. # @Email : Guanhailogn@asj6.wecom.work
  5. # @File : UnicomManageController.py
  6. # @Software: PyCharm
  7. import datetime
  8. import hashlib
  9. import json
  10. import random
  11. import threading
  12. import time
  13. import uuid
  14. from decimal import Decimal
  15. from math import ceil
  16. import openpyxl
  17. import requests
  18. from django.db import transaction, connection
  19. from django.db.models import Q, F, Count
  20. from django.http import HttpResponse
  21. from django.views.generic.base import View
  22. from Ansjer.config import CONFIG_INFO
  23. from Ansjer.config import LOGGER
  24. from Controller.UnicomCombo.UnicomComboController import UnicomComboView
  25. from Model.models import UnicomDeviceInfo, UnicomCombo, Pay_Type, UnicomComboOrderInfo, Device_User, Order_Model, \
  26. ExchangeCode, UnicomFlowPush, SysMsgModel, UnicomComboExperienceHistory, LogModel, SerialNumberPackage, \
  27. AccessNumberTaskQueue
  28. from Object.EIoTClubObject import EIoTClubObject
  29. from Object.Enums.WXOperatorEnum import WXOperatorEnum
  30. from Object.RedisObject import RedisObject
  31. from Object.ResponseObject import ResponseObject
  32. from Object.TokenObject import TokenObject
  33. from Object.UnicomObject import UnicomObjeect
  34. from Object.WXTechObject import WXTechObject
  35. from Service.CommonService import CommonService
  36. from Service.TelecomService import TelecomService
  37. UNICOM_MANAGE_LOCK = 'BASIC:UNICOM:MANAGE:OPERATION:LOCK'
  38. class UnicomManageControllerView(View):
  39. def get(self, request, *args, **kwargs):
  40. request.encoding = 'utf-8'
  41. operation = kwargs.get('operation')
  42. return self.validation(request.GET, request, operation)
  43. def post(self, request, *args, **kwargs):
  44. request.encoding = 'utf-8'
  45. operation = kwargs.get('operation')
  46. return self.validation(request.POST, request, operation)
  47. def validation(self, request_dict, request, operation):
  48. response = ResponseObject()
  49. # 获取支付类型
  50. if operation == 'get/pay':
  51. return self.get_pay_type(response)
  52. # 获取套餐类型
  53. elif operation == 'combo/type':
  54. return self.get_unicom_combo_type(response)
  55. else:
  56. tko = TokenObject(
  57. request.META.get('HTTP_AUTHORIZATION'),
  58. returntpye='pc')
  59. if tko.code != 0:
  60. return response.json(tko.code)
  61. response.lang = tko.lang
  62. userID = tko.userID
  63. # 获取套餐详细表
  64. if operation == 'get/deta/info':
  65. return self.get_unicom_info(request_dict, response)
  66. # 添加和编辑卡套餐
  67. elif operation == 'edit/combo':
  68. return self.edit_combo(request_dict, response)
  69. # 统计4G套餐
  70. elif operation == 'getComboDataList':
  71. return self.static_info(request_dict, response)
  72. # 删除卡套餐
  73. elif operation == 'dele/combo/info':
  74. return self.combo_order_info(request_dict, response)
  75. # 获取/筛选用户信息
  76. elif operation == 'filter/user':
  77. return self.get_user_info(request_dict, response)
  78. # 充值流量
  79. elif operation == 'getFlowPackages':
  80. return self.get_flow_packages(request_dict, response)
  81. # 获取/筛选4G流量卡订单信息
  82. elif operation == 'query-order':
  83. return self.query_4G_user_order(request_dict, response)
  84. elif operation == 'sim-info':
  85. return self.get_iccid_info(request_dict, response)
  86. elif operation == 'batchGenerateCDK': # 批量生成兑换码
  87. return self.create_package_cdk(request_dict, response)
  88. elif operation == 'getExchangeCodePage': # 分页获取兑换码
  89. return self.get_exchange_code_page(request_dict, response)
  90. elif operation == 'updateExchangeCode': # 修改兑换码
  91. return self.update_exchange_code(request_dict, response)
  92. elif operation == 'resetCardPackage': # 单卡重置流量
  93. return self.reset_card_package(request, request_dict, response, tko.user)
  94. elif operation == 'getPackageDetails':
  95. return self.get_package_details(request_dict, response)
  96. elif operation == 'asyncUpdateStatus':
  97. return self.async_update_status(request_dict, response)
  98. elif operation == 'getFlowComboList': # 获取流量套餐列表
  99. return self.get_flow_combo_list(request_dict, response)
  100. elif operation == 'downloadCDK': # 下载兑换码
  101. return self.package_cdk_export_excel(response)
  102. elif operation == 'uploadSerialNumberFile': # 上传序列号文件绑定4G套餐
  103. return self.serial_number_bind_package_bulk(userID, tko.user, request, request_dict, response)
  104. elif operation == 'iccidBatchReset': # 批量重置流量
  105. return self.iccid_batch_reset(tko.user, request, request_dict, response)
  106. elif operation == 'orderFlowPackage': # 订购流量套餐包
  107. return self.order_flow_package(request_dict, response, userID)
  108. elif operation == 'getSerialNumberPackagePage': # 分页获取序列号绑定套餐
  109. return self.serial_number_package_page(request_dict, response)
  110. elif operation == 'serialNumberPackageUpdate': # 序列号绑定套餐修改
  111. return self.serial_number_package_update(request_dict, response, tko.user)
  112. elif operation == 'transferDevicePackage': # 转移设备套餐
  113. return self.transfer_device_package(request_dict, response, tko.user)
  114. elif operation == 'updateExpirationDate': # 修改套餐过期时间
  115. return self.update_expiration_date(request_dict, response)
  116. elif operation == 'batchOrderFlowPackage': # 批量订购流量套餐包
  117. return self.batch_order_flow_package(request, request_dict, response, userID)
  118. elif operation == 'updateFlowComboById': # 根据ID更新流量套餐
  119. return self.update_flow_combo_by_id(request_dict, response)
  120. elif operation == 'verifyPackageExport':
  121. return self.verify_package_export_excel(request, request_dict, response)
  122. elif operation == 'batchSerialNumberCombo': # 批量查询序列号绑定iccid情况
  123. return self.batch_serial_number_combo(request, response)
  124. else:
  125. return response.json(404)
  126. @classmethod
  127. def order_flow_package(cls, request_dict, response, user_id):
  128. """
  129. 订购流量套餐包
  130. """
  131. try:
  132. serial_number = request_dict.get('serialNumber', None)
  133. package_id = request_dict.get('packageId', None)
  134. if not all([serial_number, package_id]):
  135. return response.json(444)
  136. serial_number = serial_number[0:9]
  137. result = UnicomComboView().generate_flow_package(serial_number, int(package_id), user_id)
  138. LOGGER.info(f'{serial_number}订购流量套餐包,createdBy:{user_id},result:{result}')
  139. if not result:
  140. response.json(503)
  141. return response.json(0)
  142. except Exception as e:
  143. LOGGER.info('UnicomManageControllerView.order_flow_package,errLine:{}, errMsg:{}'
  144. .format(e.__traceback__.tb_lineno, repr(e)))
  145. return response.json(500)
  146. @classmethod
  147. def reset_card_package(cls, request, request_dict, response, user):
  148. """
  149. iccid单卡重置流量
  150. @param request: 请求体
  151. @param request_dict: 请求参数
  152. @param response: 响应体
  153. @param user: 用户名称
  154. @return: 重置结果
  155. """
  156. try:
  157. serial_number = request_dict.get('serialNumber', None)
  158. if not serial_number:
  159. return response.json(444)
  160. device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_number)
  161. now_time = int(time.time())
  162. if device_info_qs.exists(): # 首先查询SIM卡绑定信息是否存在
  163. if device_info_qs.count() > 1:
  164. return response.json(177)
  165. iccid = device_info_qs.first().iccid
  166. # 根据序列号重置出厂流量套餐
  167. serial_package_qs = SerialNumberPackage.objects.filter(~Q(status=1), serial_number=serial_number)
  168. if serial_package_qs.exists():
  169. serial_package_qs.update(status=1, updated_time=now_time, updated_by=user)
  170. if device_info_qs.first().card_type == 1: # 五兴电信API删除所有套餐历史
  171. data = {'iccids': iccid, 'operator': WXOperatorEnum.TELECOM.value}
  172. wx_tech = WXTechObject()
  173. res = wx_tech.delete_card_package(**data)
  174. if res['code'] == '0':
  175. UnicomComboExperienceHistory.objects.filter(iccid=iccid).delete()
  176. LOGGER.info(f"{serial_number}电信重置流量成功:{json.dumps(res)}")
  177. return response.json(0)
  178. return response.json(176)
  179. flow_push_qs = UnicomFlowPush.objects.filter(serial_no=serial_number)
  180. if flow_push_qs.exists(): # 删除流量预警推送
  181. flow_push_qs.delete()
  182. sys_msg_qs = SysMsgModel.objects.filter(uid=serial_number)
  183. if sys_msg_qs.exists(): # 删除有关系统消息数据
  184. sys_msg_qs.delete()
  185. # 将4G用户信息状态改为已完成测试状态
  186. device_info_qs.update(status=2, updated_time=now_time, user_id='')
  187. combo_order_qs = UnicomComboOrderInfo.objects.filter(iccid=iccid)
  188. if combo_order_qs.exists():
  189. combo_order_qs.delete()
  190. # 删除免费体验记录
  191. combo_experience_history_qs = UnicomComboExperienceHistory.objects.filter(iccid=iccid)
  192. if combo_experience_history_qs.exists():
  193. combo_experience_history_qs.delete()
  194. # 重置流量后,恢复测试流量
  195. result = UnicomComboView().activate_test_flow_package(serial_number)
  196. ip = CommonService.get_ip_address(request)
  197. describe = '重置4G流量序列号{},iccid:{},{}'.format(serial_number, iccid, result)
  198. # 当前缓存是客户首次扫序列号,激活赠送测试流量生成的,重置流量所以要清除
  199. key = f'ASJ:UNICOM:CARD:ACTIVATE:{serial_number}'
  200. redis = RedisObject()
  201. redis.del_data(key)
  202. cls.create_operation_log('unicom/manage/resetCardPackage', ip, request_dict, describe)
  203. return response.json(0)
  204. return response.json(173)
  205. except Exception as e:
  206. LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  207. return response.json(500)
  208. @classmethod
  209. def generate_card_package_order(cls, iccid, serial_number):
  210. """
  211. 模拟设备上电赠送1G
  212. @param iccid:
  213. @param serial_number:
  214. @return:
  215. """
  216. url = 'https://www.zositechc.cn/' if CONFIG_INFO == 'cn' else 'https://test.zositechc.cn/'
  217. url = url + 'unicom/api/device-bind'
  218. now_time = int(time.time())
  219. sign = CommonService.encode_data(str(now_time))
  220. data = {
  221. 'iccid': iccid,
  222. 'serialNo': serial_number,
  223. 'timeStamp': now_time,
  224. 'sign': sign,
  225. 'sim': 1
  226. }
  227. response = requests.post(url=url, data=data, timeout=5)
  228. LOGGER.info(f"生成体验套餐结果:{json.loads(response.text)}")
  229. @classmethod
  230. def create_operation_log(cls, url, ip, request_dict, describe):
  231. """
  232. 存入操作日志
  233. @param url: 请求路径
  234. @param describe: 描述
  235. @param ip: 当前IP
  236. @param request_dict: 请求参数
  237. @return: True | False
  238. """
  239. try:
  240. # 记录操作日志
  241. content = json.loads(json.dumps(request_dict))
  242. log = {
  243. 'ip': ip,
  244. 'user_id': 1,
  245. 'status': 200,
  246. 'time': int(time.time()),
  247. 'content': json.dumps(content),
  248. 'url': url,
  249. 'operation': describe,
  250. }
  251. LogModel.objects.create(**log)
  252. return True
  253. except Exception as e:
  254. print('日志异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  255. return False
  256. def get_user_info(self, request_dict, response):
  257. """
  258. 获取/筛选卡用户信息
  259. @param request_dict:
  260. @param response:
  261. @return:
  262. NickName:用户昵称 phone: 电话
  263. serial_no: 设备序列号
  264. """
  265. NickName = request_dict.get('NickName', None)
  266. phone = request_dict.get('phone', None)
  267. iccid = request_dict.get('iccid', None)
  268. serial_no = request_dict.get('serialNo', None)
  269. status = request_dict.get('status')
  270. pageSize = request_dict.get('pageSize', None)
  271. pageNo = request_dict.get('pageNo', None)
  272. if not all({pageNo, pageSize}):
  273. return response.json(444)
  274. page = int(pageNo)
  275. line = int(pageSize)
  276. try:
  277. unicom_device_qs = UnicomDeviceInfo.objects.all().order_by('-updated_time')
  278. device_user_qs = Device_User.objects.filter().values(
  279. 'userID', 'NickName', 'phone')
  280. if status:
  281. unicom_device_qs = unicom_device_qs.filter(status=status)
  282. if iccid:
  283. unicom_device_qs = unicom_device_qs.filter(iccid__icontains=iccid)
  284. if serial_no:
  285. unicom_device_qs = unicom_device_qs.filter(serial_no__icontains=serial_no)
  286. if NickName:
  287. device_user_qs = device_user_qs.filter(NickName__icontains=NickName)
  288. if not device_user_qs.exists():
  289. return response.json(0, [])
  290. userID = device_user_qs.first()['userID']
  291. unicom_device_qs = unicom_device_qs.filter(user_id=userID)
  292. if phone:
  293. device_user_qs = device_user_qs.filter(phone=phone)
  294. if not device_user_qs.exists():
  295. return response.json(0, [])
  296. userID = device_user_qs.first()['userID']
  297. unicom_device_qs = unicom_device_qs.filter(user_id=userID)
  298. total = unicom_device_qs.count()
  299. unicom_device_qs = unicom_device_qs[(page - 1) * line:page * line]
  300. list_data = []
  301. for unicom_device in unicom_device_qs:
  302. data = {'iccid': unicom_device.iccid, 'serialNo': unicom_device.serial_no,
  303. 'userID': unicom_device.user_id, 'cardType': unicom_device.card_type,
  304. 'status': unicom_device.status, 'mainCard': unicom_device.main_card,
  305. 'createdTime': unicom_device.created_time, 'updatedTime': unicom_device.updated_time,
  306. 'cardStatus': self.get_device_status_by_iccid(unicom_device.iccid, unicom_device.card_type,
  307. unicom_device.access_number)}
  308. device_user_qs = Device_User.objects.filter(userID=unicom_device.user_id).values('username', 'NickName',
  309. 'phone')
  310. data['userName'] = device_user_qs[0]['username'] if device_user_qs.exists() else ''
  311. data['NickName'] = device_user_qs[0]['NickName'] if device_user_qs.exists() else ''
  312. data['phone'] = device_user_qs[0]['phone'] if device_user_qs.exists() else ''
  313. list_data.append(data)
  314. return response.json(0, {'list': list_data, 'total': total})
  315. except Exception as e:
  316. print(e)
  317. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  318. @staticmethod
  319. def query_sql_4g():
  320. """
  321. 4G关联查询SQL
  322. @return: str
  323. """
  324. sql = 'SELECT '
  325. sql += 'du.username,du.phone,o.UID as uid,o.`status`,udi.serial_no as serialNo,o.orderID,o.`desc`, '
  326. sql += 'o.price,uo.next_month_activate as nextActivate,uo.iccid,uo.`status` as useStatus,uo.`flow_total_usage`,'
  327. sql += 'uo.updated_time as upTime, uo.activation_time as acTime,uo.expire_time as epTime '
  328. sql += 'FROM orders o '
  329. sql += 'LEFT JOIN unicom_combo_order_info uo ON o.orderID = uo.order_id '
  330. sql += 'INNER JOIN device_user du ON du.userID = o.userID_id '
  331. sql += 'INNER JOIN unicom_device_info udi ON udi.iccid = uo.iccid '
  332. return sql
  333. @staticmethod
  334. def query_4G_user_order(request_dict, response):
  335. """
  336. 查询4G用户订单
  337. """
  338. try:
  339. page = int(request_dict.get('pageNo', 1))
  340. size = int(request_dict.get('pageSize', 10))
  341. user_name = request_dict.get('userName', None)
  342. uid = request_dict.get('uid', None)
  343. serial_no = request_dict.get('serialNo', None)
  344. combo_use_type = request_dict.get('comboUseType', None)
  345. cursor = connection.cursor()
  346. sql = UnicomManageControllerView.query_sql_4g()
  347. sql += 'WHERE o.order_type = %s '
  348. param_list = [2]
  349. if user_name:
  350. sql += "and du.username LIKE %s "
  351. param_list.append(user_name)
  352. if uid:
  353. sql += "and o.UID LIKE %s "
  354. param_list.append(uid)
  355. if serial_no:
  356. sql += "and udi.serial_no LIKE %s "
  357. param_list.append(serial_no)
  358. if combo_use_type:
  359. sql += 'and uo.status = %s '
  360. param_list.append(int(combo_use_type))
  361. cursor.execute(sql, param_list)
  362. total = len(cursor.fetchall())
  363. param_list.append((page - 1) * size)
  364. param_list.append(size, )
  365. sql += 'order by o.addTime DESC LIMIT %s,%s '
  366. cursor.execute(sql, param_list)
  367. data_obj = cursor.fetchall()
  368. cursor.close() # 执行完,关闭
  369. connection.close()
  370. result_list = []
  371. col_names = [desc[0] for desc in cursor.description]
  372. for item in data_obj:
  373. order_dict = dict(zip(col_names, item))
  374. order_dict['using_total'] = 0
  375. result_list.append(order_dict)
  376. return response.json(0, {'orderList': result_list, 'total': total})
  377. except Exception as e:
  378. meg = '异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e))
  379. return response.json(500, meg)
  380. @staticmethod
  381. def check_sim_user(iccid):
  382. """
  383. 检查SIM卡用户
  384. @param iccid:物联卡
  385. @return:
  386. """
  387. u_device_qs = UnicomDeviceInfo.objects.filter(iccid=iccid).values('user_id')
  388. if not u_device_qs.exists() or not u_device_qs[0]['user_id']:
  389. return False
  390. return True
  391. @classmethod
  392. def edit_combo(cls, request_dict, response):
  393. """
  394. 添加和编辑卡套餐
  395. @param request_dict:
  396. @param response:
  397. @return:
  398. """
  399. combo_id = request_dict.get('id', None)
  400. combo_name = request_dict.get('comboName', None)
  401. status = request_dict.get('status', None)
  402. combo_type = request_dict.get('comboType', None)
  403. flow_total = request_dict.get('flowTotal', None)
  404. expiration_days = request_dict.get('expirationDays', None)
  405. expiration_type = request_dict.get('expirationType', None)
  406. pay_type = request_dict.get(
  407. 'payTypes', '')[
  408. 1:-1].split(',') # '[1,2]' -> ['1','2']
  409. sort = request_dict.get('sort', None)
  410. price = request_dict.get('price', None)
  411. remark = request_dict.get('remark', None)
  412. is_show = request_dict.get('isShow', None)
  413. virtualPrice = request_dict.get('virtualPrice', None)
  414. if not all([pay_type, price, is_show, status, combo_type, flow_total, expiration_days, expiration_type]):
  415. return response.json(444)
  416. flow_total = int(flow_total)
  417. expiration_days = int(expiration_days)
  418. expiration_type = int(expiration_type)
  419. status = int(status)
  420. combo_type = int(combo_type)
  421. is_show = int(is_show)
  422. sort = int(sort)
  423. nowTime = int(time.time())
  424. # 判断是编辑还是添加
  425. with transaction.atomic():
  426. try:
  427. re_data = {
  428. 'combo_name': combo_name,
  429. 'status': status,
  430. 'combo_type': combo_type,
  431. 'flow_total': flow_total,
  432. 'expiration_days': expiration_days,
  433. 'expiration_type': expiration_type,
  434. 'price': price,
  435. 'sort': sort,
  436. 'remark': remark if remark else '',
  437. 'is_show': is_show,
  438. 'virtual_price': virtualPrice,
  439. }
  440. if combo_id:
  441. combo_type_qs = UnicomCombo.objects.filter(id=combo_id)
  442. if not combo_type_qs.exists():
  443. return response.json(173)
  444. re_data['updated_time'] = nowTime
  445. combo_type_qs.filter(id=combo_id).update(**re_data)
  446. combo_type_qs.get(id=combo_id).pay_type.set(pay_type)
  447. else:
  448. re_data['updated_time'] = int(time.time())
  449. re_data['created_time'] = int(time.time())
  450. UnicomCombo.objects.create(**re_data).pay_type.set(pay_type)
  451. return response.json(0)
  452. except Exception as e:
  453. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  454. @staticmethod
  455. def get_unicom_info(request_dict, response):
  456. """
  457. 获取套餐详细表
  458. @param request_dict:
  459. @param response:
  460. @return:
  461. """
  462. pageNo = request_dict.get('pageNo', None)
  463. pageSize = request_dict.get('pageSize', None)
  464. if not all([pageNo, pageSize]):
  465. return response.json(444)
  466. elif pageNo and pageSize:
  467. pass
  468. page = int(pageNo)
  469. line = int(pageSize)
  470. try:
  471. combo_qs = UnicomCombo.objects.filter(is_del=False) \
  472. .values('id', 'status', 'combo_name',
  473. 'flow_total', 'combo_type',
  474. 'expiration_days',
  475. 'expiration_type', 'price', 'is_unlimited',
  476. 'updated_time', 'created_time',
  477. 'remark', 'is_show', 'sort', 'virtual_price').order_by('-created_time', 'sort')
  478. if not combo_qs.exists():
  479. return response.json(0, [])
  480. total = combo_qs.count()
  481. combo_qs = combo_qs[(page - 1) * line:page * line]
  482. combo_list = []
  483. for item in combo_qs:
  484. # 获取支付方式列表
  485. pay_type_list = [pay_type['id'] for pay_type in
  486. UnicomCombo.objects.get(id=item['id']).pay_type.values('id')]
  487. combo_list.append({
  488. 'id': item['id'],
  489. 'status': item['status'],
  490. 'comboType': item['combo_type'],
  491. 'comboName': item['combo_name'],
  492. 'flowTotal': item['flow_total'],
  493. 'expirationDays': item['expiration_days'],
  494. 'expirationType': item['expiration_type'],
  495. 'price': item['price'],
  496. 'sort': item['sort'],
  497. 'isUnlimited': item['is_unlimited'],
  498. 'updatedTime': item['updated_time'],
  499. 'createdTime': item['created_time'],
  500. 'remark': item['remark'],
  501. 'isShow': item['is_show'],
  502. 'payTypes': pay_type_list,
  503. 'virtualPrice': item['virtual_price']
  504. })
  505. return response.json(0, {'list': combo_list, 'total': total})
  506. except Exception as e:
  507. print(e)
  508. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  509. @classmethod
  510. def get_pay_type(cls, response):
  511. """
  512. 获取支付类型
  513. @param response:
  514. @return:
  515. """
  516. pay_type_qs = Pay_Type.objects.all().values('id', 'payment')
  517. if not pay_type_qs.exists():
  518. return response.json(0, [])
  519. pay_type_list = []
  520. for pay_type in pay_type_qs:
  521. pay_type_list.append(pay_type)
  522. return response.json(0, pay_type_list)
  523. @classmethod
  524. def get_unicom_combo_type(cls, response):
  525. """
  526. 获取赠送套餐
  527. @param response:
  528. @return:
  529. """
  530. unicom_combo_qs = UnicomCombo.objects.filter(combo_type=2, status=0).values('id', 'combo_name')
  531. if not unicom_combo_qs.exists():
  532. return response.json(0, [])
  533. combo_list = []
  534. for combo in unicom_combo_qs:
  535. combo_list.append(combo)
  536. return response.json(0, combo_list)
  537. @classmethod
  538. def combo_order_info(cls, request_dict, response):
  539. """
  540. 删除卡套餐信息(修改状态)
  541. @param request_dict
  542. @param response
  543. @return:
  544. """
  545. combo_id = request_dict.get('id', None)
  546. if not combo_id:
  547. return response.json(444)
  548. combo_qs = UnicomCombo.objects.filter(id=combo_id)
  549. # 只修改默认状态
  550. if combo_qs.exists():
  551. combo_qs.update(is_del=True)
  552. return response.json(0)
  553. def static_info(self, request_dict, response):
  554. """
  555. 统计联通套餐
  556. @param request_dict:请求参数
  557. @param response: 响应对象
  558. @param return:
  559. """
  560. year = request_dict.get('year', None)
  561. Jan = int(time.mktime(time.strptime(year + '-1-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  562. Feb = int(time.mktime(time.strptime(year + '-2-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  563. Mar = int(time.mktime(time.strptime(year + '-3-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  564. Apr = int(time.mktime(time.strptime(year + '-4-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  565. May = int(time.mktime(time.strptime(year + '-5-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  566. Jun = int(time.mktime(time.strptime(year + '-6-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  567. Jul = int(time.mktime(time.strptime(year + '-7-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  568. Aug = int(time.mktime(time.strptime(year + '-8-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  569. Sep = int(time.mktime(time.strptime(year + '-9-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  570. Oct = int(time.mktime(time.strptime(year + '-10-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  571. Nov = int(time.mktime(time.strptime(year + '-11-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  572. Dec = int(time.mktime(time.strptime(year + '-12-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  573. Jan_next = int(time.mktime(time.strptime(str(int(year) + 1) + '-1-1 00:00:00', "%Y-%m-%d %H:%M:%S")))
  574. list_data = []
  575. unicom_combo_qs = UnicomCombo.objects.filter().values('id', 'combo_type', 'combo_name')
  576. if not unicom_combo_qs.exists():
  577. return response.json(173)
  578. try:
  579. for unicom_combo in unicom_combo_qs:
  580. name = unicom_combo['combo_name']
  581. combo_order = UnicomComboOrderInfo.objects.filter(combo_id=unicom_combo['id'])
  582. if not combo_order.exists():
  583. continue
  584. Jan_count = combo_order.filter(created_time__range=[Jan, Feb]).count()
  585. Feb_count = combo_order.filter(created_time__range=[Feb, Mar]).count()
  586. Mar_count = combo_order.filter(created_time__range=[Mar, Apr]).count()
  587. Apr_count = combo_order.filter(created_time__range=[Apr, May]).count()
  588. May_count = combo_order.filter(created_time__range=[May, Jun]).count()
  589. Jun_count = combo_order.filter(created_time__range=[Jun, Jul]).count()
  590. Jul_count = combo_order.filter(created_time__range=[Jul, Aug]).count()
  591. Aug_count = combo_order.filter(created_time__range=[Aug, Sep]).count()
  592. Sep_count = combo_order.filter(created_time__range=[Sep, Oct]).count()
  593. Oct_count = combo_order.filter(created_time__range=[Oct, Nov]).count()
  594. Nov_count = combo_order.filter(created_time__range=[Nov, Dec]).count()
  595. Dec_count = combo_order.filter(created_time__range=[Dec, Jan_next]).count()
  596. data = [Jan_count, Feb_count, Mar_count, Apr_count, May_count, Jun_count, Jul_count, Aug_count,
  597. Sep_count,
  598. Oct_count, Nov_count, Dec_count]
  599. cloud_data = {
  600. 'name': name,
  601. 'type': 'line',
  602. 'data': data,
  603. }
  604. list_data.append(cloud_data)
  605. return response.json(0, {'list': list_data})
  606. except Exception as e:
  607. print(e)
  608. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  609. @classmethod
  610. def get_flow_packages(cls, request_dict, response):
  611. """
  612. 赠送套餐流量
  613. @param request_dict:请求参数
  614. @username request_dict:用户名
  615. @comboType request_dict:套餐类型
  616. @serialNo request_dict:序列号
  617. @param response: 响应对象
  618. @return:
  619. """
  620. userId = request_dict.get('userId', None)
  621. serialNo = request_dict.get('serialNo', None)
  622. comboId = request_dict.get('comboId', None)
  623. if not all([userId, serialNo, comboId]):
  624. return response.json(444)
  625. try:
  626. while transaction.atomic():
  627. combo_info_qs = UnicomCombo.objects.filter(id=comboId, combo_type=2, status=0) \
  628. .values('id', 'combo_name', 'price', 'virtual_price', 'remark', 'combo_type')
  629. unicom_device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serialNo,
  630. user_id=userId).values \
  631. ('iccid')
  632. if not unicom_device_info_qs.exists() or not combo_info_qs.exists():
  633. return response.json(173)
  634. combo_info_qs = combo_info_qs.first()
  635. unicom_device_info_qs = unicom_device_info_qs.first()
  636. n_time = int(time.time())
  637. order_id = CommonService.createOrderID() # 生成订单号
  638. # 赠送套餐下个月生效
  639. unicom_combo = UnicomComboView.create_combo_order_info(order_id=order_id, activate_type=1,
  640. iccid=unicom_device_info_qs['iccid'],
  641. combo_id=comboId)
  642. if unicom_combo is False:
  643. return response.json(178)
  644. rank_id, ai_rank_id = UnicomComboView.get_cloud_or_ai_combo() # 生成订单必须添加该字段
  645. uid = CommonService.get_uid_by_serial_number(serialNo) # 获取序列号或UID
  646. # 获取套餐信息
  647. order_dict = {
  648. 'orderID': order_id,
  649. 'UID': uid,
  650. 'rank_id': rank_id,
  651. 'ai_rank_id': ai_rank_id,
  652. 'userID_id': userId,
  653. 'desc': combo_info_qs['combo_name'],
  654. 'payType': 10,
  655. 'payTime': n_time,
  656. 'price': combo_info_qs['price'],
  657. 'addTime': n_time,
  658. 'updTime': n_time,
  659. 'status': 1,
  660. 'unify_combo_id': str(combo_info_qs['id']),
  661. 'order_type': 2,
  662. 'store_meal_name': combo_info_qs['combo_name']
  663. }
  664. Order_Model.objects.create(**order_dict)
  665. return response.json(0)
  666. except Exception as e:
  667. print(e)
  668. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  669. @classmethod
  670. def get_iccid_info(cls, request_dict, response):
  671. """
  672. 获取联通iccid最新状态
  673. """
  674. try:
  675. iccid = request_dict.get('iccid', None)
  676. if not iccid:
  677. return response.json(444)
  678. re_data = {'iccid': iccid}
  679. result = UnicomObjeect().query_device_status(**re_data)
  680. res_dict = UnicomObjeect().get_text_dict(result)
  681. # 状态不等于1(激活)时进行激活 1:激活;2:停用
  682. return response.json(0, res_dict['data']['status'])
  683. except Exception as e:
  684. print(e)
  685. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  686. @classmethod
  687. def package_cdk_export_excel(cls, response):
  688. """
  689. 流量包兑换码导出excel
  690. """
  691. try:
  692. # 创建一个新的excel文档
  693. wb = openpyxl.Workbook()
  694. # 获取默认的工作表
  695. sheet = wb.active
  696. sheet.title = '周视国内流量年卡兑换码'
  697. sheet.column_dimensions['A'].width = 15
  698. sheet.column_dimensions['B'].width = 20
  699. exchange_code = ExchangeCode.objects.filter(status=False, is_down=False)
  700. if not exchange_code.exists():
  701. return response.json(173)
  702. # 将兑换码写入到excel表
  703. for i, vo in enumerate(list(exchange_code)):
  704. code_no = cls.fix_string_length(str(vo.id))
  705. sheet.cell(row=i + 1, column=1, value=code_no)
  706. sheet.cell(row=i + 1, column=2, value=vo.code)
  707. filename = '国内流量年卡兑换码-{}.xlsx'.format(exchange_code.count())
  708. # 创建一个http响应
  709. res = HttpResponse(content_type='application/vnd.ms-excel')
  710. # 设置响应头,告诉浏览器文件要下载而不是直接打开
  711. res['Content-Disposition'] = 'attachment; filename={}'.format(filename)
  712. # 将excel文档保存到http响应中
  713. wb.save(res)
  714. exchange_code.update(is_down=True, updated_time=int(time.time()))
  715. return res
  716. except Exception as e:
  717. LOGGER.info('*****UnicomManageController.package_cdk_export_excel:errLine:{}, errMsg:{}'
  718. .format(e.__traceback__.tb_lineno, repr(e)))
  719. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  720. @staticmethod
  721. def fix_string_length(code_no):
  722. """
  723. 将兑换码编号生成固定6位长度
  724. """
  725. if len(code_no) < 6:
  726. return 'NO.' + code_no.rjust(6, '0')
  727. else:
  728. return 'NO.' + code_no
  729. @classmethod
  730. def create_package_cdk(cls, request_dict, response):
  731. """
  732. 批量生成兑换码
  733. """
  734. try:
  735. LOGGER.info('*****UnicomManageController.create_package_cdk,params:{}'.format(request_dict))
  736. quantity = request_dict.get('quantity', None)
  737. package_id = request_dict.get('packageId', None)
  738. if not all([quantity, package_id]):
  739. return response.json(444)
  740. combo_qs = UnicomCombo.objects.filter(id=int(package_id))
  741. if not combo_qs.exists():
  742. return response.json(173)
  743. combo = combo_qs.first()
  744. exchange_code_list = []
  745. now_time = int(time.time())
  746. if combo.combo_type == 3: # 五兴电信
  747. for i in range(int(quantity)):
  748. # 10位兑换码 后面两位为标识代表五兴电信
  749. code = cls.generate_code() + 'WD'
  750. exchange_code_list.append(ExchangeCode(code=code, status=False, is_down=0,
  751. package_type=1, package_id=combo.id,
  752. expire_time=0,
  753. created_time=now_time,
  754. updated_time=now_time))
  755. elif combo.combo_type == 0: # 珠海联通
  756. for i in range(int(quantity)):
  757. # 10位兑换码 后面两位为标识代表五兴电信
  758. code = cls.generate_code() + 'ZL'
  759. exchange_code_list.append(ExchangeCode(code=code, status=False, is_down=0,
  760. package_type=0, package_id=combo.id,
  761. expire_time=0,
  762. created_time=now_time,
  763. updated_time=now_time))
  764. if exchange_code_list:
  765. ExchangeCode.objects.bulk_create(exchange_code_list)
  766. return response.json(0)
  767. return response.json(178)
  768. except Exception as e:
  769. LOGGER.info('*****UnicomManageController.create_package_cdk:errLine:{}, errMsg:{}'
  770. .format(e.__traceback__.tb_lineno, repr(e)))
  771. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  772. @classmethod
  773. def generate_code(cls):
  774. # 生成uuid并移除-
  775. uuid_str = str(uuid.uuid4()).replace('-', '')
  776. now_time = int(time.time())
  777. uuid_str += str(now_time)
  778. # 使用SHA1算法生成哈希值
  779. sha1 = hashlib.sha1(uuid_str.encode('utf-8'))
  780. # 取哈希值的前8位,并将其转换为大写字母
  781. code = sha1.hexdigest()[:8].upper()
  782. return code
  783. @classmethod
  784. def get_package_details(cls, request_dict, response):
  785. """
  786. 根据序列号获取套餐包列表
  787. """
  788. serial_number = request_dict.get('serialNumber', None)
  789. if not serial_number:
  790. return response.json(444)
  791. ud_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_number) \
  792. .values('iccid', 'card_type')
  793. package_list = []
  794. if not ud_qs.exists():
  795. return response.json(0, {'packageList': package_list})
  796. iccid = ud_qs[0]['iccid']
  797. card_type = ud_qs[0]['card_type']
  798. if card_type == 0 or card_type == 3:
  799. o_qs = UnicomComboOrderInfo.objects.filter(iccid=iccid) \
  800. .values('id', 'status', 'flow_total_usage', 'flow_exceed', 'activation_time', 'expire_time',
  801. 'combo__combo_name', 'combo__flow_total', 'updated_time') \
  802. .order_by('created_time')
  803. if not o_qs:
  804. return response.json(0, {'packageList': package_list})
  805. return response.json(0, {'package_list': cls.get_unicom_package_list(iccid, o_qs)})
  806. if card_type == 1:
  807. data = {'iccid': iccid, 'operator': 3}
  808. return response.json(0, {'package_list': cls.get_wx_package_list(**data)})
  809. if card_type == 5:
  810. data = {'iccid': iccid, 'timestamp': int(time.time()), 'nonce': random.randint(10000, 99999)}
  811. original_data = EIoTClubObject.query_order_record_list("v3", **data)
  812. return response.json(0, {'package_list': cls.get_dx_package_list(original_data)})
  813. return response.json(0, {'package_list': package_list})
  814. @classmethod
  815. def update_flow_combo_by_id(cls, request_dict, response):
  816. """
  817. 根据ID修改流量套餐
  818. """
  819. try:
  820. flow_combo_id = request_dict.get('id', None)
  821. expire_time = request_dict.get('expireTime', None)
  822. if not all([flow_combo_id, expire_time]):
  823. return response.json(0)
  824. UnicomComboOrderInfo.objects.filter(id=int(flow_combo_id)).update(expire_time=int(expire_time))
  825. return response.json(0)
  826. except Exception as e:
  827. LOGGER.error('*****更新流量套餐异常:errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  828. return response(500)
  829. @staticmethod
  830. def get_unicom_package_list(iccid, o_qs):
  831. package_list = []
  832. unicom_api = UnicomObjeect()
  833. for i, item in enumerate(o_qs):
  834. package_status = item['status']
  835. flow_total = item['combo__flow_total']
  836. flow_total_usage = float(unicom_api.get_flow_usage_total(iccid))
  837. activate_flow = float(item['flow_total_usage']) if item['flow_total_usage'] else 0
  838. used = 0
  839. if package_status == 1:
  840. used = flow_total_usage - activate_flow # 已用流量
  841. elif package_status == 2:
  842. index = i + 1
  843. if index < len(o_qs) and o_qs[index]['flow_total_usage']:
  844. package_used_flow = float(o_qs[i + 1]['flow_total_usage'])
  845. used = package_used_flow - activate_flow
  846. else:
  847. used = flow_total_usage - activate_flow
  848. status_dict = {0: "待使用", 1: "使用中", 2: "已失效"}
  849. status = status_dict.get(item['status'])
  850. package_list.append({
  851. 'id': item['id'],
  852. 'packageName': item['combo__combo_name'],
  853. 'status': status,
  854. 'flowTotal': flow_total,
  855. 'used': Decimal(used).quantize(Decimal('0.00')),
  856. 'activationTime': datetime.datetime.fromtimestamp(item['activation_time']).strftime(
  857. '%Y-%m-%d %H:%M:%S'),
  858. 'expireTime': datetime.datetime.fromtimestamp(item['expire_time']).strftime('%Y-%m-%d %H:%M:%S'),
  859. 'updatedTime': datetime.datetime.fromtimestamp(item['updated_time']).strftime('%Y-%m-%d %H:%M:%S')
  860. })
  861. return package_list
  862. @staticmethod
  863. def get_wx_package_list(**data):
  864. """
  865. 获取五兴套餐订购记录
  866. @param data: iccid,operator
  867. @return: 订购记录结果
  868. """
  869. try:
  870. package_list = []
  871. wx_tech = WXTechObject()
  872. result = wx_tech.get_package_order_record(**data)
  873. if not result:
  874. return package_list
  875. status_dict = {0: "待使用", 1: "使用中", 2: "已完成", 3: "已退订", 4: "已失效", 5: "已删除"}
  876. for item in result['data']:
  877. used_flow = float(item['flowTotal']) - float(item['flowRemain'])
  878. package_list.append({
  879. 'packageName': item['packageName'],
  880. 'status': status_dict.get(int(item['state'])),
  881. 'flowTotal': item['flowTotal'],
  882. 'used': Decimal(used_flow).quantize(Decimal('0.00')),
  883. 'activationTime': item['startDate'],
  884. 'expireTime': item['endDate'],
  885. 'updatedTime': ''
  886. })
  887. return package_list
  888. except Exception as e:
  889. print(repr(e))
  890. return []
  891. @staticmethod
  892. def get_device_status_by_iccid(iccid, card_type, access_number=''):
  893. try:
  894. re_data = {'iccid': iccid}
  895. if card_type == 0:
  896. status_dict = {1: '已激活', 2: '可激活', 3: '已停用', 4: '已失效', 5: '可测试', 6: '库存', 7: '已更换', 8: '已清除'}
  897. result = UnicomObjeect().query_device_status(**re_data)
  898. res_dict = UnicomObjeect().get_text_dict(result)
  899. return status_dict.get(int(res_dict['data']['status']), 'N/A')
  900. elif card_type == 1:
  901. status_dict = {1: '库存', 2: '可激活', 3: '已激活', 4: '已停用', 5: '已失效', 6: '强制停机'}
  902. data = {'iccid': iccid, 'operator': 3}
  903. wx_tech = WXTechObject()
  904. result = wx_tech.get_cards_info(**data)
  905. LOGGER.info(f'查询iccid{iccid}状态结果:{result}')
  906. return status_dict.get(int(result['data']['cardStatusCode']), 'N/A')
  907. elif card_type == 3:
  908. status_dict = {'connect': '已激活', 'disconnect': '已停用'}
  909. i = 0
  910. while i < 3:
  911. status_code = TelecomService().get_access_number_network_status(access_number)
  912. if status_code:
  913. return status_dict.get(status_code, 'N/A')
  914. i += 1
  915. access_info = AccessNumberTaskQueue.objects.filter(iccid=iccid, status=1) \
  916. .order_by('-completion_time').values('action')
  917. if not access_info.exists():
  918. return 'N/A'
  919. return '已激活' if access_info[0]['action'] == 2 else '已停用'
  920. else:
  921. return 'N/A'
  922. except Exception as e:
  923. LOGGER.error('查询ICCID卡状态异常iccid:{},:errLine:{}, errMsg:{}'
  924. .format(iccid, e.__traceback__.tb_lineno, repr(e)))
  925. return 'N/A'
  926. @classmethod
  927. def async_update_status(cls, request_dict, response):
  928. """
  929. 联通根据序列号异步修改卡状态
  930. @return: 修改结果
  931. """
  932. serial_number = request_dict.get('serialNumber', None)
  933. if not serial_number:
  934. return response.json(444)
  935. status = int(request_dict.get('status', 0))
  936. unicom_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_number, card_type__in=[0, 3])
  937. if not unicom_qs.exists():
  938. return response.json(173)
  939. unicom_service = UnicomObjeect()
  940. iccid = unicom_qs.first().iccid
  941. access_number = unicom_qs.first().access_number
  942. card_type = unicom_qs.first().card_type
  943. if status == 1: # 激活
  944. unicom_service.change_device_to_activate(iccid=iccid, card_type=card_type, access_number=access_number,
  945. reason='后台操作恢复网络')
  946. return response.json(0)
  947. elif status == 3: # 停用
  948. unicom_service.change_device_to_disable(iccid=iccid, card_type=card_type, access_number=access_number,
  949. reason='后台操作断网')
  950. return response.json(0)
  951. return response.json(902)
  952. @classmethod
  953. def get_exchange_code_page(cls, request_dict, response):
  954. """
  955. 分页获取兑换码
  956. @return: 分页数据
  957. """
  958. pageSize = request_dict.get('pageSize', None)
  959. pageNo = request_dict.get('pageNo', None)
  960. code = request_dict.get('code', None)
  961. is_down = request_dict.get('isDown', None)
  962. if not all({pageNo, pageSize}):
  963. return response.json(444)
  964. page = int(pageNo)
  965. line = int(pageSize)
  966. try:
  967. code_qs = ExchangeCode.objects.all()
  968. if code:
  969. code_qs = code_qs.filter(code__icontains=code)
  970. if is_down:
  971. code_qs = code_qs.filter(is_down=int(is_down))
  972. code_list = []
  973. total = code_qs.count()
  974. result = {'total': total, 'data': code_list}
  975. code_qs = code_qs.order_by('-created_time')[(page - 1) * line:page * line]
  976. if not code_qs.exists():
  977. return response.json(0, result)
  978. for item in code_qs:
  979. combo_name = UnicomCombo.objects.filter(id=item.package_id)[0].combo_name
  980. code_list.append({
  981. 'id': item.id,
  982. 'code': item.code,
  983. 'status': item.status,
  984. 'isDown': item.is_down,
  985. 'packageType': item.package_type,
  986. 'comboName': combo_name,
  987. 'expireTime': item.expire_time,
  988. 'createdTime': item.created_time,
  989. 'updatedTime': item.updated_time
  990. })
  991. result['data'] = code_list
  992. return response.json(0, result)
  993. except Exception as e:
  994. LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  995. return response.json(500)
  996. @classmethod
  997. def update_exchange_code(cls, request_dict, response):
  998. """
  999. 修改兑换码数据
  1000. """
  1001. code_id = request_dict.get('id', None)
  1002. is_down = request_dict.get('isDown', None)
  1003. status = request_dict.get('status', None)
  1004. expire_time = request_dict.get('expireTime', None)
  1005. if not code_id:
  1006. return response.json(444)
  1007. try:
  1008. code_qs = ExchangeCode.objects.filter(id=int(code_id))
  1009. if not code_qs.exists():
  1010. return response.json(173)
  1011. params = {}
  1012. if is_down:
  1013. params['is_down'] = int(is_down)
  1014. if status:
  1015. params['status'] = int(status)
  1016. if expire_time:
  1017. params['expire_time'] = int(expire_time)
  1018. if not params:
  1019. return response.json(0)
  1020. code_qs.update(**params)
  1021. return response.json(0)
  1022. except Exception as e:
  1023. LOGGER.info('异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  1024. return response.json(500)
  1025. @classmethod
  1026. def get_flow_combo_list(cls, request_dict, response):
  1027. """
  1028. 获取4G流量套餐列表
  1029. @return: 套餐列表
  1030. """
  1031. c_type = request_dict.get('type', None)
  1032. combo_qs = UnicomCombo.objects.filter(is_del=False)
  1033. if c_type:
  1034. combo_qs = combo_qs.filter(combo_type=int(c_type))
  1035. if not combo_qs.exists():
  1036. return response.json(173)
  1037. combo_qs = combo_qs.values('id', 'combo_name').order_by('-created_time')
  1038. flow_combo_list = list(combo_qs)
  1039. return response.json(0, flow_combo_list)
  1040. @classmethod
  1041. def serial_number_bind_package_bulk(cls, user_id, user, request, request_dict, response):
  1042. """
  1043. 上传序列号文件绑定套餐id
  1044. @param user_id: user_id
  1045. @param user: 当前操作用户
  1046. @param request: file txt
  1047. @param request_dict: package_id 4G套餐id
  1048. @param response: 响应对象
  1049. @return: 成功数以及异常序列号列表
  1050. """
  1051. redis_obj = RedisObject(5)
  1052. try:
  1053. lock = redis_obj.try_lock(UNICOM_MANAGE_LOCK, 'iccid', 15, 60)
  1054. if not lock:
  1055. return response.json(10074)
  1056. package_id = request_dict.get('packageId', None)
  1057. file = request.FILES['file']
  1058. serial_list = []
  1059. error_list = []
  1060. if not package_id:
  1061. return response.json(444)
  1062. n_time = int(time.time())
  1063. package_id = int(package_id)
  1064. sn_list = []
  1065. uc_qs = UnicomCombo.objects.filter(id=package_id)
  1066. if not uc_qs.exists():
  1067. return response.json(173)
  1068. for line in file:
  1069. serial_number = line.decode().strip()[0:9]
  1070. try:
  1071. sn_qs = SerialNumberPackage.objects.filter(serial_number=serial_number)
  1072. if sn_qs:
  1073. error_list.append({'serialNumber': serial_number, 'msg': '此序列号已绑定套餐'})
  1074. continue
  1075. if serial_number in serial_list:
  1076. error_list.append({'serialNumber': serial_number, 'msg': 'txt存在重复序列号'})
  1077. continue
  1078. data = {'status': 1, 'serial_number': serial_number, 'package_id': package_id,
  1079. 'created_time': n_time, 'updated_time': n_time, 'created_by': user, 'updated_by': user}
  1080. serial_number_p = SerialNumberPackage(**data)
  1081. serial_list.append(serial_number)
  1082. sn_list.append(serial_number_p)
  1083. except Exception as e:
  1084. error_list.append({'serialNumber': serial_number, 'msg': repr(e)})
  1085. if sn_list:
  1086. # 计算总数量和页数,仅计算一次
  1087. total_count = len(sn_list)
  1088. pages = ceil(total_count / 100)
  1089. # 遍历每一页,使用列表切片处理批次
  1090. for page in range(pages):
  1091. # 计算本次循环实际处理的结束索引,考虑最后一页可能不足100的情况
  1092. end = min((page + 1) * 100, total_count)
  1093. # 切片获取当前批次的sn_list
  1094. batch_sn_list = sn_list[page * 100:end]
  1095. # 执行批量创建
  1096. SerialNumberPackage.objects.bulk_create(batch_sn_list)
  1097. # 终身免流量时只保留一个有效套餐并自动激活
  1098. if uc_qs.first().remark == 'LIFETIME_FREE':
  1099. asy = threading.Thread(target=cls.activate_4G_lifetime_free, args=(sn_list, user_id))
  1100. asy.start()
  1101. # 释放锁
  1102. redis_obj.release_lock(UNICOM_MANAGE_LOCK, 'iccid')
  1103. return response.json(0, {'total': len(serial_list), 'errData': error_list})
  1104. except Exception as e:
  1105. LOGGER.info('批量绑定异常详情,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  1106. @classmethod
  1107. def activate_4G_lifetime_free(cls, sn_list, user_id):
  1108. """
  1109. 激活4G终身免流量
  1110. """
  1111. for item in sn_list:
  1112. try:
  1113. serial_number = item.serial_number
  1114. # 查询ICCID
  1115. iccid_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_number).values('iccid')
  1116. if not iccid_qs.exists():
  1117. LOGGER.info(f'*****激活终身免流量iccid不存在serial_number:{serial_number}')
  1118. continue
  1119. now_time = int(time.time())
  1120. # 写入套餐订购记录
  1121. experience_history_vo = {'iccid': iccid_qs[0]['iccid'], 'experience_type': 1, 'do_time': now_time}
  1122. UnicomComboExperienceHistory.objects.create(**experience_history_vo)
  1123. # 根据ICCID删除套餐记录
  1124. UnicomComboOrderInfo.objects.filter(iccid=iccid_qs[0]['iccid']).delete()
  1125. # 激活终身流量
  1126. UnicomComboView().generate_flow_package(serial_number, item.package_id, user_id)
  1127. except Exception as e:
  1128. LOGGER.info('UnicomManageControllerView.activate_4G_lifetime_free,'
  1129. 'errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  1130. continue
  1131. @classmethod
  1132. def iccid_batch_reset(cls, user, request, request_dict, response):
  1133. """
  1134. iccid批量重置流量
  1135. """
  1136. redis_obj = RedisObject(5)
  1137. lock = redis_obj.try_lock(UNICOM_MANAGE_LOCK, 'iccid', 15, 60)
  1138. if not lock:
  1139. return response.json(10074)
  1140. file = request.FILES['file']
  1141. binding_type = int(request_dict.get('type', 0))
  1142. if not file:
  1143. return response.json(444)
  1144. ip = CommonService.get_ip_address(request)
  1145. asy = threading.Thread(target=UnicomManageControllerView().async_bulk_reset_flow_package,
  1146. args=(file, user, ip, binding_type))
  1147. asy.start()
  1148. return response.json(0)
  1149. @staticmethod
  1150. def async_bulk_reset_flow_package(file, user, ip, binding_type):
  1151. err_data = []
  1152. date_str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  1153. num = 0
  1154. for line in file:
  1155. serial_number = line.decode().strip()[0:9]
  1156. try:
  1157. device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_number)
  1158. now_time = int(time.time())
  1159. if not device_info_qs.exists():
  1160. err_data.append({'serialNumber': serial_number, 'msg': 'data is null'})
  1161. continue
  1162. if device_info_qs.count() > 1:
  1163. err_data.append({'serialNumber': serial_number, 'msg': 'Bind multiple iccid'})
  1164. continue
  1165. iccid = device_info_qs.first().iccid
  1166. if binding_type == 1:
  1167. SerialNumberPackage.objects.filter(serial_number=serial_number).delete()
  1168. else:
  1169. # 根据序列号重置出厂流量套餐
  1170. serial_package_qs = SerialNumberPackage.objects.filter(~Q(status=1), serial_number=serial_number)
  1171. if serial_package_qs.exists():
  1172. serial_package_qs.update(status=1, updated_time=now_time, updated_by=user)
  1173. if device_info_qs.first().card_type == 1: # 五兴电信
  1174. data = {'iccids': iccid, 'operator': WXOperatorEnum.TELECOM.value}
  1175. wx_tech = WXTechObject()
  1176. res = wx_tech.delete_card_package(**data)
  1177. if res['code'] == '0':
  1178. UnicomComboExperienceHistory.objects.filter(iccid=iccid).delete()
  1179. num += 1
  1180. continue
  1181. err_data.append({'serialNumber': serial_number, 'msg': '电信重置流量异常:{}'.format(res['code'])})
  1182. continue
  1183. # 联通
  1184. flow_push_qs = UnicomFlowPush.objects.filter(serial_no=serial_number)
  1185. if flow_push_qs.exists(): # 删除流量预警推送
  1186. flow_push_qs.delete()
  1187. sys_msg_qs = SysMsgModel.objects.filter(uid=serial_number)
  1188. if sys_msg_qs.exists(): # 删除有关系统消息数据
  1189. sys_msg_qs.delete()
  1190. # 将4G用户信息状态改为已完成测试状态
  1191. device_info_qs.update(status=2, updated_time=now_time, user_id='')
  1192. combo_order_qs = UnicomComboOrderInfo.objects.filter(iccid=iccid)
  1193. if combo_order_qs.exists(): # 所有套餐删除
  1194. combo_order_qs.delete()
  1195. combo_experience_history_qs = UnicomComboExperienceHistory.objects.filter(iccid=iccid)
  1196. if combo_experience_history_qs.exists(): # 删除免费体验流量记录
  1197. combo_experience_history_qs.delete()
  1198. result = UnicomComboView().activate_test_flow_package(serial_number) # 订购新的100M测试流量
  1199. describe = '批量重置4G流量序列号{},iccid:{},{}'.format(serial_number, iccid, result)
  1200. num += 1
  1201. # 当前缓存是客户首次扫序列号,激活赠送测试流量生成的,重置流量所以要清除
  1202. key = f'ASJ:UNICOM:CARD:ACTIVATE:{serial_number}'
  1203. redis = RedisObject()
  1204. redis.del_data(key)
  1205. UnicomManageControllerView().create_operation_log('unicom/manage/iccidBatchReset', ip, binding_type,
  1206. describe)
  1207. continue
  1208. except Exception as e:
  1209. err_data.append({'serialNumber': serial_number, 'msg': '重置流量异常:{}'.format(repr(e))})
  1210. continue
  1211. if err_data:
  1212. describe = json.loads(json.dumps(err_data))
  1213. UnicomManageControllerView().create_operation_log('unicom/manage/iccidBatchReset', ip, binding_type,
  1214. describe)
  1215. try:
  1216. redis_obj = RedisObject(5)
  1217. lock = redis_obj.release_lock(UNICOM_MANAGE_LOCK, 'iccid')
  1218. describe = f'{date_str}批量重置流量释放锁{lock},数量:{num}'
  1219. UnicomManageControllerView().create_operation_log('unicom/manage/iccidBatchReset', ip, binding_type,
  1220. describe)
  1221. except Exception as e:
  1222. LOGGER.info('释放锁异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  1223. LOGGER.info(f'批量重置流量type={binding_type},err_data={err_data}')
  1224. @classmethod
  1225. def serial_number_package_page(cls, request_dict, response):
  1226. """
  1227. 分页查询序列号无限流量套餐
  1228. """
  1229. serial_number = request_dict.get('serialNumber', None)
  1230. pageSize = request_dict.get('pageSize', None)
  1231. pageNo = request_dict.get('pageNo', None)
  1232. package_id = request_dict.get('packageId', None)
  1233. if not all({pageNo, pageSize}):
  1234. return response.json(444)
  1235. page = int(pageNo)
  1236. line = int(pageSize)
  1237. serial_package_qs = SerialNumberPackage.objects.all()
  1238. if serial_number:
  1239. serial_package_qs = serial_package_qs.filter(serial_number=serial_number)
  1240. if package_id:
  1241. serial_package_qs = serial_package_qs.filter(package_id=int(package_id))
  1242. serial_package_qs = serial_package_qs.annotate(serialNumber=F('serial_number'), packageId=F('package_id'),
  1243. createdTime=F('created_time'), createdBy=F('created_by'),
  1244. updatedTime=F('updated_time'), updatedBy=F('updated_by')) \
  1245. .values('id', 'serialNumber', 'status', 'packageId', 'createdTime', 'createdBy', 'updatedTime', 'updatedBy')
  1246. total = serial_package_qs.count()
  1247. serial_package_qs = serial_package_qs.order_by('-created_time')[(page - 1) * line:page * line]
  1248. if not serial_package_qs.exists():
  1249. return response.json(0, [])
  1250. serial_list = []
  1251. for item in serial_package_qs:
  1252. data = item
  1253. data['packageName'] = UnicomCombo.objects.filter(id=item['packageId']).values('combo_name')[0]['combo_name']
  1254. serial_list.append(data)
  1255. return response.json(0, {'list': serial_list, 'total': total})
  1256. @classmethod
  1257. def serial_number_package_update(cls, request_dict, response, user):
  1258. """
  1259. 修改序列号绑定无限流量套餐
  1260. """
  1261. try:
  1262. s_id = request_dict.get('id', None)
  1263. package_id = request_dict.get('packageId', None)
  1264. status = request_dict.get('status', None)
  1265. if not s_id:
  1266. return response.json(444)
  1267. if not package_id and not status:
  1268. return response.json(444)
  1269. s_package_qs = SerialNumberPackage.objects.filter(id=int(s_id))
  1270. if not s_package_qs.exists():
  1271. return response.json(173)
  1272. n_time = int(time.time())
  1273. data = {'updated_time': n_time, 'updated_by': user}
  1274. if package_id:
  1275. data['package_id'] = int(package_id)
  1276. if status:
  1277. data['status'] = int(status)
  1278. s_package_qs.update(**data)
  1279. return response.json(0)
  1280. except Exception as e:
  1281. LOGGER.info('UnicomManageControllerView.serial_number_package_update,'
  1282. 'errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  1283. return response.json(500)
  1284. @classmethod
  1285. def transfer_device_package(cls, request_dict, response, user):
  1286. """
  1287. 联通4G订单套餐转移
  1288. @param request_dict: orderId(当前订单套餐id)、targetSerialNumber(目标设备序列号)
  1289. @param response: 响应结果
  1290. @param user: 操作用户
  1291. @return: 转移结果
  1292. """
  1293. try:
  1294. order_id = request_dict.get('orderId')
  1295. target_serial_number = request_dict.get('targetSerialNumber')
  1296. LOGGER.info('UnicomManageControllerView.transfer_device_package,serialNumber:{},orderId:{}'.format(
  1297. target_serial_number, order_id))
  1298. if not all([order_id, target_serial_number]):
  1299. return response.json(444)
  1300. # 查询旧设备订单套餐信息
  1301. order_query_set = Order_Model.objects.filter(orderID=order_id)
  1302. if not order_query_set.exists():
  1303. return response.json(173)
  1304. # 查询目标设备信息是否存在
  1305. u_device_query_set = UnicomDeviceInfo.objects.filter(serial_no=target_serial_number)
  1306. if not u_device_query_set.exists():
  1307. return response.json(173)
  1308. order_data = order_query_set.values().first()
  1309. old_order_id = order_data['orderID']
  1310. desc = '{} 转移后,前orderId:{}'.format(order_data['store_meal_name'], old_order_id)
  1311. order_data['desc'] = desc
  1312. now_order = CommonService.createOrderID()
  1313. uid = CommonService.get_uid_by_serial_number(target_serial_number)
  1314. order_data['orderID'] = now_order
  1315. order_data['UID'] = uid
  1316. order_data['currency'] = 'CNY'
  1317. package_id = int(order_data['unify_combo_id'])
  1318. Order_Model.objects.create(**order_data)
  1319. iccid = u_device_query_set.values('iccid').first()['iccid'] # 目标设备4G iccid
  1320. u_package_query_set = UnicomComboOrderInfo.objects.filter(order_id=old_order_id)
  1321. now_time = int(time.time())
  1322. unicom_api = UnicomObjeect()
  1323. if u_package_query_set.exists(): # 套餐记录存在则直接copy
  1324. package_info = u_package_query_set.values().first()
  1325. package_info.pop('id')
  1326. package_info['iccid'] = iccid
  1327. package_info['order_id'] = now_order
  1328. package_info['activation_time'] = now_time
  1329. package_info['updated_time'] = now_time
  1330. package_info['created_time'] = now_time
  1331. now_package_query_set = UnicomComboOrderInfo.objects.filter(iccid=iccid, status=1)
  1332. if now_package_query_set.exists():
  1333. package_info['status'] = 0
  1334. package_info['flow_total_usage'] = '0'
  1335. else:
  1336. package_info['status'] = 1
  1337. package_info['flow_total_usage'] = unicom_api.get_flow_usage_total(iccid)
  1338. UnicomComboOrderInfo.objects.create(**package_info)
  1339. # 设置旧套餐状态为2
  1340. u_package_query_set.update(status=2, updated_time=int(time.time()))
  1341. else:
  1342. UnicomComboView.create_combo_order_info(now_order, 0, iccid, package_id)
  1343. # 激活新卡
  1344. unicom_api.change_device_to_activate(iccid)
  1345. describe = f'{order_id}套餐转移成功,操作人{user}'
  1346. cls.create_operation_log('unicom/manage/transferDevicePackage', '127.0.0.1', request_dict, describe)
  1347. return response.json(0)
  1348. except Exception as e:
  1349. LOGGER.info('UnicomManageControllerView.transfer_device_package, errLine:{}, errMsg:{}'.format(
  1350. e.__traceback__.tb_lineno, repr(e)))
  1351. return response.json(500)
  1352. def get_dx_package_list(original_data):
  1353. """
  1354. 鼎芯数据处理
  1355. """
  1356. package_list = []
  1357. for package in original_data["data"]:
  1358. new_package = {
  1359. "packageName": package.get("packageName", ""),
  1360. "status": package.get("state"), # Assuming state 2 means 'In Use'
  1361. "flowTotal": package.get("flowTotal", 0),
  1362. "used": package.get("flowTotal", 0) - package.get("flowRemain", 0),
  1363. "activationTime": package.get("startDate", ""),
  1364. "expireTime": package.get("endDate", ""),
  1365. "updatedTime": "" # 没有这个数据接口
  1366. }
  1367. package_list.append(new_package)
  1368. return package_list
  1369. @classmethod
  1370. def update_expiration_date(cls, request_dict, response):
  1371. """
  1372. 更改套餐过期时间
  1373. @param request_dict: 请求参数
  1374. @request_dict id: 套餐id
  1375. @request_dict expireTime: 过期时间
  1376. @request_dict serialNumber: 序列号
  1377. @param response: 响应对象
  1378. @return:
  1379. """
  1380. id = request_dict.get("id", None)
  1381. expire_time = request_dict.get("expireTime", None)
  1382. serial_number = request_dict.get("serialNumber", None)
  1383. if not all([id, serial_number, expire_time]):
  1384. return response.json(444)
  1385. try:
  1386. ud_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_number).values('iccid', 'card_type')
  1387. package_list = []
  1388. if not ud_qs.exists():
  1389. return response.json(0, {'packageList': package_list})
  1390. card_type = ud_qs[0]['card_type']
  1391. if card_type == 0 or card_type == 3:
  1392. UnicomComboOrderInfo.objects.filter(pk=id).update(expire_time=expire_time)
  1393. return response.json(0)
  1394. else:
  1395. return response.json(177, "这个类型的卡不能更改过期时间")
  1396. except Exception as e:
  1397. LOGGER.info('UnicomManageControllerView.update_expiration_date, errLine:{}, errMsg:{}'.format(
  1398. e.__traceback__.tb_lineno, repr(e)))
  1399. return response.json(500)
  1400. @classmethod
  1401. def verify_package_export_excel(cls, request, request_dict, response):
  1402. """
  1403. 验证套餐导出excel
  1404. @param request_dict:
  1405. @param request:
  1406. @param response: 响应对象
  1407. @return:
  1408. """
  1409. try:
  1410. serial_list = []
  1411. file = request.FILES['serialFile']
  1412. opt_type = int(request_dict.get('optType', 1))
  1413. for line in file:
  1414. serial_number = line.decode().strip()[0:9]
  1415. serial_list.append(serial_number)
  1416. total_count = len(serial_list)
  1417. pages = ceil(total_count / 100)
  1418. package_list = []
  1419. # 遍历每一页,使用列表切片处理批次
  1420. for page in range(pages):
  1421. start = page * 100
  1422. end = (page + 1) * 100
  1423. serial_list_batch = serial_list[start:end]
  1424. # 获取设备信息
  1425. pck_qs = SerialNumberPackage.objects.filter(serial_number__in=serial_list_batch) \
  1426. .values('serial_number', 'package_id')
  1427. if not pck_qs.exists():
  1428. return response.json(0)
  1429. for item in pck_qs:
  1430. package_list.append(item)
  1431. if opt_type == 1:
  1432. return response.json(0, {'fileTotal': total_count, 'queryCount': len(package_list)})
  1433. combo_list = list(UnicomCombo.objects.filter(is_del=False).values('id', 'combo_name'))
  1434. # 创建一个新的excel文档
  1435. wb = openpyxl.Workbook()
  1436. # 获取默认的工作表
  1437. sheet = wb.active
  1438. sheet.title = '套餐核对'
  1439. sheet.column_dimensions['A'].width = 20
  1440. sheet.column_dimensions['B'].width = 20
  1441. sheet.column_dimensions['C'].width = 20
  1442. sheet.column_dimensions['D'].width = 20
  1443. for i, item in enumerate(package_list):
  1444. combo_name = next((combo['combo_name'] for combo in combo_list if combo['id'] == item['package_id']),
  1445. None)
  1446. u_device_qs = UnicomDeviceInfo.objects.filter(serial_no=item['serial_number']).values('card_type',
  1447. 'iccid')
  1448. sheet.cell(row=i + 1, column=1, value=item['serial_number'])
  1449. if u_device_qs.exists():
  1450. card_name = ''
  1451. if u_device_qs[0]['card_type'] == 0:
  1452. card_name = '珠海联通'
  1453. elif u_device_qs[0]['card_type'] == 1:
  1454. card_name = '五兴电信'
  1455. sheet.cell(row=i + 1, column=2, value=card_name)
  1456. sheet.cell(row=i + 1, column=3, value=u_device_qs[0]['iccid'])
  1457. sheet.cell(row=i + 1, column=4, value=combo_name)
  1458. filename = '序列号流量套餐核对-{}.xlsx'.format(len(package_list))
  1459. # 创建一个http响应
  1460. res = HttpResponse(content_type='application/vnd.ms-excel')
  1461. # 设置响应头,告诉浏览器文件要下载而不是直接打开
  1462. res['Content-Disposition'] = 'attachment; filename={}'.format(filename)
  1463. # 将excel文档保存到http响应中
  1464. wb.save(res)
  1465. return res
  1466. except Exception as e:
  1467. LOGGER.info('*****UnicomManageController.package_cdk_export_excel:errLine:{}, errMsg:{}'
  1468. .format(e.__traceback__.tb_lineno, repr(e)))
  1469. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  1470. @classmethod
  1471. def batch_order_flow_package(cls, request, request_dict, response, user_id):
  1472. serial_number_file = request.FILES.get('serialNumberFile', None)
  1473. package_id = request_dict.get('packageId', None)
  1474. if serial_number_file is None or package_id is None:
  1475. return response.json(444)
  1476. try:
  1477. # 读取序列号文件并处理
  1478. serial_numbers = []
  1479. for line in serial_number_file.readlines():
  1480. # 去除空格并截取前9个字符
  1481. cleaned_line = line.decode('utf-8').strip().replace(' ', '')[0:9]
  1482. serial_numbers.append(cleaned_line)
  1483. thread = threading.Thread(target=cls.batch_order_flow,
  1484. args=(serial_numbers, package_id, request, request_dict, user_id))
  1485. thread.start()
  1486. return response.json(0)
  1487. except Exception as e:
  1488. LOGGER.info('*****UnicomManageController.batch_order_flow_package:errLine:{}, errMsg:{}'
  1489. .format(e.__traceback__.tb_lineno, repr(e)))
  1490. return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  1491. @classmethod
  1492. def batch_order_flow(cls, serial_numbers, package_id, request, request_dict, user_id):
  1493. try:
  1494. failures = [] # 记录失败的序列号
  1495. successes = [] # 记录成功的数量
  1496. # 循环添加
  1497. for serial_number in serial_numbers:
  1498. serial_number = serial_number[:9]
  1499. result = UnicomComboView().generate_flow_package(serial_number, int(package_id), user_id)
  1500. LOGGER.info(f'{serial_number} 订购流量套餐包, createdBy:{user_id}, result:{result}')
  1501. if not result:
  1502. failures.append(serial_number)
  1503. else:
  1504. successes.append(serial_number)
  1505. # 写入操作日志
  1506. ip = CommonService.get_ip_address(request)
  1507. content = json.loads(json.dumps(request_dict))
  1508. log = {
  1509. 'ip': ip,
  1510. 'user_id': 1,
  1511. 'status': 200,
  1512. 'time': int(time.time()),
  1513. 'url': 'unicom/manage/batchOrderFlowPackage',
  1514. 'content': json.dumps(content),
  1515. 'operation': f'批量充值流量,序列号{failures}充值失败,序列号{successes}流量充值成功',
  1516. }
  1517. LogModel.objects.create(**log)
  1518. return
  1519. except Exception as e:
  1520. LOGGER.info('*****UnicomManageController.batch_order_flow:errLine:{}, errMsg:{}'
  1521. .format(e.__traceback__.tb_lineno, repr(e)))
  1522. return
  1523. @staticmethod
  1524. def batch_serial_number_combo(request, response):
  1525. file = request.FILES.get('file', None)
  1526. if file is None:
  1527. return response.json(444)
  1528. # 读取文件内容并只保留每行的前9位
  1529. serial_numbers = set()
  1530. if file.name.endswith('.txt'):
  1531. content = file.read().decode('utf-8')
  1532. for line in content.splitlines():
  1533. if line: # 确保行不为空
  1534. serial_numbers.add(line[:9]) # 只保留前9位
  1535. print(serial_numbers)
  1536. # 如果没有有效的 serial_no,直接返回
  1537. if not serial_numbers:
  1538. return response.json(0, {
  1539. 'single_iccid': [],
  1540. 'no_iccid': [],
  1541. 'multiple_iccid': []
  1542. })
  1543. # 查询数据库中每个 serial_no 绑定的 iccid 数量
  1544. results = (
  1545. UnicomDeviceInfo.objects
  1546. .filter(serial_no__in=serial_numbers) # 过滤出有效的 serial_no
  1547. .values('serial_no') # 只查询 serial_no 字段
  1548. .annotate(iccid_count=Count('iccid')) # 统计每个 serial_no 的 iccid 数量
  1549. )
  1550. # 初始化结果字典
  1551. result_dict = {
  1552. 'single_iccid': [],
  1553. 'no_iccid': [],
  1554. 'multiple_iccid': []
  1555. }
  1556. # 将查询结果转换为字典,方便快速查找
  1557. serial_iccid_count = {item['serial_no']: item['iccid_count'] for item in results}
  1558. # 分类统计
  1559. for serial_no in serial_numbers:
  1560. iccid_count = serial_iccid_count.get(serial_no, 0) # 如果没有记录,默认为0
  1561. if iccid_count == 1:
  1562. result_dict['single_iccid'].append(serial_no)
  1563. elif iccid_count >= 2:
  1564. result_dict['multiple_iccid'].append(serial_no)
  1565. else:
  1566. result_dict['no_iccid'].append(serial_no)
  1567. return response.json(0, result_dict)