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