tasks.py 14.4 KB
import json
import time
import logging
import traceback
from datetime import datetime, timedelta
from collections import OrderedDict
from . import app
from apps.doc.models import AFCOCRResult, HILOCRResult, AFCComparisonInfo, HILComparisonInfo, Configs
from apps.doc import consts
from apps.doc.ocr.gcap import gcap
from apps.doc.exceptions import GCAPException
from common.tools.comparison import cp

compare_log = logging.getLogger('compare')
log_base = '[CA Compare]'


def get_order_dict(src_dict, order_tuple):
    order_dict = OrderedDict({})
    for field in order_tuple:
        value = src_dict.get(field)
        if value is not None:
            order_dict[field] = value
    return order_dict


def field_compare(info_dict, ocr_res_dict, ocr_field, compare_list, res_set, has_expiry_date=False):
    is_find = False
    ocr_res_str = ocr_res_dict.get(ocr_field)
    if ocr_res_str is not None:
        ocr_res_list = json.loads(ocr_res_str)
        length = len(ocr_res_list)

        # 过期期限特殊处理
        if has_expiry_date:
            expiry_dates = []
            key = compare_list[2][1]
            for ocr_res in ocr_res_list:
                if ocr_res.get(key):
                    expiry_dates.append(ocr_res.get(key))
        else:
            expiry_dates = []

        for ocr_res in ocr_res_list:
            if is_find:
                break
            for idx, compare_tuple in enumerate(compare_list):
                input_str = info_dict.get(compare_tuple[0])
                ocr_str = ocr_res.get(compare_tuple[1])
                compare_res, ocr_output = getattr(cp, compare_tuple[2])(
                    input_str, ocr_str, idx, **compare_tuple[3])
                print('type: {0}, idx: {1}, field: {2}, input: {3}, ocr: {4}, res: {5}, out: {6}'.format(ocr_field, idx, compare_tuple[0], input_str, ocr_str, compare_res, ocr_output))
                if idx == 0 and compare_res in [consts.RESULT_N, consts.RESULT_NA] and length > 1:
                    break
                is_find = True

                # 过期期限特殊处理
                if idx == 2 and has_expiry_date:
                    if compare_res == consts.RESULT_NA:
                        for expiry_date in expiry_dates:
                            expiry_date_compare_res, expiry_date_ocr_output = getattr(cp, compare_tuple[2])(
                                input_str, expiry_date, idx, **compare_tuple[3]
                            )
                            if expiry_date_compare_res == consts.RESULT_Y:
                                compare_res = consts.RESULT_Y
                                ocr_output = expiry_date_ocr_output
                                ocr_str = expiry_date
                                break

                info_dict[compare_tuple[4]] = compare_res
                if input_str is not None:
                    if ocr_str is None or ocr_output is None:
                        del info_dict[compare_tuple[0]]
                    else:
                        info_dict[compare_tuple[0]] = ocr_output
                res_set.add(compare_res)
    if not is_find:
        res_set.add(consts.RESULT_N)
        for compare_tuple in compare_list:
            info_dict[compare_tuple[4]] = consts.RESULT_NA
            if compare_tuple[0] in info_dict:
                del info_dict[compare_tuple[0]]


def usedcar_info_compare(info_dict, ocr_res_dict, ocr_field, compare_list, res_set):
    no_match_vino = []
    is_find = False
    ocr_res_str = ocr_res_dict.get(ocr_field)
    if ocr_res_str is not None:
        ocr_res_list = json.loads(ocr_res_str)

        # 车辆登记证3、4页去除
        if ocr_field == consts.MVC_OCR_FIELD:
            tmp_list = []
            for res in ocr_res_list:
                if res.get(compare_list[0][1]) is not None:
                    tmp_list.append(res)
            ocr_res_list = tmp_list

        length = len(ocr_res_list)

        for ocr_res in ocr_res_list:
            if is_find:
                break
            for idx, compare_tuple in enumerate(compare_list):
                input_str = info_dict.get(compare_tuple[0])
                ocr_str = ocr_res.get(compare_tuple[1])
                compare_res, ocr_output = getattr(cp, compare_tuple[2])(
                    input_str, ocr_str, idx, **compare_tuple[3])
                print('type: {0}, idx: {1}, field: {2}, input: {3}, ocr: {4}, res: {5}, out: {6}'.format(ocr_field, idx, compare_tuple[0], input_str, ocr_str, compare_res, ocr_output))
                if idx == 0 and compare_res in [consts.RESULT_N, consts.RESULT_NA]:
                    if ocr_str is not None:
                        no_match_vino.append(ocr_str)
                    if length > 1:
                        break
                is_find = True
                info_dict[compare_tuple[4]] = compare_res
                if input_str is not None:
                    if ocr_str is None or ocr_output is None:
                        del info_dict[compare_tuple[0]]
                    else:
                        info_dict[compare_tuple[0]] = ocr_output
                res_set.add(compare_res)
    if not is_find:
        res_set.add(consts.RESULT_N)
        for idx, compare_tuple in enumerate(compare_list):
            info_dict[compare_tuple[4]] = consts.RESULT_NA
            if idx == 0:
                continue
            if compare_tuple[0] in info_dict:
                del info_dict[compare_tuple[0]]
    return is_find, no_match_vino


@app.task
def compare(application_id, application_entity, uniq_seq, ocr_res_id):
    # POS: application_id, application_entity, uniq_seq, None
    # OCR: application_id, business_type(application_entity), None, ocr_res_id

    compare_log.info('{0} [receive task] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}]'.format(
        log_base, application_entity, application_id, uniq_seq, ocr_res_id))

    # 根据application_id查找最新的比对信息,如果没有,结束
    comparison_class = HILComparisonInfo if application_entity == consts.HIL_PREFIX else AFCComparisonInfo
    last_obj = comparison_class.objects.filter(application_id=application_id).last()
    if last_obj is None:
        compare_log.info('{0} [comparison info empty] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}]'.format(
            log_base, application_entity, application_id, uniq_seq, ocr_res_id))
        return

    # 根据application_id查找OCR累计结果指定license字段,如果没有,结束
    result_class = HILOCRResult if application_entity == consts.HIL_PREFIX else AFCOCRResult
    if ocr_res_id is None:
        ocr_res_dict = result_class.objects.filter(application_id=application_id).values(*consts.COMPARE_FIELDS).first()
    else:
        ocr_res_dict = result_class.objects.filter(id=ocr_res_id).values(*consts.COMPARE_FIELDS).first()
    if ocr_res_dict is None:
        compare_log.info('{0} [ocr info empty] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}]'.format(
            log_base, application_entity, application_id, uniq_seq, ocr_res_id
        ))
        return

    # 比对信息
    try:
        comparison_res = OrderedDict({
            'OCR_Input': {
                'uniqSeq': last_obj.uniq_seq,
                'applicationId': application_id,
                'applicationEntity': application_entity,
                'applicationVersion': last_obj.application_version,
                'vehicleStatus': last_obj.vehicle_status,
                'wholeResult': 'Y',
                'wholeResultMessage': '',
                'applicationLink': r'//china.bmw.corp/WINFS/SF-CN-data/SF3-CN-S/SF3-CN-S-1-New Business/CA/OCR II test',
            }
        })

        res_set = set()

        # is_sep = True if last_obj.customer_type == consts.CUSTOMER_TYPE[5] else False

        individual_cus_info_list = json.loads(last_obj.individual_cus_info)
        order_individual_cus_info_list = []
        for individual_cus_info in individual_cus_info_list:
            order_individual_cus_info = get_order_dict(individual_cus_info, consts.IN_ORDER)

            # 个人信息证件
            id_type = order_individual_cus_info.get('idType')
            compare_info_list = consts.ID_TYPE_COMPARE.get(id_type)
            if compare_info_list is not None:
                field_compare(order_individual_cus_info, ocr_res_dict, compare_info_list[0], compare_info_list[1], res_set, has_expiry_date=True)

            # 第二证件
            second_id_type = order_individual_cus_info.get('secondIdType')
            second_compare_info_list = consts.SECOND_ID_TYPE_COMPARE.get(second_id_type)
            if second_compare_info_list is not None:
                field_compare(order_individual_cus_info, ocr_res_dict, second_compare_info_list[0], second_compare_info_list[1], res_set)
                # 重新排列
                new_dict = OrderedDict({})
                second_id_res = order_individual_cus_info.pop(consts.SECOND_ID_RES, consts.RESULT_NA)
                for key, value in order_individual_cus_info.items():
                    new_dict[key] = value
                    if key == consts.ID_RES:
                        new_dict[consts.SECOND_ID_RES] = second_id_res
                order_individual_cus_info = new_dict

            # sep营业执照
            if order_individual_cus_info.get('customerType') == consts.CUSTOMER_TYPE[5]:
                field_compare(order_individual_cus_info, ocr_res_dict, consts.BL_OCR_FIELD, consts.TCSEP, res_set)

            order_individual_cus_info_list.append(order_individual_cus_info)

        comparison_res['OCR_Input']['individualCusInfo'] = order_individual_cus_info_list

        if last_obj.vehicle_status == consts.VEHICLE_STATUS[0] and last_obj.usedcar_info is not None:
            usedcar_info = json.loads(last_obj.usedcar_info)
            order_usedcar_info = get_order_dict(usedcar_info, consts.UC_ORDER)

            mvc_find, mvc_vinos = usedcar_info_compare(order_usedcar_info, ocr_res_dict, consts.MVC_OCR_FIELD, consts.PCUSD_MVC, res_set)

            # if order_usedcar_info[consts.PCUSD_MVC[0][0] + 'Result'] == consts.RESULT_Y:
            dl_find, dl_vinos = usedcar_info_compare(order_usedcar_info, ocr_res_dict, consts.DL_OCR_FIELD, consts.PCUSD_DL, res_set)

            if mvc_find is True and dl_find is False:
                vino = dl_vinos[0] if len(dl_vinos) > 0 else ''
                order_usedcar_info[consts.PCUSD_MVC[0][0]] = vino
            elif mvc_find is False and dl_find is True:
                vino = mvc_vinos[0] if len(mvc_vinos) > 0 else ''
                order_usedcar_info[consts.PCUSD_MVC[0][0]] = vino
                order_usedcar_info[consts.PCUSD_MVC[0][4]] = consts.RESULT_N
            elif mvc_find is False and dl_find is False:
                vino_list = []
                if len(mvc_vinos) > 0:
                    vino_list.append(mvc_vinos[0])
                if len(dl_vinos) > 0:
                    vino_list.append(dl_vinos[0])
                vino = '、'.join(vino_list)
                order_usedcar_info[consts.PCUSD_MVC[0][0]] = vino

            comparison_res['OCR_Input']['usedCarInfo'] = order_usedcar_info

        if last_obj.corporate_cus_info is not None:
            corporate_cus_info = json.loads(last_obj.corporate_cus_info)
            order_corporate_cus_info = get_order_dict(corporate_cus_info, consts.CO_ORDER)
            field_compare(order_corporate_cus_info, ocr_res_dict, consts.BL_OCR_FIELD, consts.TCCOR, res_set)

            comparison_res['OCR_Input']['corporateCusInfo'] = order_corporate_cus_info

        comparison_res['OCR_Input']['wholeResult'] = consts.RESULT_N if consts.RESULT_N in res_set or consts.RESULT_NA in res_set else consts.RESULT_Y

    except Exception as e:
        compare_log.error('{0} [compare error] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] '
                          '[error={5}]'.format(log_base, application_entity, application_id, uniq_seq, ocr_res_id,
                                               traceback.format_exc()))
    else:
        compare_log.info('{0} [compare success] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] '
                         '[compare_res={5}]'.format(log_base, application_entity, application_id, uniq_seq,
                                                    ocr_res_id, comparison_res))

        # 时间延迟
        send_time = last_obj.create_time + timedelta(seconds=15)
        while datetime.now() < send_time:
            compare_log.info('{0} [time wait 5s] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}]'.format(
                log_base, application_entity, application_id, uniq_seq, ocr_res_id))
            time.sleep(5)

        is_gcap_send = Configs.objects.filter(id=1).first()
        if is_gcap_send is not None and is_gcap_send.value == 'N':
            compare_log.info('{0} [gcap closed] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}]'.format(
                log_base, application_entity, application_id, uniq_seq, ocr_res_id))
            return

        # 将比对结果发送GCAP
        try:
            data = gcap.dict_to_xml(comparison_res)
        except Exception as e:
            compare_log.error('{0} [dict to xml failed] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] '
                              '[error={5}]'.format(log_base, application_entity, application_id, uniq_seq, ocr_res_id,
                                                   traceback.format_exc()))
        else:
            try:
                for times in range(consts.RETRY_TIMES):
                    try:
                        res_text = gcap.send(data)
                    except Exception as e:
                        gcap_exc = str(e)
                    else:
                        break
                else:
                    raise GCAPException(gcap_exc)
            except Exception as e:
                compare_log.error('{0} [gcap failed] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] '
                                  '[error={5}]'.format(log_base, application_entity, application_id, uniq_seq,
                                                       ocr_res_id, traceback.format_exc()))
            else:
                compare_log.info('{0} [gcap success] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] '
                                 '[response={5}]'.format(log_base, application_entity, application_id, uniq_seq,
                                                         ocr_res_id, res_text))
                compare_log.info('{0} [task success] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}]'.format(
                    log_base, application_entity, application_id, uniq_seq, ocr_res_id))