comparison v1
Showing
7 changed files
with
495 additions
and
55 deletions
| ... | @@ -1019,15 +1019,108 @@ BASE_XML_TEXT = """<?xml version="1.0" encoding="utf-8"?> | ... | @@ -1019,15 +1019,108 @@ BASE_XML_TEXT = """<?xml version="1.0" encoding="utf-8"?> |
| 1019 | CDATA_TEXT = """<![CDATA[<Exec xmlns="http://tempuri.org/"><strXMLParm><Request><Framework><UserName>SFCHINA\qqcout0</UserName><GUID>70d0efcb-3bc2-4018-ac4e-681c8f3131b6</GUID><DetailedTracingEnabled>False</DetailedTracingEnabled><ServiceName>AMSWebService</ServiceName><SupportsRedirection>true</SupportsRedirection><ServiceType>Service</ServiceType></Framework><Parms><InputXML type="string">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;InputXML&gt; &lt;Result&gt; {0} &lt;/Result&gt;&lt;AuthorizationData&gt;&lt;ServiceComponent&gt;OCR&lt;/ServiceComponent&gt;&lt;RoleId/&gt;&lt;CompanyId/&gt;&lt;/AuthorizationData&gt;&lt;/InputXML&gt;</InputXML></Parms></Request></strXMLParm></Exec>]]>""" | 1019 | CDATA_TEXT = """<![CDATA[<Exec xmlns="http://tempuri.org/"><strXMLParm><Request><Framework><UserName>SFCHINA\qqcout0</UserName><GUID>70d0efcb-3bc2-4018-ac4e-681c8f3131b6</GUID><DetailedTracingEnabled>False</DetailedTracingEnabled><ServiceName>AMSWebService</ServiceName><SupportsRedirection>true</SupportsRedirection><ServiceType>Service</ServiceType></Framework><Parms><InputXML type="string">&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;InputXML&gt; &lt;Result&gt; {0} &lt;/Result&gt;&lt;AuthorizationData&gt;&lt;ServiceComponent&gt;OCR&lt;/ServiceComponent&gt;&lt;RoleId/&gt;&lt;CompanyId/&gt;&lt;/AuthorizationData&gt;&lt;/InputXML&gt;</InputXML></Parms></Request></strXMLParm></Exec>]]>""" |
| 1020 | 1020 | ||
| 1021 | RESULT_MAPPING = { | 1021 | RESULT_MAPPING = { |
| 1022 | MVI_CLASSIFY: 'mvi_ocr', | 1022 | # MVI_CLASSIFY: 'mvi_ocr', |
| 1023 | IC_CLASSIFY: 'ic_ocr', | 1023 | IC_CLASSIFY: 'ic_ocr', |
| 1024 | RP_CLASSIFY: 'rp_ocr', | 1024 | RP_CLASSIFY: 'rp_ocr', |
| 1025 | BC_CLASSIFY: 'bc_ocr', | 1025 | # BC_CLASSIFY: 'bc_ocr', |
| 1026 | BL_CLASSIFY: 'bl_ocr', | 1026 | BL_CLASSIFY: 'bl_ocr', |
| 1027 | UCI_CLASSIFY: 'uci_ocr', | 1027 | # UCI_CLASSIFY: 'uci_ocr', |
| 1028 | EEP_CLASSIFY: 'eep_ocr', | 1028 | EEP_CLASSIFY: 'eep_ocr', |
| 1029 | DL_CLASSIFY: 'dl_ocr', | 1029 | DL_CLASSIFY: 'dl_ocr', |
| 1030 | PP_CLASSIFY: 'pp_ocr', | 1030 | PP_CLASSIFY: 'pp_ocr', |
| 1031 | MVC_CLASSIFY: 'mvc_ocr', | 1031 | MVC_CLASSIFY: 'mvc_ocr', |
| 1032 | VAT_CLASSIFY: 'vat_ocr', | 1032 | # VAT_CLASSIFY: 'vat_ocr', |
| 1033 | } | 1033 | } |
| 1034 | |||
| 1035 | COMPARE_FIELDS = ('ic_ocr', 'rp_ocr', 'bl_ocr', 'eep_ocr', 'dl_ocr', 'pp_ocr', 'mvc_ocr') | ||
| 1036 | |||
| 1037 | # 身份证 | ||
| 1038 | ITPRC = { | ||
| 1039 | 'customerChineseName': ('姓名', 'common_compare', {}), | ||
| 1040 | 'idNum': ('公民身份号码', 'common_compare', {}), | ||
| 1041 | # 20200410-20250410 OCR识别为长期,向GCAP发送:2099-12-31 00:00:00.0 | ||
| 1042 | 'idExpiryDate': ('有效期限', 'date_compare', {'long': True, 'ocr_split': True, 'input_replace': ''}), | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | # 护照 | ||
| 1046 | ITPSP = { | ||
| 1047 | 'customerChineseName': ('英文姓名', 'common_compare', {}), | ||
| 1048 | 'idNum': ('护照号码', 'common_compare', {}), | ||
| 1049 | 'idExpiryDate': ('有效期至', 'date_compare', {'input_replace': ''}), # 20250410 | ||
| 1050 | 'dateOfBirth': ('出生日期', 'date_compare', {'input_replace': ''}), # 20250410 | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | # 港澳台通行证 | ||
| 1054 | ITHKM_ITTID = { | ||
| 1055 | 'customerChineseName': ('中文名', 'common_compare', {}), | ||
| 1056 | 'idNum': ('证件号码', 'common_compare', {}), | ||
| 1057 | 'idExpiryDate': ('有效期限', 'date_compare', {'ocr_split': True, 'input_replace': '.'}), # 2013.10.24-2023.10.23 | ||
| 1058 | 'dateOfBirth': ('出生日期', 'date_compare', {'input_replace': '.'}), # 2023.10.23 | ||
| 1059 | # 'secondIdNum': '' | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | # 居住证 | ||
| 1063 | ITRES = { | ||
| 1064 | 'customerChineseName': ('姓名', 'common_compare', {}), | ||
| 1065 | 'idNum': ('公民身份号码', 'common_compare', {}), | ||
| 1066 | 'idExpiryDate': ('有效期限', 'date_compare', {'ocr_split': True, 'input_replace': ''}), # 20200410-20250410 | ||
| 1067 | 'secondIdNum': ('通行证号码', 'common_compare', {}) | ||
| 1068 | } | ||
| 1069 | |||
| 1070 | ID_TYPE_COMPARE = { | ||
| 1071 | 'ITPRC': {'model_field': 'ic_ocr', 'compare_field': ITPRC}, | ||
| 1072 | 'ITPSP': {'model_field': 'pp_ocr', 'compare_field': ITPSP}, | ||
| 1073 | 'ITHKM': {'model_field': 'eep_ocr', 'compare_field': ITHKM_ITTID}, | ||
| 1074 | 'ITTID': {'model_field': 'eep_ocr', 'compare_field': ITHKM_ITTID}, | ||
| 1075 | 'ITRES': {'model_field': 'rp_ocr', 'compare_field': ITRES}, | ||
| 1076 | } | ||
| 1077 | |||
| 1078 | # 1. 分别对比 POS车架号 vs 车辆登记正,POS车架号 vs 行驶证 | ||
| 1079 | # a)两种比对 均一致:Y | ||
| 1080 | # b)其中一个 不一致:N,向GCAP发送:不一致的OCR识别结果 | ||
| 1081 | # c)两中比对 均不一致:N,向GCAP发送:车辆登记证 & 行驶证识别结果 | ||
| 1082 | # 车辆登记证 | ||
| 1083 | PCUSD_MVC = { | ||
| 1084 | 'vinNo': ('9.车辆识别代号/车架号', 'common_compare', {}), | ||
| 1085 | 'manufactureDate': ('32.车辆出厂日期', 'common_compare', {}), | ||
| 1086 | 'firstRegistrationDate': ('3.登记日期', 'common_compare', {}), | ||
| 1087 | } | ||
| 1088 | |||
| 1089 | # 行驶证 | ||
| 1090 | PCUSD_DL = { | ||
| 1091 | 'vinNo': ('车辆识别代码', 'common_compare', {}), | ||
| 1092 | # 'manufactureDate': '', | ||
| 1093 | # 'firstRegistrationDate': '', | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | # 营业执照 | ||
| 1097 | TCCOR = { | ||
| 1098 | 'customerChineseName': ('企业名称', 'common_compare', {}), | ||
| 1099 | 'legalRepName': ('经营者姓名', 'common_compare', {}), | ||
| 1100 | 'idNum': ('注册号', 'common_compare', {}), | ||
| 1101 | 'businessLicenseNo': ('注册号', 'common_compare', {}), | ||
| 1102 | 'taxRegistrationCode': ('注册号', 'common_compare', {}), | ||
| 1103 | 'incorporationDate': ('成立日期', 'date_compare', {'ocr_replace': True}), # 2017年07月11日 | ||
| 1104 | # 2017年07月11日至长期 1. OCR识别为长期,向GCAP发送:2099-12-31 00:00:00.0 | ||
| 1105 | 'businessLicenseDueDate': ('营业期限', 'date_compare', {'long': True, 'ocr_replace': True}), | ||
| 1106 | 'capitalRegAmount': ('注册资本', 'rmb_compare', {}), # 壹拾万元整 将OCR识别结果(人民币大写)转化为数字 | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | TCSEP = { | ||
| 1110 | 'companyName': ('企业名称', 'common_compare', {}), | ||
| 1111 | 'registeredCapital': ('注册资本', 'rmb_compare', {}), # 壹拾万元整 将OCR识别结果(人民币大写)转化为数字 | ||
| 1112 | 'selfEmployedSubType': ('企业类型', 'type_compare', {}), # 有限责任公司 | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | # 1. POS数据OCR识别结果对应关系如下: | ||
| 1116 | # a)Individual Businessman CSIBM => 个体工商户 | ||
| 1117 | # b)Small and Micro Enterprise Owners CSSME => 个人独资企业、有限合伙企业、股份合作制、有限责任公司(***)【只需比对“有限责任公司”即可】 | ||
| 1118 | # c)Others CSOTH => 识别结果不一致时,向GCAP发送 OCR的识别结果 | ||
| 1119 | |||
| 1120 | RESULT_Y = 'Y' | ||
| 1121 | RESULT_N = 'N' | ||
| 1122 | RESULT_NA = 'NA' | ||
| 1123 | |||
| 1124 | |||
| 1125 | |||
| 1126 | ... | ... |
| ... | @@ -888,53 +888,54 @@ class Command(BaseCommand, LoggerMixin): | ... | @@ -888,53 +888,54 @@ class Command(BaseCommand, LoggerMixin): |
| 888 | os.remove(excel_path) | 888 | os.remove(excel_path) |
| 889 | finally: | 889 | finally: |
| 890 | # TODO 识别结果存一张表,方便跑报表 | 890 | # TODO 识别结果存一张表,方便跑报表 |
| 891 | try: | 891 | if doc.document_scheme == consts.DOC_SCHEME_LIST[0]: |
| 892 | # 更新OCR累计识别结果表 | ||
| 893 | result_class = HILOCRResult if business_type == consts.HIL_PREFIX else AFCOCRResult | ||
| 894 | res_obj = result_class.objects.filter(application_id=doc.application_id).first() | ||
| 895 | if res_obj is None: | ||
| 896 | res_obj = result_class() | ||
| 897 | res_obj.application_id = doc.application_id | ||
| 898 | for classify, field in consts.RESULT_MAPPING.items(): | ||
| 899 | license_list = license_summary.get(classify) | ||
| 900 | if not license_list: | ||
| 901 | continue | ||
| 902 | if classify == consts.IC_CLASSIFY and ic_merge: | ||
| 903 | license_list[0].update(license_list[1]) | ||
| 904 | license_list.pop(1) | ||
| 905 | elif classify == consts.RP_CLASSIFY and rp_merge: | ||
| 906 | license_list[0].update(license_list[1]) | ||
| 907 | license_list.pop(1) | ||
| 908 | if not hasattr(res_obj, field): | ||
| 909 | continue | ||
| 910 | old_res_str = getattr(res_obj, field) | ||
| 911 | if old_res_str is None: | ||
| 912 | last_res_str = json.dumps(license_list) | ||
| 913 | else: | ||
| 914 | old_res_list = json.loads(old_res_str) | ||
| 915 | old_res_list.extend(license_list) | ||
| 916 | last_res_str = json.dumps(old_res_list) | ||
| 917 | setattr(res_obj, field, last_res_str) | ||
| 918 | res_obj.save() | ||
| 919 | except Exception as e: | ||
| 920 | self.online_log.error( | ||
| 921 | '{0} [process error (ocr result save)] [task={1}] [error={2}]'.format( | ||
| 922 | self.log_base, task_str, traceback.format_exc())) | ||
| 923 | else: | ||
| 924 | self.online_log.info('{0} [ocr result save success] [task={1}] [res_id={2}]'.format( | ||
| 925 | self.log_base, task_str, res_obj.id)) | ||
| 926 | # 触发比对 | ||
| 927 | try: | 892 | try: |
| 928 | pass | 893 | # 更新OCR累计识别结果表 |
| 929 | # compare.apply_async((doc.application_id, business_type, None, res_obj.id), | 894 | result_class = HILOCRResult if business_type == consts.HIL_PREFIX else AFCOCRResult |
| 930 | # queue='queue_compare') | 895 | res_obj = result_class.objects.filter(application_id=doc.application_id).first() |
| 896 | if res_obj is None: | ||
| 897 | res_obj = result_class() | ||
| 898 | res_obj.application_id = doc.application_id | ||
| 899 | for classify, field in consts.RESULT_MAPPING.items(): | ||
| 900 | license_list = license_summary.get(classify) | ||
| 901 | if not license_list: | ||
| 902 | continue | ||
| 903 | if classify == consts.IC_CLASSIFY and ic_merge: | ||
| 904 | license_list[0].update(license_list[1]) | ||
| 905 | license_list.pop(1) | ||
| 906 | elif classify == consts.RP_CLASSIFY and rp_merge: | ||
| 907 | license_list[0].update(license_list[1]) | ||
| 908 | license_list.pop(1) | ||
| 909 | if not hasattr(res_obj, field): | ||
| 910 | continue | ||
| 911 | old_res_str = getattr(res_obj, field) | ||
| 912 | if old_res_str is None: | ||
| 913 | last_res_str = json.dumps(license_list) | ||
| 914 | else: | ||
| 915 | old_res_list = json.loads(old_res_str) | ||
| 916 | old_res_list.extend(license_list) | ||
| 917 | last_res_str = json.dumps(old_res_list) | ||
| 918 | setattr(res_obj, field, last_res_str) | ||
| 919 | res_obj.save() | ||
| 931 | except Exception as e: | 920 | except Exception as e: |
| 932 | self.online_log.error( | 921 | self.online_log.error( |
| 933 | '{0} [process error (comparison info send)] [task={1}] [error={2}]'.format( | 922 | '{0} [process error (ocr result save)] [task={1}] [error={2}]'.format( |
| 934 | self.log_base, task_str, traceback.format_exc())) | 923 | self.log_base, task_str, traceback.format_exc())) |
| 935 | else: | 924 | else: |
| 936 | self.online_log.info('{0} [comparison info send success] [task={1}] ' | 925 | self.online_log.info('{0} [ocr result save success] [task={1}] [res_id={2}]'.format( |
| 937 | '[res_id={2}]'.format(self.log_base, task_str, res_obj.id)) | 926 | self.log_base, task_str, res_obj.id)) |
| 927 | # 触发比对 | ||
| 928 | try: | ||
| 929 | pass | ||
| 930 | # compare.apply_async((doc.application_id, business_type, None, res_obj.id), | ||
| 931 | # queue='queue_compare') | ||
| 932 | except Exception as e: | ||
| 933 | self.online_log.error( | ||
| 934 | '{0} [process error (comparison info send)] [task={1}] [error={2}]'.format( | ||
| 935 | self.log_base, task_str, traceback.format_exc())) | ||
| 936 | else: | ||
| 937 | self.online_log.info('{0} [comparison info send success] [task={1}] ' | ||
| 938 | '[res_id={2}]'.format(self.log_base, task_str, res_obj.id)) | ||
| 938 | finally: | 939 | finally: |
| 939 | try: | 940 | try: |
| 940 | img_save_path = os.path.join(doc_data_path, 'img') | 941 | img_save_path = os.path.join(doc_data_path, 'img') | ... | ... |
| ... | @@ -3,6 +3,7 @@ from requests.auth import HTTPBasicAuth | ... | @@ -3,6 +3,7 @@ from requests.auth import HTTPBasicAuth |
| 3 | from settings import conf | 3 | from settings import conf |
| 4 | from common.tools.dict_to_xml import dicttoxml, escape_xml | 4 | from common.tools.dict_to_xml import dicttoxml, escape_xml |
| 5 | from apps.doc import consts | 5 | from apps.doc import consts |
| 6 | from apps.doc.exceptions import GCAPException | ||
| 6 | 7 | ||
| 7 | 8 | ||
| 8 | class GCAP: | 9 | class GCAP: |
| ... | @@ -19,11 +20,10 @@ class GCAP: | ... | @@ -19,11 +20,10 @@ class GCAP: |
| 19 | comparison_xml = dicttoxml(comparison_res, root=False, attr_type=False) | 20 | comparison_xml = dicttoxml(comparison_res, root=False, attr_type=False) |
| 20 | return consts.BASE_XML_TEXT.format(consts.CDATA_TEXT.format(escape_xml(comparison_xml))).encode('utf-8') | 21 | return consts.BASE_XML_TEXT.format(consts.CDATA_TEXT.format(escape_xml(comparison_xml))).encode('utf-8') |
| 21 | 22 | ||
| 22 | def send(self, comparison_res): | 23 | def send(self, data): |
| 23 | data = self.dict_to_xml(comparison_res) | ||
| 24 | response = requests.post(self.url, headers=self.headers, data=data, verify=False, auth=self.auth) | 24 | response = requests.post(self.url, headers=self.headers, data=data, verify=False, auth=self.auth) |
| 25 | return response | 25 | if response.status_code != 200: |
| 26 | 26 | raise GCAPException('GCAP response with code: {0}'.format(response.status_code)) | |
| 27 | |||
| 28 | 27 | ||
| 29 | 28 | ||
| 29 | gcap = GCAP() | ... | ... |
| 1 | import json | ||
| 1 | import logging | 2 | import logging |
| 3 | import traceback | ||
| 2 | from . import app | 4 | from . import app |
| 3 | from apps.doc.models import AFCDoc | 5 | from apps.doc.models import AFCOCRResult, HILOCRResult, AFCComparisonInfo, HILComparisonInfo |
| 6 | from apps.doc import consts | ||
| 7 | from apps.doc.ocr.gcap import gcap | ||
| 8 | from apps.doc.exceptions import GCAPException | ||
| 9 | from common.tools.comparison import cp | ||
| 4 | 10 | ||
| 5 | compare_log = logging.getLogger('compare') | 11 | compare_log = logging.getLogger('compare') |
| 12 | log_base = '[CA Compare]' | ||
| 6 | 13 | ||
| 7 | 14 | ||
| 8 | @app.task | 15 | @app.task |
| ... | @@ -10,8 +17,190 @@ def compare(application_id, application_entity, uniq_seq, ocr_res_id): | ... | @@ -10,8 +17,190 @@ def compare(application_id, application_entity, uniq_seq, ocr_res_id): |
| 10 | # POS: application_id, application_entity, uniq_seq, None | 17 | # POS: application_id, application_entity, uniq_seq, None |
| 11 | # OCR: application_id, business_type(application_entity), None, ocr_res_id | 18 | # OCR: application_id, business_type(application_entity), None, ocr_res_id |
| 12 | 19 | ||
| 20 | compare_log.info('{0} [receive task] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}]'.format( | ||
| 21 | log_base, application_entity, application_id, uniq_seq, ocr_res_id)) | ||
| 22 | |||
| 13 | # 根据application_id查找最新的比对信息,如果没有,结束 | 23 | # 根据application_id查找最新的比对信息,如果没有,结束 |
| 14 | # 分析比对信息,需要比对的license | 24 | comparison_class = HILComparisonInfo if application_entity == consts.HIL_PREFIX else AFCComparisonInfo |
| 25 | last_obj = comparison_class.objects.filter(application_id=application_id).last() | ||
| 26 | if last_obj is None: | ||
| 27 | compare_log.info('{0} [comparison info empty] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}]'.format( | ||
| 28 | log_base, application_entity, application_id, uniq_seq, ocr_res_id | ||
| 29 | )) | ||
| 30 | return | ||
| 31 | |||
| 15 | # 根据application_id查找OCR累计结果指定license字段,如果没有,结束 | 32 | # 根据application_id查找OCR累计结果指定license字段,如果没有,结束 |
| 16 | # 比对信息,将比对结果发送GCAP | 33 | result_class = HILOCRResult if application_entity == consts.HIL_PREFIX else AFCOCRResult |
| 17 | pass | 34 | if ocr_res_id is None: |
| 35 | ocr_res_dict = result_class.objects.filter(application_id=application_id).values(*consts.COMPARE_FIELDS).first() | ||
| 36 | else: | ||
| 37 | ocr_res_dict = result_class.objects.filter(id=ocr_res_id).values(*consts.COMPARE_FIELDS).first() | ||
| 38 | if ocr_res_dict is None: | ||
| 39 | compare_log.info('{0} [ocr info empty] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}]'.format( | ||
| 40 | log_base, application_entity, application_id, uniq_seq, ocr_res_id | ||
| 41 | )) | ||
| 42 | return | ||
| 43 | |||
| 44 | # 比对信息 | ||
| 45 | comparison_res = { | ||
| 46 | 'OCR_Input': { | ||
| 47 | 'uniqSeq': last_obj.uniq_seq, | ||
| 48 | 'applicationId': application_id, | ||
| 49 | 'applicationEntity': application_entity, | ||
| 50 | 'applicationVersion': last_obj.application_version, | ||
| 51 | 'vehicleStatus': last_obj.vehicle_status, | ||
| 52 | # 'wholeResult': 'Y', | ||
| 53 | 'wholeResultMessage': '', | ||
| 54 | 'applicationLink': '', | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | res_set = set() | ||
| 59 | |||
| 60 | is_sep = True if last_obj.customer_type == consts.CUSTOMER_TYPE[5] else False | ||
| 61 | |||
| 62 | individual_cus_info_list = json.loads(last_obj.individual_cus_info) | ||
| 63 | for individual_cus_info in individual_cus_info_list: | ||
| 64 | individual_cus_info['customerType'] = last_obj.customer_type | ||
| 65 | # sep营业执照 | ||
| 66 | if is_sep and individual_cus_info.get('companyName') is not None: | ||
| 67 | sep_is_find = False | ||
| 68 | sep_ocr_res_str = ocr_res_dict.get('bl_ocr') | ||
| 69 | if sep_ocr_res_str is not None: | ||
| 70 | sep_ocr_list = json.loads(sep_ocr_res_str) | ||
| 71 | for sep_ocr in sep_ocr_list: | ||
| 72 | company_name = sep_ocr.get(consts.TCSEP.get('companyName')[0]) | ||
| 73 | if company_name is None or company_name != individual_cus_info.get('companyName'): | ||
| 74 | continue | ||
| 75 | sep_is_find = True | ||
| 76 | for sep_field, sep_tuple in consts.TCSEP.items(): | ||
| 77 | sep_res = getattr(cp, sep_tuple[1])( | ||
| 78 | individual_cus_info.get(sep_field), sep_ocr.get(sep_tuple[0]), sep_tuple[2]) | ||
| 79 | individual_cus_info[sep_field + 'Result'] = sep_res | ||
| 80 | res_set.add(sep_res) | ||
| 81 | break | ||
| 82 | if not sep_is_find: | ||
| 83 | res_set.add(consts.RESULT_N) | ||
| 84 | for field in consts.TCSEP.keys(): | ||
| 85 | individual_cus_info[field + 'Result'] = consts.RESULT_N | ||
| 86 | |||
| 87 | # 个人信息证件 | ||
| 88 | id_type = individual_cus_info.get('idType') | ||
| 89 | compare_target = consts.ID_TYPE_COMPARE.get(id_type) | ||
| 90 | if compare_target is None: | ||
| 91 | continue | ||
| 92 | is_find = False | ||
| 93 | ocr_res_str = ocr_res_dict.get(compare_target.get('model_field')) | ||
| 94 | if ocr_res_str is not None: | ||
| 95 | ocr_res_list = json.loads(ocr_res_str) | ||
| 96 | compare_target_dict = compare_target.get('compare_field') | ||
| 97 | for ocr_res in ocr_res_list: | ||
| 98 | base_name = ocr_res.get(compare_target_dict.get('customerChineseName')[0]) | ||
| 99 | if base_name is None or base_name != individual_cus_info.get('customerChineseName'): # TODO 特殊姓名比对 | ||
| 100 | continue | ||
| 101 | is_find = True | ||
| 102 | for compare_field, compare_tuple in compare_target.get('compare_field').items(): | ||
| 103 | compare_res = getattr(cp, compare_tuple[1])( | ||
| 104 | individual_cus_info.get(compare_field), ocr_res.get(compare_tuple[0]), compare_tuple[2]) | ||
| 105 | individual_cus_info[compare_field + 'Result'] = compare_res | ||
| 106 | res_set.add(compare_res) | ||
| 107 | break | ||
| 108 | if not is_find: | ||
| 109 | res_set.add(consts.RESULT_N) | ||
| 110 | for field in compare_target.get('compare_field').keys(): | ||
| 111 | individual_cus_info[field + 'Result'] = consts.RESULT_N | ||
| 112 | |||
| 113 | comparison_res['individualCusInfo'] = individual_cus_info_list | ||
| 114 | |||
| 115 | if last_obj.corporate_cus_info is not None: | ||
| 116 | corporate_cus_info = json.loads(last_obj.corporate_cus_info) | ||
| 117 | corporate_cus_info['customerType'] = last_obj.customer_type | ||
| 118 | |||
| 119 | is_bl_find = False | ||
| 120 | bl_ocr_res_str = ocr_res_dict.get('bl_ocr') | ||
| 121 | if bl_ocr_res_str is not None: | ||
| 122 | bl_ocr_list = json.loads(bl_ocr_res_str) | ||
| 123 | for bl_ocr in bl_ocr_list: | ||
| 124 | company_name = bl_ocr.get(consts.TCCOR.get('customerChineseName')[0]) | ||
| 125 | if company_name is None or company_name != corporate_cus_info.get('customerChineseName'): | ||
| 126 | continue | ||
| 127 | is_bl_find = True | ||
| 128 | for bl_field, bl_tuple in consts.TCCOR.items(): | ||
| 129 | bl_res = getattr(cp, bl_tuple[1])( | ||
| 130 | corporate_cus_info.get(bl_field), bl_ocr.get(bl_tuple[0]), bl_tuple[2]) | ||
| 131 | corporate_cus_info[bl_field + 'Result'] = bl_res | ||
| 132 | res_set.add(bl_res) | ||
| 133 | break | ||
| 134 | if not is_bl_find: | ||
| 135 | res_set.add(consts.RESULT_N) | ||
| 136 | for field in consts.TCCOR.keys(): | ||
| 137 | corporate_cus_info[field + 'Result'] = consts.RESULT_N | ||
| 138 | |||
| 139 | comparison_res['corporateCusInfo'] = corporate_cus_info | ||
| 140 | |||
| 141 | if last_obj.vehicle_status == consts.VEHICLE_STATUS[0] and last_obj.usedcar_info is not None: | ||
| 142 | usedcar_info = json.loads(last_obj.usedcar_info) | ||
| 143 | |||
| 144 | is_usedcar_find = False | ||
| 145 | mvc_ocr_res_str = ocr_res_dict.get('mvc_ocr') | ||
| 146 | if mvc_ocr_res_str is not None: | ||
| 147 | mvc_ocr_list = json.loads(mvc_ocr_res_str) | ||
| 148 | for mvc_ocr in mvc_ocr_list: | ||
| 149 | vin_no = mvc_ocr.get(consts.PCUSD_MVC.get('vinNo')[0]) | ||
| 150 | if vin_no is None or vin_no != usedcar_info.get('vinNo'): | ||
| 151 | continue | ||
| 152 | is_usedcar_find = True | ||
| 153 | for mvc_field, mvc_tuple in consts.PCUSD_MVC.items(): | ||
| 154 | mvc_res = getattr(cp, mvc_tuple[1])( | ||
| 155 | usedcar_info.get(mvc_field), mvc_ocr.get(mvc_tuple[0]), mvc_tuple[2]) | ||
| 156 | usedcar_info[mvc_field + 'Result'] = mvc_res | ||
| 157 | res_set.add(mvc_res) | ||
| 158 | |||
| 159 | dl_find = False | ||
| 160 | dl_ocr_res_str = ocr_res_dict.get('dl_ocr') | ||
| 161 | if dl_ocr_res_str is not None: | ||
| 162 | dl_ocr_list = json.loads(dl_ocr_res_str) | ||
| 163 | for dl_ocr in dl_ocr_list: | ||
| 164 | dl_vin_no = dl_ocr.get(consts.PCUSD_DL.get('vinNo')[0]) | ||
| 165 | if dl_vin_no is None or dl_vin_no != usedcar_info.get('vinNo'): | ||
| 166 | continue | ||
| 167 | dl_find = True | ||
| 168 | break | ||
| 169 | if not dl_find: | ||
| 170 | res_set.add(consts.RESULT_N) | ||
| 171 | usedcar_info['vinNo' + 'Result'] = consts.RESULT_N | ||
| 172 | break | ||
| 173 | if not is_usedcar_find: | ||
| 174 | res_set.add(consts.RESULT_N) | ||
| 175 | for field in consts.PCUSD_MVC.keys(): | ||
| 176 | usedcar_info[field + 'Result'] = consts.RESULT_N | ||
| 177 | comparison_res['usedCarInfo'] = usedcar_info | ||
| 178 | |||
| 179 | comparison_res['wholeResult'] = consts.RESULT_N if consts.RESULT_N in res_set else consts.RESULT_Y | ||
| 180 | print(comparison_res) | ||
| 181 | |||
| 182 | # 将比对结果发送GCAP | ||
| 183 | # try: | ||
| 184 | # data = gcap.dict_to_xml(comparison_res) | ||
| 185 | # except Exception as e: | ||
| 186 | # compare_log.error('{0} [dict to xml failed] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] ' | ||
| 187 | # '[error={5}]'.format(log_base, application_entity, application_id, uniq_seq, ocr_res_id, | ||
| 188 | # traceback.format_exc())) | ||
| 189 | # else: | ||
| 190 | # try: | ||
| 191 | # for times in range(consts.RETRY_TIMES): | ||
| 192 | # try: | ||
| 193 | # gcap.send(data) | ||
| 194 | # except Exception as e: | ||
| 195 | # gcap_exc = str(e) | ||
| 196 | # else: | ||
| 197 | # break | ||
| 198 | # else: | ||
| 199 | # raise GCAPException(gcap_exc) | ||
| 200 | # except Exception as e: | ||
| 201 | # compare_log.error('{0} [gcap failed] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] ' | ||
| 202 | # '[error={5}]'.format(log_base, application_entity, application_id, uniq_seq, | ||
| 203 | # ocr_res_id, traceback.format_exc())) | ||
| 204 | # else: | ||
| 205 | # compare_log.info('{0} [task success] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}]'.format( | ||
| 206 | # log_base, application_entity, application_id, uniq_seq, ocr_res_id)) | ... | ... |
src/common/tools/comparison.py
0 → 100644
| 1 | import re | ||
| 2 | from .rmb_upper import to_rmb_upper | ||
| 3 | |||
| 4 | |||
| 5 | class Comparison: | ||
| 6 | |||
| 7 | def __init__(self): | ||
| 8 | self.CSIBM = 'CSIBM' | ||
| 9 | self.CSSME = 'CSSME' | ||
| 10 | self.CSOTH = 'CSOTH' | ||
| 11 | |||
| 12 | self.TYPE_MAPPING = ( | ||
| 13 | (r'个体工商户', self.CSIBM), | ||
| 14 | (r'有限责任公司', self.CSSME), | ||
| 15 | (r'个人独资企业', self.CSSME), | ||
| 16 | (r'有限合伙企业', self.CSSME), | ||
| 17 | (r'股份合作制', self.CSSME), | ||
| 18 | ) | ||
| 19 | |||
| 20 | self.RESULT_Y = 'Y' | ||
| 21 | self.RESULT_N = 'N' | ||
| 22 | self.RESULT_NA = 'NA' # TODO NA情况 | ||
| 23 | |||
| 24 | def build_res(self, result): | ||
| 25 | if result: | ||
| 26 | return self.RESULT_Y | ||
| 27 | else: | ||
| 28 | return self.RESULT_N | ||
| 29 | |||
| 30 | def common_compare(self, input_str, ocr_str, **kwargs): | ||
| 31 | return self.build_res(input_str == ocr_str) | ||
| 32 | |||
| 33 | def date_compare(self, input_str, ocr_str, **kwargs): | ||
| 34 | if kwargs.get('long', False) and '长期' in ocr_str: | ||
| 35 | return '2099-12-31' | ||
| 36 | if kwargs.get('ocr_split', False): | ||
| 37 | ocr_str = ocr_str.split('-')[-1] | ||
| 38 | if kwargs.get('ocr_replace', False): | ||
| 39 | ocr_str = ocr_str.replace('年', '-').replace('月', '-').replace('日', '') | ||
| 40 | if kwargs.get('input_replace') is not None: | ||
| 41 | input_str = input_str.replace('-', kwargs.get('replace')) | ||
| 42 | return self.build_res(input_str == ocr_str) | ||
| 43 | |||
| 44 | def rmb_compare(self, input_str, ocr_str, **kwargs): | ||
| 45 | input_rmb_upper = to_rmb_upper(float(input_str)) | ||
| 46 | return self.build_res(input_rmb_upper == ocr_str) | ||
| 47 | |||
| 48 | def type_compare(self, input_str, ocr_str, **kwargs): | ||
| 49 | for map_tuple in self.TYPE_MAPPING: | ||
| 50 | if re.search(map_tuple[0], ocr_str) is not None: | ||
| 51 | compare_str = map_tuple[1] | ||
| 52 | break | ||
| 53 | else: | ||
| 54 | compare_str = self.CSOTH | ||
| 55 | |||
| 56 | return self.build_res(input_str == compare_str) | ||
| 57 | |||
| 58 | |||
| 59 | cp = Comparison() | ||
| 60 | |||
| 61 |
src/common/tools/rmb_upper.py
0 → 100644
| 1 | from io import StringIO | ||
| 2 | import math | ||
| 3 | |||
| 4 | _RMB_DIGITS = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖' ] | ||
| 5 | _SECTION_CHARS = ['', '拾', '佰', '仟', '万' ] | ||
| 6 | |||
| 7 | |||
| 8 | def to_rmb_upper(price): | ||
| 9 | price = round(price, 2) | ||
| 10 | integer_part = int(price) | ||
| 11 | wanyi_part = integer_part // 1000000000000 | ||
| 12 | yi_part = integer_part % 1000000000000 // 100000000 | ||
| 13 | wan_part = integer_part % 100000000 // 10000 | ||
| 14 | qian_part = integer_part % 10000 | ||
| 15 | dec_part = int(round(price * 100 % 100)) | ||
| 16 | |||
| 17 | strio = StringIO() | ||
| 18 | |||
| 19 | zero_count = 0 | ||
| 20 | #处理万亿以上的部分 | ||
| 21 | if integer_part >= 1000000000000 and wanyi_part > 0: | ||
| 22 | zero_count = _parse_integer(strio, wanyi_part, zero_count, True) | ||
| 23 | strio.write('万') | ||
| 24 | |||
| 25 | #处理亿到千亿的部分 | ||
| 26 | if integer_part >= 100000000 and yi_part > 0: | ||
| 27 | is_first_section = integer_part >= 100000000 and integer_part < 1000000000000 | ||
| 28 | zero_count = _parse_integer(strio, yi_part, zero_count, is_first_section) | ||
| 29 | strio.write('亿') | ||
| 30 | |||
| 31 | #处理万的部分 | ||
| 32 | if integer_part >= 10000 and wan_part > 0: | ||
| 33 | is_first_section = integer_part >= 1000 and integer_part < 10000000 | ||
| 34 | zero_count = _parse_integer(strio, wan_part, zero_count, is_first_section) | ||
| 35 | strio.write('万') | ||
| 36 | |||
| 37 | #处理千及以后的部分 | ||
| 38 | if qian_part > 0: | ||
| 39 | is_first_section = integer_part < 1000 | ||
| 40 | zero_count = _parse_integer(strio, qian_part, zero_count, is_first_section) | ||
| 41 | else: | ||
| 42 | zero_count += 1 | ||
| 43 | if integer_part > 0: | ||
| 44 | strio.write('元') | ||
| 45 | |||
| 46 | #处理小数 | ||
| 47 | if dec_part > 0: | ||
| 48 | _parse_decimal(strio, integer_part, dec_part, zero_count) | ||
| 49 | elif dec_part == 0 and integer_part > 0: | ||
| 50 | strio.write('整') | ||
| 51 | else: | ||
| 52 | strio.write('零元整') | ||
| 53 | |||
| 54 | return strio.getvalue() | ||
| 55 | |||
| 56 | |||
| 57 | def _parse_integer(strio, value, zero_count = 0, is_first_section = False): | ||
| 58 | assert value > 0 and value <= 9999 | ||
| 59 | ndigits = int(math.floor(math.log10(value))) + 1 | ||
| 60 | if value < 1000 and not is_first_section: | ||
| 61 | zero_count += 1 | ||
| 62 | for i in range(0, ndigits): | ||
| 63 | factor = int(pow(10, ndigits - 1 - i)) | ||
| 64 | digit = int(value / factor) | ||
| 65 | if digit != 0: | ||
| 66 | if zero_count > 0: | ||
| 67 | strio.write('零') | ||
| 68 | strio.write(_RMB_DIGITS[digit]) | ||
| 69 | strio.write(_SECTION_CHARS[ndigits - i - 1]) | ||
| 70 | zero_count = 0 | ||
| 71 | else: | ||
| 72 | zero_count += 1 | ||
| 73 | value -= value // factor * factor | ||
| 74 | return zero_count | ||
| 75 | |||
| 76 | |||
| 77 | def _parse_decimal(strio, integer_part, value, zero_count): | ||
| 78 | assert value > 0 and value <= 99 | ||
| 79 | jiao = value // 10 | ||
| 80 | fen = value % 10 | ||
| 81 | if zero_count > 0 and (jiao > 0 or fen > 0) and integer_part > 0: | ||
| 82 | strio.write('零') | ||
| 83 | if jiao > 0: | ||
| 84 | strio.write(_RMB_DIGITS[jiao]) | ||
| 85 | strio.write('角') | ||
| 86 | if zero_count == 0 and jiao == 0 and fen > 0 and integer_part > 0: | ||
| 87 | strio.write('零') | ||
| 88 | if fen > 0: | ||
| 89 | strio.write(_RMB_DIGITS[fen]) | ||
| 90 | strio.write('分') | ||
| 91 | else: | ||
| 92 | strio.write('整') | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
-
Please register or sign in to post a comment