示例#1
0
    def etc_toll(rsu_client: RsuSocket):
        """
        根据检测到的obu信息判断是否扣费
        @param rsu_client:
        @return:
        """

        while True:
            # socket监听,接受数据
            try:
                msg_str = rsu_client.recv_msg_max_wait_time()
            except:
                DBOPeration.update_rsu_pid_status(rsu_client, 0)
                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)
                continue
            # 有接收到数据,表明天线还在工作,更新心跳时间
            rsu_client.rsu_heartbeat_time = datetime.now()
            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 msg_str[8: 10] == 'b4':
                logger.info('检测到车辆信息')
                logger.info(msg=msg_str)
                b4_info = rsu_client.command_recv_set.parse_b4(msg_str)
                plate_no = b4_info['VehicleLicencePlateNumber']
                plate_color = b4_info['VehicleLicencePlateColor']

                # TODO 待删
                # if (plate_no == 'ffffffffffffffffffffffff' and plate_color == 'ffff') or \
                #         (plate_no == '000000000000000000000000' and plate_color == '0000'):  # 测试卡
                #     logger.info('测试卡:{}'.format(msg_str))
                #     logger.info('b4信息: {}'.format(json.dumps(b4_info)))
                #     plate_no, plate_color = 'd4c141313131313100000000', '0000'

                plate_no = CommonUtil.parse_plate_code(plate_no)
                logger.info('车牌号: {}, 车颜色:{}'.format(plate_no, plate_color))
                park_code = rsu_client.rsu_conf['park_code']  # 停车场
                if plate_no:
                    # 上传车辆信息
                    threading.Thread(target=ThirdEtcApi.upload_vehicle_plate_no,
                                     args=(park_code, plate_no, plate_color)).start()
                else:
                    logger.error('读到的车牌号为空。。。。。。。')
                # TODO 该处为测试,待删,扣所有obu的车费
                if plate_no:
                    plate_no_test = '鲁L12345'
                    query_vehicle_owe: VehicleOweOrm = DBClient.query_vehicle_owe('鲁L12345', '0000')  # 查询欠费车辆信息
                    query_vehicle_owe.plate_no = plate_no
                else:
                    query_vehicle_owe = None

                # TODO 待恢复
                # query_vehicle_owe: VehicleOweOrm = DBClient.query_vehicle_owe(plate_no, plate_color)  # 查询欠费车辆信息


                if query_vehicle_owe:  # 如果车辆欠费,开启扣费
                    logger.info('-------------车牌号:{}, 车颜色:{} 欠费,开始扣费----------'.format(plate_no, plate_color))
                    # etc_result = rsu_client.fee_deduction(body)
                    etc_result = EtcToll.toll(query_vehicle_owe, rsu_client)
                    if etc_result['flag'] is True:
                        logger.info('------------------------扣费成功--------------------------')
                        # TODO 后续成功扣费后需要删除数据库中的数据
                    else:
                        logger.error('------------------------扣费失败--------------------------')

                else:
                    logger.info('车牌号:{}, 车颜色:{} 没有欠费'.format(plate_no, plate_color))

            else:
                logger.info('lane_num:{}  接收到指令: {}'.format(rsu_client.lane_num, msg_str))
                if not msg_str:
                    time.sleep(3)
示例#2
0
    def handle_data(self, body: ETCRequestInfoOrm):
        """
        处理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['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:其它)
            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_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_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 单位分
            trans_order_no=body.trans_order_no,  # 交易订单号 "6711683258167489287"
            # TODO 待确认
            trans_type='09',  # 交易类型(06:传统;09:复合)
            vehicle_type=str(int(
                self.command_recv_set.info_b4['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