def query_etc_deduct_status(order_id: str) -> dict: """ 查询etc扣费状态 :param order_id: 订单号 """ result = { "flag": False, "errorCode": "", "errorMessage": "", "data": None } _, db_session = create_db_session(sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') etc_request_orm: ETCRequestInfoOrm = db_session.query( ETCRequestInfoOrm).filter( ETCRequestInfoOrm.trans_order_no == order_id).order_by( desc(ETCRequestInfoOrm.create_time)).first() if etc_request_orm: deduct_status = etc_request_orm.deduct_status result['data'] = deduct_status if deduct_status == EtcDeductStatus.SUCCESS: result['flag'] = True elif deduct_status == EtcDeductStatus.DEDUCTING: create_time = etc_request_orm.create_time if (datetime.now() - create_time ).seconds > 10: # 超过10s还是DEDUCTING,认为没有检测到obu result['data'] = EtcDeductStatus.NO_DETECT_OBU else: msg = '没有此订单号: {}'.format(order_id) result['data'] = msg result['errorMessage'] = msg return result
def etc_request_info_to_db(body: OBUModel): """ 请求体body入库 """ db_engine, db_session = create_db_session( sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') # etc_deduct_info_json入库 DBClient.add(db_session=db_session, orm=ETCRequestInfoOrm( id=CommonUtil.random_str(32).lower(), lane_num=body.lane_num, trans_order_no=body.trans_order_no, park_code=body.park_code, plate_no=body.plate_no, plate_color_code=body.plate_color_code, plate_type_code=body.plate_type_code, entrance_time=body.entrance_time, park_record_time=body.park_record_time, exit_time=body.exit_time, deduct_amount=body.deduct_amount, receivable_total_amount=body.receivable_total_amount, discount_amount=body.discount_amount, flag=0, )) db_session.close() db_engine.dispose()
def etc_toll(rsu_client: RsuSocket): # TimingJob.start_scheduler(rsu_client) while True: time.sleep(random.choice(range(1, 4))) now = datetime.now() # 查询天线的计费状态,charge=1开启计费,charge=0关闭计费 rsu_charge = DBRsuCharge.query_rsu_charge() # 有接收到数据,表明天线还在工作,更新心跳时间 rsu_client.rsu_heartbeat_time = datetime.now() DBOPeration.update_rsu_heartbeat(rsu_client) # 心跳更新入库 # 查询数据库订单 _, db_session = create_db_session( sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') query_item: ETCRequestInfoOrm = db_session.query( ETCRequestInfoOrm).filter( and_( ETCRequestInfoOrm.lane_num == rsu_client.lane_num, ETCRequestInfoOrm.create_time > (datetime.now() - timedelta(seconds=10)), ETCRequestInfoOrm.flag == 0)).first() # TODO 收到etc扣费请求,但是车上没有obu logger.info('当前时间:{}'.format(datetime.now())) # 找到订单开始扣费 if query_item: logger.info('开始扣费。。。。。。') logger.info('{}, {}'.format(query_item.create_time, query_item.flag)) etc_result = EtcToll.toll(query_item, rsu_client) etc_result['flag'] = False if random.randint(0, 3) == 0 else True query_item.flag = 1 if etc_result['flag']: logger.info( '...................扣费成功........................') query_item.deduct_status = EtcDeductStatus.SUCCESS else: logger.info( '...................扣费失败........................') query_item.deduct_status = EtcDeductStatus.FAIL # 数据修改好后提交 try: db_session.commit() except: db_session.rollback() logger.error(traceback.format_exc()) else: # 没有查询到订单,pass pass db_session.close()
def check_rsu_heartbeat(callback): """ 检测天线心跳状态, 心跳停止过长,重启天线 @return: """ # 定义要上传的天线心跳字典 upload_rsu_heartbeat_dict = dict(park_code=CommonConf.ETC_CONF_DICT['etc'][0]['park_code'], dev_code=CommonConf.ETC_CONF_DICT['dev_code'], # 设备编号,运行本代码的机器编号,非天线 status_code='11', # 11:正常,00:暂停收费,01:故障, 默认正常 rsu_broke_list=[], black_file_version='0', black_file_version_incr='0' ) db_engine, db_session = create_db_session(sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') rsu_info_orms = db_session.query(RSUInfoOrm).all() rsu_pids = list() now = datetime.datetime.now() for rsu_infor_orm in rsu_info_orms: rsu_pids.append(rsu_infor_orm.pid) time_diff_seconds = (now - rsu_infor_orm.heartbeat_latest).seconds # 查看天线状态,status=0需要重启etc扣费,一般socket监听超时会更新RSUInfoOrm的status为0 if (rsu_infor_orm.status == 0) or (time_diff_seconds >= 60): logger.error('park_code: {}, lane_num: {} 的最新心跳时间: {},距离当前已过:{}s'.format( rsu_infor_orm.park_code, rsu_infor_orm.lane_num, rsu_infor_orm.heartbeat_latest, time_diff_seconds)) upload_rsu_heartbeat_dict['rsu_broke_list'].append(rsu_infor_orm.sn) if upload_rsu_heartbeat_dict['rsu_broke_list']: upload_rsu_heartbeat_dict['status_code'] = '01' logger.error('天线 {} 出现故障'.format(','.join(upload_rsu_heartbeat_dict['rsu_broke_list']))) # 结束进程 logger.info('*********************kill pid: {}*************************************'.format( ','.join([str(item) for item in rsu_pids]))) CommonUtil.kill_process_by_pid(rsu_pids) logger.info("==================重启天线服务================") RsuStatus.restart_rsu_control() # rsu_script_filename = 'main2.py' # # 找出进程号 # pids = CommonUtil.query_pids(rsu_script_filename) # if pids: # os.system('kill -9 {}'.format(pids)) # 杀死进程 # logger.info('kill -9 {}'.format(pids)) # # 重启天线 # rsu_script_path = os.path.join(CommonConf.ROOT_DIR, rsu_script_filename) # os.system('nohup python3 {} &'.format(rsu_script_path)) else: logger.info('。。。。。。。。。天线心跳正常。。。。。。。。。') callback(upload_rsu_heartbeat_dict)
def update_rsu_heartbeat(rsu_client: RsuSocket): """ 更新天线心跳时间 """ db_engine, db_session = create_db_session(sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') query_item: RSUInfoOrm = db_session.query(RSUInfoOrm).filter(RSUInfoOrm.lane_num == rsu_client.lane_num).first() query_item.heartbeat_latest = rsu_client.rsu_heartbeat_time # 数据修改好后提交 try: db_session.commit() except: db_session.rollback() db_session.close()
def clear_table(): """ 清空数据表 """ _, db_session = create_db_session(sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') try: db_session.query(RSUInfoOrm).delete() db_session.commit() except: db_session.rollback() logger.error(traceback.format_exc()) finally: db_session.close()
def check_rsu_heartbeat(callback): """ 检测天线心跳状态, 心跳停止过长,重启天线 @return: """ # 定义要上传的天线心跳字典 upload_rsu_heartbeat_dict = dict( park_code=CommonConf.ETC_CONF_DICT['etc'][0]['park_code'], dev_code=CommonConf. ETC_CONF_DICT['dev_code'], # 设备编号,运行本代码的机器编号,非天线 status_code='11', # 11:正常,00:暂停收费,01:故障, 默认正常 rsu_broke_list=[], black_file_version='0', black_file_version_incr='0') db_engine, db_session = create_db_session( sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') rsu_info_orms = db_session.query(RSUInfoOrm).all() now = datetime.datetime.now() rsu_pids = list() for rsu_infor_orm in rsu_info_orms: rsu_pids.append(rsu_infor_orm.pid) time_diff_seconds = (now - rsu_infor_orm.heartbeat_latest).seconds # 如果三分钟没有心跳,需要重启etc扣费 # if time_diff_seconds >= CommonConf.ETC_HEARTBEAT_TIME_OUT or rsu_infor_orm.status == 0: if rsu_infor_orm.status == 0: logger.error( 'park_code: {}, lane_num: {} 的最新心跳时间: {},距离当前已过:{}s'. format(rsu_infor_orm.park_code, rsu_infor_orm.lane_num, rsu_infor_orm.heartbeat_latest, time_diff_seconds)) upload_rsu_heartbeat_dict['rsu_broke_list'].append( rsu_infor_orm.sn) if upload_rsu_heartbeat_dict['rsu_broke_list']: upload_rsu_heartbeat_dict['status_code'] = '01' logger.error('天线 {} 出现故障'.format(','.join( upload_rsu_heartbeat_dict['rsu_broke_list']))) # 结束进程 logger.info( '*********************kill pid: {}*************************************' .format(','.join([str(item) for item in rsu_pids]))) CommonUtil.kill_process_by_pid(rsu_pids) logger.info("==================重启天线服务================") # TODO RsuStatus.restart_rsu_control() else: logger.info('。。。。。。。。。天线心跳正常。。。。。。。。。') callback(upload_rsu_heartbeat_dict)
def rsu_info_to_db(lane_num, park_code, sn): """ 天线数据入库 """ db_engine, db_session = create_db_session(sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') DBClient.add(db_session=db_session, orm=RSUInfoOrm(id=CommonUtil.random_str(32).lower(), lane_num=lane_num, park_code=park_code, sn=sn, heartbeat_latest=datetime.now() )) db_session.close() db_engine.dispose()
def upload_vehicle_plate_no(park_code, plate_no, plate_color): """ 上传车辆信息 @param vehicle_info_json: @return: """ params = dict(park_code=park_code, plate_no=plate_no, plate_color_code=str(int(plate_color, 16)), record_time=CommonUtil.timestamp_format( int(time.time()), format='%Y%m%d%H%M%S')) vehicle_info_dict = dict(method='passThrough', params=params) vehicle_info_json = json.dumps(vehicle_info_dict, ensure_ascii=False) # # 如果上传成功upload_flag=1, 上传失败upload_flag=0, 默认上传失败 upload_flag = 0 # 业务编码报文 # 将data 值base64 后,使用SHA256WithRSA 计算签名 sign = XlapiSignature.to_sign_with_private_key( vehicle_info_json, private_key=ThirdEtcApi.PRIVATE_KEY) upload_body = dict(appid=ThirdEtcApi.APPID, data=vehicle_info_json, sign=sign.decode(encoding='utf8')) logger.info('上传车辆信息: {}'.format(vehicle_info_json)) try: res = http_session.post(ThirdEtcApi.ETC_UPLOAD_URL, data=upload_body) if res.json()['code'] == '000000': upload_flag = 1 logger.info(res.json()) except: logger.error(traceback.format_exc()) upload_fail_count = 0 if upload_flag else 1 if not upload_flag: db_engine, db_session = create_db_session( sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') # etc_deduct_info_json入库 DBClient.add(db_session=db_session, orm=VehicleInfoOrm( id=CommonUtil.random_str(32).lower(), vehicle_info=vehicle_info_json, upload_flag=upload_flag, upload_fail_count=upload_fail_count)) db_session.close() db_engine.dispose() return upload_flag, upload_fail_count
def update_rsu_pid_status(rsu_client: RsuSocket, status): """ :param status: 1 表示天线正常工作, 0表示异常 """ logger.info('lane_num: {} 出现异常'.format(rsu_client.lane_num)) db_engine, db_session = create_db_session( sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') query_item: RSUInfoOrm = db_session.query(RSUInfoOrm).filter( RSUInfoOrm.lane_num == rsu_client.lane_num).first() query_item.status = status # 数据修改好后提交 try: db_session.commit() except: db_session.rollback() db_session.close()
def query_rsu_charge(): """ 查询是否启用天线扣费状态, rsu_charge_on_off的chage=1,开启扣费模式, charge=0,关闭扣费模式 """ db_engine, db_session = create_db_session( sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') query_item: RsuChargeOnOffOrm = db_session.query( RsuChargeOnOffOrm).first() if not query_item: query_item = RsuChargeOnOffOrm( id=CommonUtil.random_str(32).lower(), charge=1, update_time=datetime.now()) DBClient.add(db_session=db_session, orm=query_item) return query_item.charge
def etc_upload_and_addto_db(handle_data_result, body: dict): """ 通知抬杆, 上传etc数据,并将etc数据存入本地 :param handle_data_result: :param body: :return: """ params = handle_data_result['data'] exit_time = handle_data_result['exit_time'] park_code = body['park_code'] etc_deduct_info_dict = {"method": "etcPayUpload", "params": params} # 业务编码报文json格式 etc_deduct_info_json = json.dumps(etc_deduct_info_dict, ensure_ascii=False) logger.info('=' * 160) logger.info(etc_deduct_info_json) # 进行到此步骤,表示etc扣费成功,如果etc_deduct_notify_url不为空,通知抬杆 if CommonConf.ETC_CONF_DICT['thirdApi']['etc_deduct_notify_url']: payTime = CommonUtil.timeformat_convert(exit_time, format1='%Y%m%d%H%M%S', format2='%Y-%m-%d %H:%M:%S') res_etc_deduct_notify_flag = ThirdEtcApi.etc_deduct_notify(park_code, body['trans_order_no'], body['discount_amount'], body['deduct_amount'], payTime) else: res_etc_deduct_notify_flag = True logger.info('=' * 160) if res_etc_deduct_notify_flag: # 接收到强哥返回值后,上传etc扣费数据 logger.info('=' * 160) upload_flag, upload_fail_count = ThirdEtcApi.etc_deduct_upload(etc_deduct_info_json) db_engine, db_session = create_db_session(sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') # etc_deduct_info_json入库 DBClient.add(db_session=db_session, orm=ETCFeeDeductInfoOrm(id=CommonUtil.random_str(32).lower(), trans_order_no=body['trans_order_no'], etc_info=etc_deduct_info_json, upload_flag=upload_flag, upload_fail_count=upload_fail_count)) db_session.close() db_engine.dispose()
def update_rsu_charge_on_off(charge=1, update_time=datetime.now()): """ 更新表rsu_charge_on_off """ _, db_session = create_db_session(sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') query_item: RsuChargeOnOffOrm = db_session.query( RsuChargeOnOffOrm).first() if query_item: query_item.charge = charge query_item.update_time = update_time # 数据修改好后提交 try: db_session.commit() except: db_session.rollback() db_session.close() else: DBClient.add(db_session=db_session, orm=RsuChargeOnOffOrm( id=CommonUtil.random_str(32).lower(), charge=charge, update_time=update_time))
def etc_request_info_to_db(body: OBUModel): """ 请求体body入库 """ if CommonConf.ETC_CONF_DICT['wugan'] == 'true': is_white = WuGan.is_white( park_code=CommonConf.ETC_CONF_DICT['etc'][0]['park_code'], plate_no=body.plate_no, plate_color_code=body.plate_color_code) is_white = 1 if is_white else 0 else: is_white = 0 db_engine, db_session = create_db_session( sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') # etc_deduct_info_json入库 DBClient.add(db_session=db_session, orm=ETCRequestInfoOrm( id=CommonUtil.random_str(32).lower(), lane_num=body.lane_num, trans_order_no=body.trans_order_no, park_code=body.park_code, plate_no=body.plate_no, plate_color_code=body.plate_color_code, plate_type_code=body.plate_type_code, entrance_time=body.entrance_time, park_record_time=body.park_record_time, exit_time=body.exit_time, deduct_amount=body.deduct_amount, receivable_total_amount=body.receivable_total_amount, discount_amount=body.discount_amount, is_white=is_white, flag=0, deduct_status=EtcDeductStatus.DEDUCTING, )) db_session.close() db_engine.dispose()
def etc_toll(rsu_client: RsuSocket): cache_time = datetime.now() while True: now = datetime.now() # 查询天线的计费状态,charge=1开启计费,charge=0关闭计费 rsu_charge = DBRsuCharge.query_rsu_charge() if rsu_charge == 0: rsu_client.rsu_heartbeat_time = now # 更新心跳 DBOPeration.update_rsu_heartbeat(rsu_client) # 心跳更新入库 time.sleep(30) continue # socket监听,接受数据 try: msg_str = rsu_client.recv_msg_max_wait_time() except: err_msg = traceback.format_exc() logger.error(err_msg) time.sleep(10) DBOPeration.update_rsu_pid_status(rsu_client, 0) rsu_client.close_socket() rsu_client.init_rsu() continue # 有接收到数据,表明天线还在工作,更新心跳时间 rsu_client.rsu_heartbeat_time = datetime.now() if CommonConf.ETC_MAKER == 'soulin': if msg_str[6:16] == 'b2ffffffff': # 心跳指令 logger.info('lane_num:{} 心跳指令:{}, 天线时间:{}, 当前时间:{}'.format(rsu_client.lane_num, msg_str, rsu_client.rsu_heartbeat_time, datetime.now())) DBOPeration.update_rsu_heartbeat(rsu_client) # 心跳更新入库 continue # # 检测到obu, 检测到obu时,会狂发b2指令,频繁的更新数据库,所以此种情况下不要更新天线心跳时间 # if msg_str[6: 8] == 'b2': # logger.info('lane_num:{} 检测到obu: {}'.format(rsu_client.lane_num, msg_str)) # else: # logger.info('lane_num:{} 接收到指令: {}'.format(rsu_client.lane_num, msg_str)) elif CommonConf.ETC_MAKER == 'jinyi': if msg_str[8: 12] == 'b200': # 心跳指令 logger.info('lane_num:{} 心跳指令:{}, 天线时间:{}, 当前时间:{}'.format(rsu_client.lane_num, msg_str, rsu_client.rsu_heartbeat_time, datetime.now())) DBOPeration.update_rsu_heartbeat(rsu_client) # 心跳更新入库 continue elif msg_str[8: 12] == 'b201': logger.error('射频初始化异常: {}'.format(msg_str)) break elif msg_str[8: 12] == 'b202': logger.error('PSAM卡初始化异常或无卡: {}'.format(msg_str)) break elif CommonConf.ETC_MAKER == 'wanji': if msg_str[16: 20] == 'b100': logger.info('lane_num:{} 心跳指令:{}, 天线时间:{}, 当前时间:{}'.format(rsu_client.lane_num, msg_str, rsu_client.rsu_heartbeat_time, datetime.now())) DBOPeration.update_rsu_heartbeat(rsu_client) # 心跳更新入库 continue elif msg_str[16: 18] == 'b1': logger.error('心跳出错:{}'.format(msg_str)) continue # 检测到obu会狂发指令,通过添加if语句可以控制每隔一秒打印日志 if (datetime.now() - cache_time).seconds >= 1: logger.info('lane_num:{} 检测到obu: {}'.format(rsu_client.lane_num, msg_str)) cache_time = datetime.now() # 查询数据库订单 _, db_session = create_db_session(sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') query_item: ETCRequestInfoOrm = db_session.query(ETCRequestInfoOrm).filter( and_(ETCRequestInfoOrm.lane_num == rsu_client.lane_num, ETCRequestInfoOrm.create_time > (datetime.now() - timedelta(seconds=10)), ETCRequestInfoOrm.flag == 0)).first() # 找到订单开始扣费 if query_item: logger.info('开始扣费。。。。。。') logger.info('{}, {}'.format(query_item.create_time, query_item.flag)) logger.info('{}'.format(query_item.park_code)) try: EtcToll.toll(query_item, rsu_client, db_session) except: logger.error(traceback.format_exc()) else: db_session.close()
db_engine, db_session = create_db_session(sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') # etc_deduct_info_json入库 DBClient.add(db_session=db_session, orm=ETCFeeDeductInfoOrm(id=CommonUtil.random_str(32).lower(), trans_order_no=body['trans_order_no'], etc_info=etc_deduct_info_json, upload_flag=upload_flag, upload_fail_count=upload_fail_count)) db_session.close() db_engine.dispose() if __name__ == '__main__': # 查询数据库订单 _, db_session1 = create_db_session(sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') query_item1: ETCRequestInfoOrm = db_session1.query(ETCRequestInfoOrm).filter( and_(ETCRequestInfoOrm.lane_num == '002', ETCRequestInfoOrm.create_time > (datetime.now() - timedelta(seconds=12000)), ETCRequestInfoOrm.flag == 0)).order_by(ETCRequestInfoOrm.create_time.desc()).first() # 找到订单开始扣费 if query_item1: logger.info('开始扣费。。。。。。') logger.info('{}, {}'.format(query_item1.create_time, query_item1.flag)) query_item1.flag = 3 # 数据修改好后提交 try: db_session1.commit() except: db_session1.rollback()
def etc_toll(rsu_client: RsuSocket): # TimingJob.start_scheduler(rsu_client) while True: now = datetime.now() # 查询天线的计费状态,charge=1开启计费,charge=0关闭计费 rsu_charge = DBRsuCharge.query_rsu_charge() if rsu_charge == 0: rsu_client.rsu_heartbeat_time = now # 更新心跳 DBOPeration.update_rsu_heartbeat(rsu_client) # 心跳更新入库 time.sleep(30) continue # if 0 <= now.hour <= 4: # 0:00-5:00和22:00-24:00关闭天线 # if rsu_client.rsu_on_or_off == StatusFlagConfig.RSU_ON: # logger.info('-------------关闭天线---------------') # rsu_client.close_socket() # rsu_client.rsu_on_or_off = StatusFlagConfig.RSU_OFF # # rsu_client.rsu_heartbeat_time = now # 更新心跳 # DBOPeration.update_rsu_heartbeat(rsu_client) # 心跳更新入库 # time.sleep(60) # logger.info('。。。当前天线处于休眠状态。。。') # continue # elif rsu_client.rsu_on_or_off == StatusFlagConfig.RSU_OFF: # 其它时间段打开天线 # logger.info('-------------打开天线---------------') # rsu_client.init_rsu() # rsu_client.rsu_on_or_off = StatusFlagConfig.RSU_ON # socket监听,接受数据 try: msg_str = rsu_client.recv_msg_max_wait_time() except: err_msg = traceback.format_exc() logger.error(err_msg) if err_msg.find('远程主机强迫关闭了一个现有的连接') != -1 or err_msg.find( '你的主机中的软件中止了一个已建立的连接') != -1: time.sleep(30) else: time.sleep(10) DBOPeration.update_rsu_pid_status(rsu_client, 0) rsu_client.close_socket() rsu_client.init_rsu() continue # 有接收到数据,表明天线还在工作,更新心跳时间 rsu_client.rsu_heartbeat_time = datetime.now() if msg_str[6:16] == 'b2ffffffff': # 心跳指令 logger.info('lane_num:{} 心跳指令:{}, 天线时间:{}, 当前时间:{}'.format( rsu_client.lane_num, msg_str, rsu_client.rsu_heartbeat_time, datetime.now())) DBOPeration.update_rsu_heartbeat(rsu_client) # 心跳更新入库 continue # 检测到obu, 检测到obu时,会狂发b2指令,频繁的更新数据库,所以此种情况下不要更新天线心跳时间 if msg_str[6:8] == 'b2': logger.info('lane_num:{} 检测到obu: {}'.format( rsu_client.lane_num, msg_str)) else: logger.info('lane_num:{} 接收到指令: {}'.format( rsu_client.lane_num, msg_str)) # 查询数据库订单 _, db_session = create_db_session( sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') query_item: ETCRequestInfoOrm = db_session.query( ETCRequestInfoOrm).filter( and_( ETCRequestInfoOrm.lane_num == rsu_client.lane_num, ETCRequestInfoOrm.create_time > (datetime.now() - timedelta(seconds=10)), ETCRequestInfoOrm.flag == 0)).first() # TODO 收到etc扣费请求,但是车上没有obu # 找到订单开始扣费 if query_item: logger.info('开始扣费。。。。。。') logger.info('{}, {}'.format(query_item.create_time, query_item.flag)) etc_result = EtcToll.toll(query_item, rsu_client) query_item.flag = 1 if etc_result['flag']: logger.info( '...................扣费成功........................') query_item.deduct_status = EtcDeductStatus.SUCCESS else: logger.info( '...................扣费失败........................') query_item.deduct_status = EtcDeductStatus.FAIL # 数据修改好后提交 try: db_session.commit() except: db_session.rollback() logger.error(traceback.format_exc()) else: # 没有查询到订单,pass pass db_session.close()
def handle_data(self, body: VehicleOweOrm): """ 处理self.command_recv_set,也就是收到的天线的信息 :param body: 接收到的数据 :return: """ # 结果存储 result = dict(flag=False, data=None, error_msg=None) # TODO 待待删打印信息 # self.command_recv_set.print_obu_info() # TODO 判断card_net和card_sn 物理卡号是否存在于黑名单中 # card_sn_in_blacklist_flag, error_msg = self.card_sn_in_blacklist() # # 物理卡号存在于黑名单中直接返回 # if card_sn_in_blacklist_flag: # result['error_msg'] = error_msg # return result # 入场时间戳格式化 yyyyMMddHHmmss entrance_time = body.entrance_time # 出场时间 exit_time = body.exit_time # 交易时间格式化(yyyyMMddHHmmss) trans_time = self.command_recv_set.info_b5['TransTime'] # 计算停车时长 park_record_time = body.park_record_time # 交易后余额 balance = self.command_recv_set.info_b5['CardRestMoney'] # 交易前余额 1999918332 单位分 trans_before_balance = self.command_recv_set.info_b4['CardRestMoney'] if CommonConf.ETC_CONF_DICT['debug'] == 'true': deduct_amount = 0.01 else: deduct_amount = body.deduct_amount card_net_no = self.command_recv_set.info_b4['CardNetNo'] # 网络编号 # ETC 卡片类型 16 储值卡 17 记账卡,转换成十进制分别对应22,23 card_type = str(int(self.command_recv_set.info_b4['CardType'], 16)) # PSAM 卡编号 10字节 try: psam_id = self.command_recv_set.info_ba['PsamSN'] except: print(self.command_recv_set.info_ba) # card_sn 物理卡号 8字节 card_sn = psam_id[4:] # TODO 待确认 logger.info('ETC 卡片类型(22:储值卡;23:记账卡): {}'.format(card_type)) params = dict( algorithm_type="1", # TODO 金额位数待确定 balance=CommonUtil.hex_to_etcfee(balance, unit='fen'), # 交易后余额 # TODO 待确认 card_net_no=card_net_no, # 网络编号 card_rnd=CommonUtil.random_str(8), # 卡内随机数 card_serial_no=self.command_recv_set. info_b5['ETCTradNo'], # 卡内交易序号 card_sn=card_sn, # self.command_recv_set.info_b4['CardID'], # "1030230218354952",ETC 支付时与卡物理号一致;非 ETC 时上传车牌号 card_type=card_type, # "23", # ETC 卡片类型(22:储值卡;23:记账卡) charging_type="0", # 扣费方式(0:天线 1:刷卡器) deduct_amount=CommonUtil.yuan_to_fen(deduct_amount), # 扣款金额 device_no=self.rsu_conf['device_no'], # 设备号 device_type=self.rsu_conf['device_type'], # 设备类型(0:天线;1:刷卡器;9:其它) # TODO 折扣金额 discount_amount=CommonUtil.yuan_to_fen(body.discount_amount), entrance_time=entrance_time, # 入场时间 yyyyMMddHHmmss exit_time=exit_time, # 交易时间(yyyyMMddHHmmss) issuer_identifier=self.command_recv_set. info_b4['IssuerIdentifier'].upper(), # 发行商代码 obu_id=self.command_recv_set.info_b4['ObuID'].upper(), # OBU 序号编码 park_code=self.rsu_conf['park_code'], # 车场编号 park_record_time=park_record_time, # 停车时长,时间精确到秒, 6小时50分钟 plate_color_code=body. plate_color, # 车牌颜色编码 0:蓝色、1:黄色、2:黑色、3:白色、4:渐变绿色、5:黄绿双拼、6:绿色、7:蓝白渐变 plate_no=body.plate_no, # 车牌号码 "皖LX4652", # TODO 车辆类型编码 0:小车 1:大车 2:超大车 plate_type_code=body.plate_type_code, psam_id=psam_id, # PSAM 卡编号 "37010101000000295460" psam_serial_no=self.command_recv_set. info_b5['PSAMTransSerial'], # PSAM 流水号 "00005BA2", # TODO 应收金额 receivable_total_amount=CommonUtil.yuan_to_fen( body.receivable_total_amount), serial_number=self.command_recv_set. info_b4['ApplySerial'], # 合同序列号"340119126C6AFEDE" tac=self.command_recv_set.info_b5['TAC'], # 交易认证码 terminal_id=self.command_recv_set. info_b5['PsamTerminalID'], # 终端编号 trans_before_balance=CommonUtil.hex_to_etcfee( trans_before_balance, unit='fen'), # 交易前余额 1999918332 单位分 # TODO 交易订单号 "6711683258167489287" trans_order_no=CommonUtil.random_str(16), # body.trans_order_no, trans_time=trans_time, # 交易时间 # TODO 待确认 trans_type='09', # 交易类型(06:传统;09:复合) vehicle_type=str( int(self.command_recv_set.info_b4['VehicleClass'], 16)) # 收费车型 ) etc_deduct_info_dict = {"method": "etcPayUpload", "params": params} etc_deduct_info_json = json.dumps(etc_deduct_info_dict, ensure_ascii=False) logger.info(etc_deduct_info_json) # TODO 上传etc扣费数据 upload_flag, upload_fail_count = ThirdEtcApi.etc_deduct_upload( etc_deduct_info_json) db_engine, db_session = create_db_session( sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') # etc_deduct_info_json入库 DBClient.add(db_session=db_session, orm=ETCFeeDeductInfoOrm( id=CommonUtil.random_str(32).lower(), etc_info=etc_deduct_info_json, upload_flag=upload_flag, upload_fail_count=upload_fail_count)) db_session.close() db_engine.dispose() # 清除收集到的b2,b3, b4, b5 self.command_recv_set.clear_info_b2345() result['flag'] = True result['data'] = params return result
def handle_data(self, body: OBUModel): """ 处理self.command_recv_set,也就是收到的天线的信息 :param body: 接收到的数据 :return: """ # 结果存储 result = dict(flag=False, data=None, error_msg=None) # TODO 待待删打印信息 # self.command_recv_set.print_obu_info() # 判断card_net和card_sn 物理卡号是否存在于黑名单中 card_sn_in_blacklist_flag, error_msg = self.card_sn_in_blacklist() # 物理卡号存在于黑名单中直接返回 if card_sn_in_blacklist_flag: result['error_msg'] = error_msg return result # 入场时间戳格式化 yyyyMMddHHmmss entrance_time = CommonUtil.timestamp_format(body.entrance_time, format='%Y%m%d%H%M%S') # 交易时间格式化(yyyyMMddHHmmss) # exit_time = CommonUtil.timestamp_format(body.exit_time, format='%Y%m%d%H%M%S') exit_time = self.command_recv_set.info_b5['TransTime'] exit_time_stamp = CommonUtil.str_to_timestamp(timestr=exit_time, format='%Y%m%d%H%M%S') # 计算停车时长 park_record_time = CommonUtil.time_difference(body.entrance_time, exit_time_stamp) # 交易后余额 balance = self.command_recv_set.info_b5['CardBalance'] # 交易前余额 1999918332 单位分 trans_before_balance = self.command_recv_set.info_b4['CardRestMoney'] if CommonConf.ETC_CONF_DICT['debug'] == 'true': deduct_amount = 0.01 else: deduct_amount = body.deduct_amount # 卡片发行信息 issuer_info = self.command_recv_set.info_b4['IssuerInfo'] # ETC 卡片类型(22:储值卡;23:记账卡), 位于issuer_info的16,17位, 16进制形式,需要转为10进制 card_type = str(int(issuer_info[16:18], 16)) # PSAM 卡编号 psam_id = issuer_info[20:40] # card_sn 物理卡号 card_sn = psam_id[4:] # TODO 待确认 logger.info('ETC 卡片类型(22:储值卡;23:记账卡): {}'.format(card_type)) params = dict( algorithm_type="1", # TODO 金额位数待确定 balance=CommonUtil.hex_to_etcfee(balance, unit='fen'), # 交易后余额 # TODO 待确认 card_net_no=issuer_info[20:24], # 网络编号 card_rnd=CommonUtil.random_str(8), # 卡内随机数 card_serial_no=self.command_recv_set. info_b5['ICCPaySerial'], # 卡内交易序号 card_sn=card_sn, # self.command_recv_set.info_b4['CardID'], # "1030230218354952",ETC 支付时与卡物理号一致;非 ETC 时上传车牌号 card_type=card_type, # "23", # ETC 卡片类型(22:储值卡;23:记账卡) charging_type="0", # 扣费方式(0:天线 1:刷卡器) deduct_amount=CommonUtil.yuan_to_fen(deduct_amount), # 扣款金额 device_no=self.rsu_conf['device_no'], # 设备号 device_type=self.rsu_conf['device_type'], # 设备类型(0:天线;1:刷卡器;9:其它) discount_amount=CommonUtil.yuan_to_fen( body.discount_amount), # 折扣金额 entrance_time=entrance_time, # 入场时间 yyyyMMddHHmmss exit_time=exit_time, # 交易时间(yyyyMMddHHmmss) issuer_identifier=self.command_recv_set. info_b2['IssuerIdentifier'].upper(), # 发行商代码 obu_id=self.command_recv_set.info_b2['OBUID'].upper(), # OBU 序号编码 park_code=self.rsu_conf['park_code'], # 车场编号 park_record_time=park_record_time, # 停车时长,时间精确到秒, 6小时50分钟 plate_color_code=body. plate_color_code, # 车牌颜色编码 0:蓝色、1:黄色、2:黑色、3:白色、4:渐变绿色、5:黄绿双拼、6:绿色、7:蓝白渐变 plate_no=body.plate_no, # 车牌号码 "皖LX4652", plate_type_code=body.plate_type_code, # 车辆类型编码 0:小车 1:大车 2:超大车 psam_id=psam_id, # PSAM 卡编号 "37010101000000295460" psam_serial_no=self.command_recv_set. info_b5['PSAMTransSerial'], # PSAM 流水号 "00005BA2", receivable_total_amount=CommonUtil.yuan_to_fen( body.receivable_total_amount), # 应收金额 serial_number=self.command_recv_set. info_b2['SerialNumber'], # 合同序列号"340119126C6AFEDE" tac=self.command_recv_set.info_b5['TAC'], # 交易认证码 terminal_id=self.command_recv_set.info_b5['PSAMNo'], # 终端编号 trans_before_balance=CommonUtil.hex_to_etcfee(trans_before_balance, unit='fen'), # 交易前余额 1999918332 单位分 trans_order_no=body.trans_order_no, # 交易订单号 "6711683258167489287" trans_type=self.command_recv_set. info_b5['TransType'], # 交易类型(06:传统;09:复合) vehicle_type=str(int( self.command_recv_set.info_b3['VehicleClass'])) # 收费车型 ) etc_deduct_info_dict = {"method": "etcPayUpload", "params": params} # 业务编码报文json格式 etc_deduct_info_json = json.dumps(etc_deduct_info_dict, ensure_ascii=False) # TODO 进行到此步骤,表示etc扣费成功,调用强哥接口 payTime = CommonUtil.timeformat_convert(exit_time, format1='%Y%m%d%H%M%S', format2='%Y-%m-%d %H:%M:%S') res_etc_deduct_notify_flag = ThirdEtcApi.etc_deduct_notify( self.rsu_conf['park_code'], body.trans_order_no, body.discount_amount, body.deduct_amount, payTime) if res_etc_deduct_notify_flag: # 接收到强哥返回值后,上传etc扣费数据 upload_flag, upload_fail_count = ThirdEtcApi.etc_deduct_upload( etc_deduct_info_json) db_engine, db_session = create_db_session( sqlite_dir=CommonConf.SQLITE_DIR, sqlite_database='etc_deduct.sqlite') # etc_deduct_info_json入库 DBClient.add(db_session=db_session, orm=ETCFeeDeductInfoOrm( id=CommonUtil.random_str(32).lower(), trans_order_no=body.trans_order_no, etc_info=etc_deduct_info_json, upload_flag=upload_flag, upload_fail_count=upload_fail_count)) db_session.close() db_engine.dispose() # 清除收集到的b2,b3, b4, b5 self.command_recv_set.clear_info_b2345() result['flag'] = True result['data'] = params return result