1e50135a by 周伟奇

prese part 1

1 parent f6840d5c
...@@ -1234,26 +1234,39 @@ RESULT_MAPPING = { ...@@ -1234,26 +1234,39 @@ RESULT_MAPPING = {
1234 } 1234 }
1235 1235
1236 CA_ADD_COMPARE_FIELDS = (IC_OCR_FIELD, BL_OCR_FIELD, BS_FIELD) 1236 CA_ADD_COMPARE_FIELDS = (IC_OCR_FIELD, BL_OCR_FIELD, BS_FIELD)
1237 CA_ADD_COMPARE_FIELDS_PRE = (IC_OCR_FIELD,)
1238
1239 COMPARE_FIELDS = (
1240 MVI_OCR_FIELD,
1241 IC_OCR_FIELD,
1242 RP_OCR_FIELD,
1243 BC_OCR_FIELD,
1244 BL_OCR_FIELD,
1245 UCI_OCR_FIELD,
1246 EEP_OCR_FIELD,
1247 DL_OCR_FIELD,
1248 PP_OCR_FIELD,
1249 MVC_OCR_FIELD,
1250 DDA_OCR_FIELD,
1251 HMH_OCR_FIELD,
1252 JYPZ_OCR_FIELD,
1253 HT_FIELD,
1254 BD_FIELD,
1255 BS_FIELD,
1256 HIL_CONTRACT_1_FIELD,
1257 HIL_CONTRACT_2_FIELD,
1258 HIL_CONTRACT_3_FIELD,
1259 )
1237 1260
1238 COMPARE_FIELDS = (MVI_OCR_FIELD, 1261 PRE_COMPARE_FIELDS = (
1239 IC_OCR_FIELD, 1262 MVI_OCR_FIELD,
1240 RP_OCR_FIELD, 1263 IC_OCR_FIELD,
1241 BC_OCR_FIELD, 1264 BC_OCR_FIELD,
1242 BL_OCR_FIELD, 1265 HMH_OCR_FIELD,
1243 UCI_OCR_FIELD, 1266 HT_FIELD,
1244 EEP_OCR_FIELD, 1267 BD_FIELD,
1245 DL_OCR_FIELD, 1268 HIL_CONTRACT_1_FIELD,
1246 PP_OCR_FIELD, 1269 HIL_CONTRACT_2_FIELD,
1247 MVC_OCR_FIELD,
1248 DDA_OCR_FIELD,
1249 HMH_OCR_FIELD,
1250 JYPZ_OCR_FIELD,
1251 HT_FIELD,
1252 BD_FIELD,
1253 BS_FIELD,
1254 HIL_CONTRACT_1_FIELD,
1255 HIL_CONTRACT_2_FIELD,
1256 HIL_CONTRACT_3_FIELD,
1257 ) 1270 )
1258 1271
1259 # 身份证 1272 # 身份证
......
...@@ -2,8 +2,9 @@ import re ...@@ -2,8 +2,9 @@ import re
2 import json 2 import json
3 import requests 3 import requests
4 from .named_enum import DocStatus 4 from .named_enum import DocStatus
5 from .models import HILDoc, AFCDoc 5 from .models import HILDoc, AFCDoc, AFCSEOCRResult, AFCOCRResult, HILSEOCRResult, HILOCRResult
6 from . import consts 6 from . import consts
7 from prese.compare import pre_compare
7 8
8 9
9 class MPOSHandler: 10 class MPOSHandler:
...@@ -141,3 +142,31 @@ class DocHandler: ...@@ -141,3 +142,31 @@ class DocHandler:
141 else: 142 else:
142 return consts.DATA_SOURCE_LIST[0] 143 return consts.DATA_SOURCE_LIST[0]
143 144
145
146 class PreSEHandler:
147
148 # preSettlement
149 @staticmethod
150 def pre_compare_entrance(pos_content):
151 application_entity = pos_content.get('applicationEntity')
152 application_id = pos_content.get('applicationId')
153
154 # 根据application_id查找OCR累计结果指定license字段,如果没有,结束
155 result_class = HILSEOCRResult if application_entity in consts.HIL_SET else AFCSEOCRResult
156 ca_result_class = HILOCRResult if application_entity in consts.HIL_SET else AFCOCRResult
157
158 ca_ocr_res_dict = ca_result_class.objects.filter(application_id=application_id).values(
159 *consts.CA_ADD_COMPARE_FIELDS_PRE).first()
160 ocr_res_dict = result_class.objects.filter(application_id=application_id).values(
161 *consts.PRE_COMPARE_FIELDS).first()
162 if ocr_res_dict is None:
163 return
164
165 id_res_list = []
166 for field_name in consts.CA_ADD_COMPARE_FIELDS_PRE:
167 if field_name == consts.IC_OCR_FIELD:
168 id_res_list.append(ca_ocr_res_dict.get(field_name) if isinstance(ca_ocr_res_dict, dict) else None)
169 id_res_list.append(ocr_res_dict.get(field_name))
170
171 rebuild_compare_result = pre_compare(pos_content, ocr_res_dict, id_res_list)
172 return rebuild_compare_result
......
...@@ -48,10 +48,10 @@ from .models import ( ...@@ -48,10 +48,10 @@ from .models import (
48 MposReport, 48 MposReport,
49 ) 49 )
50 from .named_enum import ErrorType, AutoResult, WholeResult, RPAResult 50 from .named_enum import ErrorType, AutoResult, WholeResult, RPAResult
51 from .mixins import DocHandler, MPOSHandler 51 from .mixins import DocHandler, MPOSHandler, PreSEHandler
52 from . import consts 52 from . import consts
53 from apps.account.authentication import OAuth2AuthenticationWithUser 53 from apps.account.authentication import OAuth2AuthenticationWithUser
54 from celery_compare.tasks import compare, pos_compare 54 from celery_compare.tasks import compare
55 55
56 56
57 class CustomDate(fields.Date): 57 class CustomDate(fields.Date):
...@@ -87,6 +87,8 @@ se_vehicle_args = { ...@@ -87,6 +87,8 @@ se_vehicle_args = {
87 'vehicleTransactionAmount': CustomDecimal(required=True), 87 'vehicleTransactionAmount': CustomDecimal(required=True),
88 'vinNo': fields.Str(required=True, validate=validate.Length(max=256)), 88 'vinNo': fields.Str(required=True, validate=validate.Length(max=256)),
89 'dealer': fields.Str(required=True, validate=validate.Length(max=256)), 89 'dealer': fields.Str(required=True, validate=validate.Length(max=256)),
90 'showRoom': fields.Str(required=False),
91 'agencyDealer': fields.Str(required=False),
90 'option': CustomDecimal(required=False), 92 'option': CustomDecimal(required=False),
91 'msrp': CustomDecimal(required=False), 93 'msrp': CustomDecimal(required=False),
92 'totalAmount': CustomDecimal(required=False), 94 'totalAmount': CustomDecimal(required=False),
...@@ -125,6 +127,7 @@ se_quotationt_args = { ...@@ -125,6 +127,7 @@ se_quotationt_args = {
125 'loanTerm': fields.Int(required=True), 127 'loanTerm': fields.Int(required=True),
126 'vehiclePrincipal': CustomDecimal(required=True), 128 'vehiclePrincipal': CustomDecimal(required=True),
127 'associatedServicePrincipal': CustomDecimal(required=False), 129 'associatedServicePrincipal': CustomDecimal(required=False),
130 'mortgageType': fields.Str(required=True, validate=validate.Length(max=16)),
128 'associatedServiceInfo': fields.List(fields.Nested(se_associated_args), required=False), 131 'associatedServiceInfo': fields.List(fields.Nested(se_associated_args), required=False),
129 'monthlyPaymentInfo': fields.List(fields.Nested(se_payment_args), required=True, validate=validate.Length(min=1)), 132 'monthlyPaymentInfo': fields.List(fields.Nested(se_payment_args), required=True, validate=validate.Length(min=1)),
130 } 133 }
...@@ -224,6 +227,10 @@ se_compare_content = { ...@@ -224,6 +227,10 @@ se_compare_content = {
224 'applicationId': fields.Str(required=True, validate=validate.Length(max=64)), 227 'applicationId': fields.Str(required=True, validate=validate.Length(max=64)),
225 "applicationVersion": fields.Int(required=True), 228 "applicationVersion": fields.Int(required=True),
226 'applicationEntity': fields.Str(required=True, validate=validate.OneOf(consts.ENTITY)), 229 'applicationEntity': fields.Str(required=True, validate=validate.OneOf(consts.ENTITY)),
230
231 'productGroup': fields.Str(required=False),
232 'productGroupID': fields.Str(required=False),
233
227 'customerType': fields.Str(required=True, validate=validate.OneOf(consts.CUSTOMER_TYPE)), 234 'customerType': fields.Str(required=True, validate=validate.OneOf(consts.CUSTOMER_TYPE)),
228 "firstSubmmisonDate": CustomDate(required=True), 235 "firstSubmmisonDate": CustomDate(required=True),
229 'propertyDocumentPolicy': fields.Str(required=False, validate=validate.Length(max=16)), 236 'propertyDocumentPolicy': fields.Str(required=False, validate=validate.Length(max=16)),
...@@ -754,34 +761,45 @@ class CompareView(GenericView): ...@@ -754,34 +761,45 @@ class CompareView(GenericView):
754 ''' 761 '''
755 762
756 763
757 class SECompareView(GenericView): 764 class SECompareView(GenericView, PreSEHandler):
758 permission_classes = [IsAuthenticated] 765 permission_classes = [IsAuthenticated]
759 authentication_classes = [OAuth2AuthenticationWithUser] 766 authentication_classes = [OAuth2AuthenticationWithUser]
760 767
761 # pos上传比对信息接口 SE 768 # SE preSettlement
762 @use_args(se_compare_args, location='data') 769 @use_args(se_compare_args, location='data')
763 def post(self, request, args): 770 def post(self, request, args):
764 # 存库 771 log_base = '[prese]'
772
765 content = args.get('content', {}) 773 content = args.get('content', {})
766 business_type = content.get('applicationEntity') 774 business_type = content.get('applicationEntity')
767 application_id = content.get('applicationId') 775 application_id = content.get('applicationId')
776 uniq_seq = content.get('uniqSeq')
768 bank_verify = content.get('bankInfo', {}).get('bankVerificationStatus', '') 777 bank_verify = content.get('bankInfo', {}).get('bankVerificationStatus', '')
769 778
770 bank_class = HILbankVerification if business_type in consts.HIL_SET else AFCbankVerification 779 # 存库, 用于银行卡比对
771 bank_obj = bank_class.objects.filter(application_id=application_id).first() 780 try:
781 bank_class = HILbankVerification if business_type in consts.HIL_SET else AFCbankVerification
782 bank_obj = bank_class.objects.filter(application_id=application_id).first()
772 783
773 if bank_obj is None and bank_verify == 'PASS': 784 if bank_obj is None and bank_verify == 'PASS':
774 bank_class.objects.create( 785 bank_class.objects.create(
775 application_id=application_id, 786 application_id=application_id,
776 ) 787 )
777 elif bank_obj is not None and bank_verify == 'PASS' and bank_obj.on_off is False: 788 elif bank_obj is not None and bank_verify == 'PASS' and bank_obj.on_off is False:
778 bank_obj.on_off = True 789 bank_obj.on_off = True
779 bank_obj.save() 790 bank_obj.save()
780 elif bank_obj is not None and bank_verify != 'PASS' and bank_obj.on_off is True: 791 elif bank_obj is not None and bank_verify != 'PASS' and bank_obj.on_off is True:
781 bank_obj.on_off = False 792 bank_obj.on_off = False
782 bank_obj.save() 793 bank_obj.save()
783 794 except Exception as e:
784 compare_result = pos_compare(content) 795 self.running_log.info('{0} [bankCard verify save db error] [applicationEntity={1}] '
796 '[application_id={2}] [bank_status={3}] [error={4}]'.format(
797 log_base, business_type, application_id, bank_verify, traceback.format_exc()))
798
799 # preSettlement比对
800 compare_result = self.pre_compare_entrance(content)
801 self.running_log.info('{0} [prese completed] [applicationEntity={1}] [application_id={2}] [uniq_seq={3}] '
802 '[result={4}]'.format(log_base, business_type, application_id, uniq_seq, compare_result))
785 803
786 return response.ok(data=compare_result) 804 return response.ok(data=compare_result)
787 805
......
...@@ -39,7 +39,6 @@ from apps.doc.exceptions import GCAPException ...@@ -39,7 +39,6 @@ from apps.doc.exceptions import GCAPException
39 from apps.doc.named_enum import RequestTeam, RequestTrigger, ProcessName, ErrorType 39 from apps.doc.named_enum import RequestTeam, RequestTrigger, ProcessName, ErrorType
40 from common.tools.comparison import cp 40 from common.tools.comparison import cp
41 from common.tools.des import decode_des 41 from common.tools.des import decode_des
42 from pos import pos
43 42
44 compare_log = logging.getLogger('compare') 43 compare_log = logging.getLogger('compare')
45 log_base = '[Compare]' 44 log_base = '[Compare]'
...@@ -2414,6 +2413,7 @@ def se_compare_license_id(license_en, id_res_list, field_list): ...@@ -2414,6 +2413,7 @@ def se_compare_license_id(license_en, id_res_list, field_list):
2414 if is_find: 2413 if is_find:
2415 break 2414 break
2416 2415
2416 result_field_list.clear()
2417 for idx, (name, value) in enumerate(field_list): 2417 for idx, (name, value) in enumerate(field_list):
2418 # if ocr_field == consts.MVI_OCR_FIELD and name == consts.SE_NEW_ADD_FIELD[9]: 2418 # if ocr_field == consts.MVI_OCR_FIELD and name == consts.SE_NEW_ADD_FIELD[9]:
2419 # ocr_str = getattr(cp, consts.ZW_METHOD)( 2419 # ocr_str = getattr(cp, consts.ZW_METHOD)(
...@@ -2493,6 +2493,7 @@ def se_compare_license_id(license_en, id_res_list, field_list): ...@@ -2493,6 +2493,7 @@ def se_compare_license_id(license_en, id_res_list, field_list):
2493 result_field_list.append((name, value, result, ocr_str, img_path, error_type, compare_logic[name][3])) 2493 result_field_list.append((name, value, result, ocr_str, img_path, error_type, compare_logic[name][3]))
2494 2494
2495 if not is_find: 2495 if not is_find:
2496 result_field_list.clear()
2496 for name, value in field_list: 2497 for name, value in field_list:
2497 if isinstance(value, list): 2498 if isinstance(value, list):
2498 value = json.dumps(value, ensure_ascii=False) 2499 value = json.dumps(value, ensure_ascii=False)
...@@ -3200,135 +3201,3 @@ def compare(application_id, application_entity, uniq_seq, ocr_res_id, is_ca=True ...@@ -3200,135 +3201,3 @@ def compare(application_id, application_entity, uniq_seq, ocr_res_id, is_ca=True
3200 '[error={4}]'.format(log_base, application_entity, application_id, ocr_res_id, 3201 '[error={4}]'.format(log_base, application_entity, application_id, ocr_res_id,
3201 traceback.format_exc())) 3202 traceback.format_exc()))
3202 3203
3203
3204 # pos接口
3205 def pos_compare(pos_content, application_id, application_entity, uniq_seq, ocr_res_id=None, is_ca=True, is_cms=False):
3206 # POS: application_id, application_entity, uniq_seq, None
3207 # OCR: application_id, business_type(application_entity), None, ocr_res_id
3208 compare_log.info('{0} [pos_compare] [entity={1}] [id={2}] [uniq_seq={3}] [is_ca={4}] '
3209 '[is_cms={5}]'.format(log_base, application_entity, application_id, uniq_seq,
3210 is_ca, is_cms))
3211
3212 # 根据application_id查找最新的比对信息,如果没有,结束
3213 # if is_ca:
3214 # comparison_class = HILComparisonInfo if application_entity == consts.HIL_PREFIX else AFCComparisonInfo
3215 # else:
3216 # if application_entity == consts.HIL_PREFIX:
3217 # comparison_class = HILSECMSInfo if is_cms else HILSEComparisonInfo
3218 # else:
3219 # comparison_class = AFCSECMSInfo if is_cms else AFCSEComparisonInfo
3220 # last_obj = comparison_class.objects.filter(application_id=application_id).last()
3221 # if last_obj is None:
3222 # compare_log.info('{0} [comparison info empty] [entity={1}] [id={2}] [uniq_seq={3}] '
3223 # '[is_ca={4}] [is_cms]={5}'.format(log_base, application_entity, application_id, uniq_seq,
3224 # is_ca, is_cms))
3225 # return
3226
3227 # 根据application_id查找OCR累计结果指定license字段,如果没有,结束
3228 if is_ca:
3229 result_class = HILOCRResult if application_entity == consts.HIL_PREFIX else AFCOCRResult
3230 ca_ocr_res_dict = dict()
3231 else:
3232 result_class = HILSEOCRResult if application_entity == consts.HIL_PREFIX else AFCSEOCRResult
3233 ca_result_class = HILOCRResult if application_entity == consts.HIL_PREFIX else AFCOCRResult
3234 # if ocr_res_id is None:
3235 ca_ocr_res_dict = ca_result_class.objects.filter(application_id=application_id).values(
3236 *consts.CA_ADD_COMPARE_FIELDS).first()
3237 # else:
3238 # ca_ocr_res_dict = ca_result_class.objects.filter(id=ocr_res_id).values(
3239 # *consts.CA_ADD_COMPARE_FIELDS).first()
3240 ocr_res_dict = result_class.objects.filter(application_id=application_id).values(*consts.COMPARE_FIELDS).first()
3241 if ocr_res_dict is None:
3242 compare_log.info('{0} [ocr info empty] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] '
3243 '[is_ca={5}] [is_cms]={6}'.format(log_base, application_entity, application_id,
3244 uniq_seq, ocr_res_id, is_ca, is_cms))
3245 return
3246
3247 pos_content_obj = json.loads(pos_content)
3248 if is_ca:
3249 # 比对逻辑
3250 # compare_info = get_ca_compare_info(pos_content_obj)
3251 # compare_result, total_fields, failed_count = ca_compare_process(compare_info, ocr_res_dict)
3252 # compare_log.info('{0} [CA] [compare success] [entity={1}] [id={2}] [ocr_res_id={3}] [result={4}]'.format(
3253 # log_base, application_entity, application_id, ocr_res_id, compare_result))
3254 # ca_compare(application_id, application_entity, ocr_res_id, pos_content_obj, ocr_res_dict)
3255 compare_result = pos.PosCompare.ca_compare(pos_content_obj, ocr_res_dict)
3256 else:
3257 id_res_list = []
3258 for field_name in consts.CA_ADD_COMPARE_FIELDS:
3259 if field_name == consts.IC_OCR_FIELD:
3260 id_res_list.append(ocr_res_dict.get(field_name))
3261 id_res_list.append(ca_ocr_res_dict.get(field_name) if isinstance(ca_ocr_res_dict, dict) else None)
3262
3263 if isinstance(ca_ocr_res_dict, dict) and isinstance(ca_ocr_res_dict.get(field_name), str):
3264 tmp_ca_result = json.loads(ca_ocr_res_dict.get(field_name))
3265 if isinstance(ocr_res_dict.get(field_name), str):
3266 tmp_se_result = json.loads(ocr_res_dict.get(field_name))
3267 tmp_ca_result.extend(tmp_se_result)
3268 ocr_res_dict[field_name] = json.dumps(tmp_ca_result)
3269 # auto settlement
3270 # auto_class = HILAutoSettlement if application_entity == consts.HIL_PREFIX else AFCAutoSettlement
3271 # auto_obj = auto_class.objects.filter(application_id=application_id, on_off=True).first()
3272 # bank_class = HILbankVerification if application_entity == consts.HIL_PREFIX else AFCbankVerification
3273 # ignore_bank = bank_class.objects.filter(application_id=application_id, on_off=True).exists()
3274 # if auto_obj is not None:
3275 # auto_result = se_compare_auto(application_id, application_entity, ocr_res_id, pos_content_obj, ocr_res_dict, auto_obj, ignore_bank, id_res_list)
3276 # else:
3277 # auto_result = None
3278 #
3279 # full_result = se_compare(application_id, application_entity, ocr_res_id, pos_content_obj, ocr_res_dict, is_cms, auto_result, ignore_bank, id_res_list)
3280 #
3281 # if auto_obj is not None:
3282 # try:
3283 # auto_obj.ocr_whole_result_pass = full_result
3284 # auto_obj.save()
3285 # compare_log.info('{0} [Auto SE] [result save success] [entity={1}] [id={2}] [ocr_res_id={3}]'.format(
3286 # log_base, application_entity, application_id, ocr_res_id))
3287 # except Exception as e:
3288 # compare_log.error('{0} [Auto SE] [result save error] [entity={1}] [id={2}] [ocr_res_id={3}] '
3289 # '[error={4}]'.format(log_base, application_entity, application_id, ocr_res_id,
3290 # traceback.format_exc()))
3291
3292 # result_table = HILCACompareResult if application_entity == consts.HIL_PREFIX else AFCCACompareResult
3293 # res_obj = result_table.objects.filter(application_id=application_id).first()
3294 compare_result = pos.PosCompare.se_compare(pos_content_obj, ocr_res_dict, id_res_list=id_res_list)
3295 return pos_result_output(compare_result)
3296
3297
3298 # pos输出解析
3299 def pos_result_output(compare_result):
3300 result_obj = json.loads(compare_result)
3301 license_map = dict()
3302 for item in result_obj:
3303 license_en = item.get("License")
3304 if license_map.get(license_en):
3305 license_map.get(license_en).append(item)
3306 else:
3307 info_items = [item]
3308 license_map[license_en] = info_items
3309
3310 is_pass = True
3311 particulars = []
3312 for license, license_items in license_map.items():
3313 particular = {"object_name": license}
3314 # license_comments = OCR_COMPARE_COMMENT.get(license)
3315 # if not license_comments:
3316 # continue
3317 fields = []
3318 particular["fields"] = fields
3319 for license_item in license_items:
3320 field = dict()
3321 field["input"] = license_item.get("Input")
3322 field["ocr"] = license_item.get("OCR")
3323 field["field_is_pass"] = license_item.get("Result") == 'Y'
3324 if not field["field_is_pass"]:
3325 is_pass = False
3326 field["comments"] = license_item.get('comments', '')
3327 fields.append(field)
3328 particular["fields"] = fields
3329 particulars.append(particular)
3330
3331 return {
3332 "is_pass": is_pass,
3333 "particulars": particulars
3334 }
......
...@@ -29,8 +29,6 @@ class Comparison: ...@@ -29,8 +29,6 @@ class Comparison:
29 29
30 self.RESULT_Y = 'Y' 30 self.RESULT_Y = 'Y'
31 self.RESULT_N = 'N' 31 self.RESULT_N = 'N'
32 self.RESULT_N1 = 'N1'
33 self.RESULT_N2 = 'N2'
34 self.RESULT_NA = 'NA' 32 self.RESULT_NA = 'NA'
35 33
36 self.TRANS_MAP = { 34 self.TRANS_MAP = {
...@@ -610,19 +608,19 @@ class Comparison: ...@@ -610,19 +608,19 @@ class Comparison:
610 return self.RESULT_N 608 return self.RESULT_N
611 return self.se_date_compare_2(input_str, ocr_date_set.pop(), three_month=True) 609 return self.se_date_compare_2(input_str, ocr_date_set.pop(), three_month=True)
612 610
613 def se_date_compare_pos(self, input_str, ocr_str, **kwargs): 611 # def se_date_compare_pos(self, input_str, ocr_str, **kwargs):
614 try: 612 # try:
615 ocr_date = datetime.strptime(ocr_str, "%Y-%m-%d").date() 613 # ocr_date = datetime.strptime(ocr_str, "%Y-%m-%d").date()
616 today = datetime.now().date() 614 # today = datetime.now().date()
617 if ocr_date < today: 615 # if ocr_date < today:
618 return self.RESULT_N1 616 # return self.RESULT_N1
619 elif today <= ocr_date <= (today + timedelta(days=8)): 617 # elif today <= ocr_date <= (today + timedelta(days=8)):
620 return self.RESULT_N2 618 # return self.RESULT_N2
621 elif ocr_date > (today + timedelta(days=8)): 619 # elif ocr_date > (today + timedelta(days=8)):
622 return self.RESULT_Y 620 # return self.RESULT_Y
623 except Exception as e: 621 # except Exception as e:
624 return self.RESULT_N 622 # return self.RESULT_N
625 return self.RESULT_N 623 # return self.RESULT_N
626 624
627 625
628 cp = Comparison() 626 cp = Comparison()
......
1 from apps.doc import consts
2 import json
3 from common.tools.des import decode_des
4 from pos import pos_consts
5 from settings import conf
6 from pos_compare import SECompare, CACompare
7
8 empty_str = ''
9 des_key = conf.CMS_DES_KEY
10 empty_error_type = 1000
11
12
13 def ca_compare_process(compare_info, ocr_res_dict):
14 # individualCusInfo
15 # corporateCusInfo
16 # usedCarInfo
17 compare_result = []
18 total_fields = 0
19 failed_count = 0
20
21 for info_key, info_value in compare_info.items():
22 if info_key == 'individualCusInfo':
23 for idx, license_list in info_value.items():
24 for license_dict in license_list:
25 for license_en, field_list in license_dict.items():
26 result_field_list, field_img_path_dict = CACompare.ca_compare_license(license_en, ocr_res_dict, field_list)
27 for name, value, result, ocr_str, img_path, error_type, reason in result_field_list:
28 total_fields += 1
29 if result == consts.RESULT_N:
30 failed_count += 1
31 compare_result.append(
32 {
33 consts.HEAD_LIST[0]: info_key,
34 consts.HEAD_LIST[1]: idx,
35 consts.HEAD_LIST[2]: license_en,
36 consts.HEAD_LIST[3]: name,
37 consts.HEAD_LIST[4]: value,
38 consts.HEAD_LIST[5]: ocr_str,
39 consts.HEAD_LIST[6]: result,
40 consts.HEAD_LIST[7]: field_img_path_dict.get(name, empty_str),
41 consts.HEAD_LIST[8]: img_path,
42 consts.HEAD_LIST[9]: error_type,
43 "comments": reason if result == consts.RESULT_N else ''
44 }
45 )
46 else:
47 for license_en, field_list in info_value.items():
48 result_field_list, field_img_path_dict = CACompare.ca_compare_license(license_en, ocr_res_dict, field_list)
49 for name, value, result, ocr_str, img_path, error_type, reason in result_field_list:
50 total_fields += 1
51 if result == consts.RESULT_N:
52 failed_count += 1
53 compare_result.append(
54 {
55 consts.HEAD_LIST[0]: info_key,
56 consts.HEAD_LIST[1]: "0",
57 consts.HEAD_LIST[2]: license_en,
58 consts.HEAD_LIST[3]: name,
59 consts.HEAD_LIST[4]: value,
60 consts.HEAD_LIST[5]: ocr_str,
61 consts.HEAD_LIST[6]: result,
62 consts.HEAD_LIST[7]: field_img_path_dict.get(name, empty_str),
63 consts.HEAD_LIST[8]: img_path,
64 consts.HEAD_LIST[9]: error_type,
65 "comments": reason if result == consts.RESULT_N else ''
66 }
67 )
68 return compare_result, total_fields, failed_count
69
70
71 def se_compare_process(compare_info, ocr_res_dict, is_gsyh, is_auto, id_res_list):
72 # individualCusInfo
73 # corporateCusInfo
74 # vehicleInfo
75 # bankInfo
76 compare_result = []
77 total_fields = 0
78 failed_count = 0
79 successful_at_this_level = True
80 failure_reason = {}
81 cn_reason_list = []
82 rpa_failure_reason = {}
83
84 for info_key, info_value in compare_info.items():
85 if info_key in ['individualCusInfo', 'applicantInformation']:
86 for idx, license_list in info_value.items():
87 for license_dict in license_list:
88 for license_en, field_list in license_dict.items():
89 strip_list = []
90 for a, b in field_list:
91 if isinstance(b, str):
92 strip_list.append((a, b.strip()))
93 elif isinstance(b, list):
94 c = []
95 for i in b:
96 if isinstance(i, str):
97 c.append(i.strip())
98 else:
99 c.append(i)
100 strip_list.append((a, c))
101 else:
102 strip_list.append((a, b))
103 failure_field = []
104 # 身份证先SE正反面,后CA正反面
105 if license_en == consts.ID_EN:
106 result_field_list, no_ocr_result, field_img_path_dict = SECompare.se_compare_license_id(
107 license_en, id_res_list, strip_list)
108 else:
109 result_field_list, no_ocr_result, field_img_path_dict = SECompare.se_compare_license(
110 license_en, ocr_res_dict, strip_list)
111 for name, value, result, ocr_str, img_path, error_type, cn_reason in result_field_list:
112 if license_en not in consts.SKIP_CARD or not no_ocr_result:
113 total_fields += 1
114 if result == consts.RESULT_N:
115 failed_count += 1
116 successful_at_this_level = False
117 failure_field.append(name)
118 cn_reason_list.append(cn_reason)
119 rpa_failure_reason.setdefault(cn_reason, []).append(value)
120 compare_result.append(
121 {
122 consts.HEAD_LIST[0]: info_key,
123 consts.HEAD_LIST[1]: idx,
124 consts.HEAD_LIST[2]: license_en,
125 consts.HEAD_LIST[3]: name,
126 consts.HEAD_LIST[4]: value,
127 consts.HEAD_LIST[5]: ocr_str,
128 consts.HEAD_LIST[6]: result,
129 consts.HEAD_LIST[7]: field_img_path_dict.get(name, empty_str),
130 consts.HEAD_LIST[8]: img_path,
131 consts.HEAD_LIST[9]: error_type,
132 "comments": cn_reason if result == consts.RESULT_N else ''
133 }
134 )
135 if len(failure_field) > 0:
136 failure_reason.setdefault(info_key, []).append(';'.join(failure_field))
137 else:
138 for license_en, field_list in info_value.items():
139 strip_list = []
140 for a, b in field_list:
141 if isinstance(b, str):
142 strip_list.append((a, b.strip()))
143 elif isinstance(b, list):
144 c = []
145 for i in b:
146 if isinstance(i, str):
147 c.append(i.strip())
148 else:
149 c.append(i)
150 strip_list.append((a, c))
151 else:
152 strip_list.append((a, b))
153 failure_field = []
154 if license_en == consts.MVC34_EN:
155 result_field_list, field_img_path_dict = SECompare.se_mvc34_compare(license_en, ocr_res_dict, strip_list)
156 elif license_en in [consts.HIL_CONTRACT_1_EN, consts.HIL_CONTRACT_2_EN, consts.HIL_CONTRACT_3_EN, consts.AFC_CONTRACT_EN]:
157 result_field_list, field_img_path_dict = SECompare.se_contract_compare(license_en, ocr_res_dict, strip_list, is_gsyh)
158 elif license_en == consts.BS_EN:
159 result_field_list, field_img_path_dict = SECompare.se_bs_compare(license_en, ocr_res_dict, strip_list, is_auto)
160 else:
161 result_field_list, _, field_img_path_dict = SECompare.se_compare_license(license_en, ocr_res_dict, strip_list)
162
163 for name, value, result, ocr_str, img_path, error_type, cn_reason in result_field_list:
164 total_fields += 1
165 if result == consts.RESULT_N:
166 # if license_en != consts.MVI_EN or name != consts.SE_NEW_ADD_FIELD[9]:
167 successful_at_this_level = False
168 failed_count += 1
169 failure_field.append(name)
170 if isinstance(cn_reason, str):
171 cn_reason_list.append(cn_reason)
172 rpa_failure_reason.setdefault(cn_reason, []).append(value)
173 elif isinstance(cn_reason, list):
174 cn_reason_list.extend(cn_reason)
175 rpa_failure_reason.setdefault('、'.join(cn_reason), []).append(value)
176 compare_result.append(
177 {
178 consts.HEAD_LIST[0]: info_key,
179 consts.HEAD_LIST[1]: "0",
180 consts.HEAD_LIST[2]: license_en,
181 consts.HEAD_LIST[3]: name,
182 consts.HEAD_LIST[4]: value,
183 consts.HEAD_LIST[5]: ocr_str,
184 consts.HEAD_LIST[6]: result,
185 consts.HEAD_LIST[7]: field_img_path_dict.get(name, empty_str),
186 consts.HEAD_LIST[8]: img_path,
187 consts.HEAD_LIST[9]: error_type,
188 "comments": cn_reason if result == consts.RESULT_N else ''
189 }
190 )
191 if len(failure_field) > 0:
192 failure_reason.setdefault(info_key, []).append(';'.join(failure_field))
193 if failed_count == 0:
194 failure_reason_str = ''
195 cn_failure_reason_str = ''
196 bs_failure_reason_str = ''
197 else:
198 reason_list = []
199 for key, value in failure_reason.items():
200 if len(value) > 0:
201 value_str = json.dumps(value)
202 reason_list.append('{0}: {1}'.format(key, value_str))
203 failure_reason_str = '、'.join(reason_list)
204
205 tmp_set = set()
206 last_cn_reason_list = []
207 bs_cn_reason_list = []
208 for i in cn_reason_list:
209 if i in tmp_set:
210 continue
211 # elif i in consts.BS_REASON:
212 # tmp_set.add(i)
213 # bs_cn_reason_list.append(i)
214 else:
215 tmp_set.add(i)
216 last_cn_reason_list.append(i)
217 cn_failure_reason_str = '\n'.join(last_cn_reason_list)
218 bs_failure_reason_str = '\n'.join(bs_cn_reason_list)
219 return compare_result, total_fields, failed_count, successful_at_this_level, failure_reason_str, cn_failure_reason_str, bs_failure_reason_str, rpa_failure_reason
220
221
222 class CorporateCusInfo:
223 def __init__(self):
224 self.customerType = ''
225 self.companyName = ''
226 self.firstIdType = ''
227 self.firstIdNo = ''
228 self.businessLicenseNo = ''
229 self.organizationCreditCode = ''
230 self.taxRegistrationCertificateNo = ''
231 self.establishmentDate = ''
232 self.incorporationDate = ''
233 self.businessLicenseDueDate = ''
234 self.legalRepName = ''
235 self.organizationType = ''
236 self.fleetCustomer = False
237 self.beneficialOwnerName = ''
238 self.beneficialOwnerIdType = ''
239 self.beneficialOwnerIdNo = ''
240 self.beneficialOwnerIdExpiryDate = ''
241
242
243 class VehicleInfo:
244 def __int__(self):
245 self.vehicleStatus = ''
246 self.vehicleTransactionAmount = 0.0
247 self.vinNo = ''
248 self.dealer = ''
249 self.showRoom = ''
250 self.agencyDealer = ''
251 self.option = 0.0
252 self.msrp = 0.0
253 self.totalAmount = 0.0
254
255
256 class InsuranceInfo:
257 def __init__(self):
258 self.insuredAmount = 0.0
259 self.insuranceType = ''
260 self.startDate = ''
261 self.endDate = ''
262
263
264 class BankInfo:
265 def __init__(self):
266 self.bankName = ''
267 self.branchName = ''
268 self.applicantType = ''
269 self.accountHolderName = ''
270 self.accountNo = ''
271 self.accountNo = 'bankVerificationStatus'
272 self.isAllDocUploaded = False
273
274
275 class QuotationtInfo:
276 def __init__(self):
277 self.totalLoanAmount = 0.0
278 self.loanTerm = 0
279 self.vehiclePrincipal = 0.0
280 self.associatedServicePrincipal = 0.0
281 self.mortgageType = ''
282 self.associatedServiceInfo = []
283 self.monthlyPaymentInfo = []
284
285
286 class CompareInfoResult:
287 def __init__(self):
288 self.compare_info = None
289 self.is_cdfl_bo = False # 车贷分离,主借
290 self.is_cdfl_co = False # 车贷分离,共借
291 self.is_gsyh = False # 是否工商银行
292
293
294 class CompareInfo:
295 def __init__(self, pos_content):
296 self.pos_content = pos_content
297 self.compare_info = {}
298 self.main_role_info = {}
299 self.company_info_list = []
300 self.company_info = None
301 self.vehicleTransactionAmount = 0.0
302 self.customer_name = ''
303 self.id_num = None
304 self.application_id = pos_content.get('applicationId', '')
305 self.application_version = pos_content.get('applicationVersion', 0)
306 self.application_entity = pos_content.get('applicationEntity', '')
307 self.is_auto_settlement = pos_content.get('isAutoSettlement', '')
308 self.first_submmison_date = pos_content.get('firstSubmmisonDate', '')
309 self.product_group_name = pos_content.get('productGroup', '')
310 self.account_holder_name = ''
311
312 self.is_cdfl_bo = False # 车贷分离,主借
313 self.is_cdfl_co = False # 车贷分离,共借
314 self.is_gsyh = False # 是否工商银行
315
316 self.vin_no = ''
317 self.bank_name = ''
318 self.account_no = ''
319
320 def get(self, ignore_bank=False):
321 individual_cus_info = self.pos_content.get('individualCusInfo', [])
322 corporate_cus_info = self.pos_content.get('corporateCusInfo', {})
323 vehicle_info = self.pos_content.get('vehicleInfo', {})
324 insurance_info = self.pos_content.get('insuranceInfo', {})
325 bank_info = self.pos_content.get('bankInfo', {})
326 quotationt_info = self.pos_content.get('quotationtInfo', {})
327
328 self.getApplicantInformation(individual_cus_info, corporate_cus_info)
329 self.getVehicleInfo(vehicle_info)
330 self.getBankInfo(bank_info, ignore_bank)
331 self.getContract(quotationt_info)
332 self.getOther(quotationt_info, insurance_info)
333
334 compare_result = CompareInfoResult()
335 compare_result.compare_info = self.compare_info
336 compare_result.is_cdfl_co = self.is_cdfl_co
337 compare_result.is_cdfl_bo = self.is_cdfl_bo
338 compare_result.is_gsyh = self.is_gsyh
339 return compare_result
340
341 def getApplicantInformation(self, individual_cus_info, corporate_cus_info):
342 individual_info_dict = {}
343 for individual_info in individual_cus_info:
344 all_id_num = []
345 license_dict = {}
346 customer_name = individual_info.get('customerName', '').strip()
347 self.customer_name = customer_name
348 legal_name = corporate_cus_info.get('legalRepName', '')
349 establishment_date = corporate_cus_info.get('establishmentDate', '')
350
351 # 车贷分离判断
352 is_corporate = individual_info.get('selfEmployedSubType', '') == 'Corporate'
353 if individual_info['applicantType'] == consts.APPLICANT_TYPE_ORDER[1] and is_corporate:
354 self.is_cdfl_co = True
355 if individual_info['applicantType'] == consts.APPLICANT_TYPE_ORDER[0] and not is_corporate:
356 self.is_cdfl_bo = True
357
358 if individual_info.get('idType') in consts.SE_CMS_FIRST_ID_FIELD_MAPPING:
359 license_en, is_prc = consts.SE_CMS_FIRST_ID_FIELD_MAPPING[individual_info['idType']]
360 # ['customerName', 'idNum', 'dateOfBirth', 'idExpiryDate', 'hukouProvince']
361 id_num = decode_des(individual_info.get('idNum', ''), des_key)
362 self.id_num = id_num
363 field_input = [('customerName', customer_name),
364 ('idNum', id_num),
365 ('idExpiryDate', individual_info.get('idExpiryDate', ''))]
366 # if is_prc:
367 # field_input.append(('hukouProvince', province))
368 # field_input.append(('真伪', consts.IC_RES_MAPPING.get(1)))
369 license_dict[license_en] = field_input
370 all_id_num.append(id_num)
371
372 if len(all_id_num) > 0:
373 self.main_role_info.setdefault(individual_info['applicantType'], []).append(
374 (customer_name, '、'.join(all_id_num), all_id_num[0])
375 )
376
377 if len(license_dict) > 0:
378 individual_info_dict.setdefault(individual_info['applicantType'], []).append(license_dict)
379 self.compare_info['applicantInformation'] = individual_info_dict
380
381 def getVehicleInfo(self, vehicleInfo):
382 main_name = main_id_all = main_id = ''
383 for applicant_type in consts.APPLICANT_TYPE_ORDER:
384 if applicant_type in self.main_role_info:
385 main_name, main_id_all, main_id = self.main_role_info[applicant_type][0]
386 # hmh_name, _, hmh_id = main_role_info[applicant_type][0]
387 break
388
389 # co_name = co_id = bo_name = bo_id = ''
390 # if is_cdfl:
391 # co_name, _, co_id = main_role_info[consts.APPLICANT_TYPE_ORDER[1]][0]
392 # bo_name, _, bo_id = main_role_info[consts.APPLICANT_TYPE_ORDER[0]][0]
393
394 co_name = co_id = bo_name = bo_id = ''
395 is_cdfl = self.is_cdfl_bo and self.is_cdfl_co
396 if is_cdfl:
397 if len(self.main_role_info.get(consts.APPLICANT_TYPE_ORDER[1], [])) > 0:
398 co_name, _, co_id = self.main_role_info[consts.APPLICANT_TYPE_ORDER[1]][0]
399 else:
400 co_name = co_id = ''
401 if len(self.main_role_info.get(consts.APPLICANT_TYPE_ORDER[0], [])) > 0:
402 bo_name, _, bo_id = self.main_role_info[consts.APPLICANT_TYPE_ORDER[0]][0]
403 else:
404 bo_name = bo_id = ''
405
406 # dda_name_list = []
407 # dda_num_list = []
408 if len(self.company_info_list) > 0:
409 # tmp_idx = 1
410 self.company_info = self.company_info_list[0]
411 else:
412 # tmp_idx = 0
413 self.company_info = None
414
415 vehicle_info = {}
416 vehicle_field_input = []
417 vehicle_status = vehicleInfo.get('vehicleStatus', '')
418 first_submission_date = self.first_submmison_date
419 vin_no = vehicleInfo.get('vinNo', '')
420 self.vin_no = vin_no
421 # amount = str(vehicleInfo.get('vehiclePrice', '0.0'))
422 amount = str(vehicleInfo.get('vehicleTransactionAmount', '0.0'))
423 self.vehicleTransactionAmount = amount
424 dealer_name_list = vehicleInfo.get('dealer', '').split()
425 dealer_name = '' if len(dealer_name_list) == 0 else dealer_name_list[-1]
426 self.dealer_name = dealer_name
427 issuer_dealer = vehicleInfo.get('fapiaoIssuerDealer', '').strip()
428 # 新车发票----------------------------------------------------------------------------------------------------------
429 if vehicle_status == 'New':
430 vehicle_field_input.append(('vinNo', vin_no))
431 vehicle_field_input.append(('dealer', dealer_name if len(issuer_dealer) == 0 else issuer_dealer))
432 vehicle_field_input.append(('vehicleTransactionAmount', amount))
433
434 if isinstance(self.company_info, tuple):
435 vehicle_field_input.append(
436 (consts.SE_NEW_ADD_FIELD[0], co_name if self.is_cdfl else self.company_info[0])) # 车贷分离
437 vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[1], self.co_id if self.is_cdfl else self.company_info[1])) # 车贷分离
438 else:
439 vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[0], co_name if is_cdfl else main_name)) # 车贷分离
440 vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[1], co_id if is_cdfl else main_id)) # 车贷分离
441 vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[2], first_submission_date))
442 # vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[3], consts.SE_STAMP_VALUE))
443 vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[4], consts.SE_FPL_VALUE))
444 bhsj = float(amount) / 1.13
445 # vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[5], consts.SPLIT_STR.join([
446 # format(bhsj, '.2f'),
447 # format(float(amount) - bhsj, '.2f'),
448 # consts.RESULT_Y
449 # ])))
450 vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[7], format(bhsj, '.2f')))
451 vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[8], format(float(amount) - bhsj, '.2f')))
452 vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[9], consts.RESULT_Y))
453 vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[6], consts.SE_LAYOUT_VALUE))
454 vehicle_field_input.append(("firstSubmmisonDate", self.first_submmison_date))
455 vehicle_field_input.append(("productGroupName", self.product_group_name))
456
457 if self.product_group_name.find('官方认证二手车') == -1 and self.product_group_name.find('非官方认证二手车') == -1:
458 vehicle_info[consts.MVI_EN] = vehicle_field_input
459
460 # 二手车发票、交易凭证、绿本------------------------------------------------------------------------------------------
461 # else:
462 # gb_field_input = [
463 # ('vinNo', vin_no),
464 # ]
465 # gb34_field_input = []
466 # jypz_field_input = []
467 # vehicle_field_input.append(('vinNo', vin_no))
468 # vehicle_field_input.append(('vehicleTransactionAmount', amount))
469 # if isinstance(company_info, tuple):
470 # vehicle_field_input.append(
471 # (consts.SE_NEW_ADD_FIELD[0], co_name if is_cdfl else company_info[0])) # 车贷分离
472 # vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[1], co_id if is_cdfl else company_info[1])) # 车贷分离
473 # jypz_field_input.append((consts.SE_NEW_ADD_FIELD[0], co_name if is_cdfl else company_info[0])) # 车贷分离
474 # jypz_field_input.append((consts.SE_NEW_ADD_FIELD[1], co_id if is_cdfl else company_info[1])) # 车贷分离
475 # gb34_field_input.append((consts.SE_GB_USED_FIELD[0], co_name if is_cdfl else company_info[0])) # 车贷分离
476 # gb34_field_input.append((consts.SE_GB_USED_FIELD[1], co_id if is_cdfl else company_info[1])) # 车贷分离
477 # else:
478 # vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[0], co_name if is_cdfl else main_name)) # 车贷分离
479 # vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[1], co_id if is_cdfl else main_id_all)) # 车贷分离
480 # jypz_field_input.append((consts.SE_NEW_ADD_FIELD[0], co_name if is_cdfl else main_name)) # 车贷分离
481 # jypz_field_input.append((consts.SE_NEW_ADD_FIELD[1], co_id if is_cdfl else main_id_all)) # 车贷分离
482 # gb34_field_input.append((consts.SE_GB_USED_FIELD[0], co_name if is_cdfl else main_name)) # 车贷分离
483 # gb34_field_input.append((consts.SE_GB_USED_FIELD[1], co_id if is_cdfl else main_id_all)) # 车贷分离
484 # gb34_field_input.append((consts.SE_GB_USED_FIELD[2], first_submission_date))
485 # vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[2], first_submission_date))
486 # # vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[3], consts.SE_STAMP_VALUE))
487 # jypz_field_input.append(('dealerName', dealer_name))
488 # jypz_field_input.append(('vinNo', vin_no))
489 # jypz_field_input.append(('vehicleTransactionAmount', amount))
490 # jypz_field_input.append((consts.SE_GB_USED_FIELD[2], first_submission_date))
491 # if fp_group.find('Non OCU Product Group') != -1:
492 # jypz_field_input.append(('type', consts.JYPZ_TYPE_1))
493 # elif fp_group.find('OCU Product Group') != -1:
494 # jypz_field_input.append(('type', consts.JYPZ_TYPE_2))
495 #
496 # vehicle_info[consts.MVC_EN] = gb_field_input
497 # vehicle_info[consts.MVC34_EN] = gb34_field_input
498 # if not detect_list[0]:
499 # vehicle_info[consts.UCI_EN] = vehicle_field_input
500 # if not detect_list[1]:
501 # vehicle_info[consts.JYPZ_EN] = jypz_field_input
502 # if detect_list[0] and detect_list[1]:
503 # vehicle_info[consts.UCI_EN] = vehicle_field_input
504 self.compare_info['vehicleInfo'] = vehicle_info
505
506 def getBankInfo(self, bankInfo, ignore_bank):
507 bank_info = {}
508 bank_name = bankInfo.get('bankName', '')
509 self.bank_name = bank_name
510 account_no = decode_des(bankInfo.get('accountNo', ''), des_key)
511 self.account_no = account_no
512 account_holder_name = bankInfo.get('accountHolderName', '')
513 self.account_holder_name = account_holder_name
514 self.is_gsyh = True if '工商' in bank_name else False
515 bank_verification_status = bankInfo.get('bankVerificationStatus', '')
516 if isinstance(self.company_info, tuple) and self.company_info[0] == account_holder_name:
517 pass
518 elif not ignore_bank:
519 bank_field_input = [
520 ('accountNo', account_no),
521 ('bankName', bank_name),
522 ('type', consts.BC_TYPE_VALUE) # 是否为借记卡
523 ]
524 if bank_verification_status != 'PASS':
525 # pos 银行卡校验失败后需要走ocr校验
526 if bank_verification_status == 'FAIL' or bank_verification_status == 'N/A':
527 bank_field_input.append(('bankVerificationStatus', ''))
528 bank_info[consts.BC_EN] = bank_field_input
529 # DDA------------------------------------------------------------------------------------------------------------
530 # if is_gsyh or not detect_list[-1]:
531 # dda_field_input = [
532 # ('applicationId(1)', last_obj.application_id),
533 # ('applicationId(2)', last_obj.application_id),
534 # ('bankName', bank_name),
535 # ('companyName', consts.HIL_COMPANY_NAME if application_entity in consts.HIL_SET else consts.AFC_COMPANY_NAME),
536 # ('customerName', dda_name),
537 # ('idNum', dda_num),
538 # ('accountHolderName', account_holder_name),
539 # ('accountNo', account_no),
540 # ]
541 # bank_info[consts.DDA_EN] = dda_field_input
542 if len(bank_info) > 0:
543 self.compare_info['bankInfo'] = bank_info
544
545 def getContract(self, quotationtInfo):
546 # ASP -------------------------------------------------------------------------------------------------------
547 asp_list = []
548 is_asp = False
549 insurance_price = None
550 gzs_price = None
551 have_other_asp = False
552 fin_total = 0
553 if str(quotationtInfo.get('associatedServicePrincipal', '0.00')) != '0.00':
554 is_asp = True
555 # for asp_info in cms_info.get('associatedServices', []):
556 for asp_info in quotationtInfo.get('associatedServiceInfo', []):
557 tmp_asp_name = asp_info.get('service')
558 if isinstance(tmp_asp_name, str) and len(tmp_asp_name) > 0:
559 asp_list.append(
560 (
561 tmp_asp_name,
562 asp_info.get('amount', '0.00'),
563 asp_info.get('financedAmount', '0.00')
564 )
565 )
566 fin_total += float(asp_info.get('financedAmount', '0.00'))
567 # 购置税
568 if tmp_asp_name.find(consts.GZS_NAME) != -1:
569 gzs_price = asp_info.get('amount', '0.00')
570 # 保单费合计
571 elif tmp_asp_name.find('机动车辆保险') != -1:
572 insurance_price = asp_info.get('amount', '0.00')
573 else:
574 have_other_asp = True
575
576 asp_list.append(
577 (
578 consts.ASP_SUM_NAME,
579 '',
580 # fin_total,
581 format(fin_total, '.2f'),
582 )
583 )
584
585 # CMS Vehicle Price / 1.13 * 10 %
586 if isinstance(gzs_price, str):
587 try:
588 tmp_gzs_list = [float(self.vehicleTransactionAmount) * 0.1 / 1.13, float(gzs_price)]
589 except Exception as e:
590 tmp_gzs_list = [self.vehicleTransactionAmount, gzs_price]
591 else:
592 tmp_gzs_list = [self.vehicleTransactionAmount, ]
593
594 main_name = main_id_all = main_id = ''
595 for applicant_type in consts.APPLICANT_TYPE_ORDER:
596 if applicant_type in self.main_role_info:
597 main_name, main_id_all, main_id = self.main_role_info[applicant_type][0]
598 # hmh_name, _, hmh_id = main_role_info[applicant_type][0]
599 break
600
601 contract_info = {}
602 if self.application_entity in consts.HIL_SET:
603 # HIL合同 售后回租合同 --------------------------------------------------------------------------------------
604 hil_contract_1_input = [
605 # (pos_consts.SE_HIL_CON_1_FIELD[0], [full_no] if online_sign else full_no),
606 # (pos_consts.SE_HIL_CON_1_FIELD[1], full_no),
607 # (pos_consts.SE_HIL_CON_1_FIELD[2], self.vin_no),
608 # (pos_consts.SE_HIL_CON_1_FIELD[3], self.dealer_name),
609 # (pos_consts.SE_HIL_CON_1_FIELD[4], self.vehicleTransactionAmount),
610 # (pos_consts.SE_HIL_CON_1_FIELD[5],
611 # str(cms_info.get('financialInformation', {}).get('originationPrincipal', '0.0'))),
612 # (pos_consts.SE_HIL_CON_1_FIELD[6], str(quotationtInfo.get('loanTerm', '0'))),
613 # (pos_consts.SE_HIL_CON_1_FIELD[7], schedule_list_str),
614 # (pos_consts.SE_HIL_CON_1_FIELD[11], self.account_no),
615 # (pos_consts.SE_HIL_CON_1_FIELD[12], self.account_holder_name),
616 # (pos_consts.SE_HIL_CON_1_FIELD[13], self.bank_name),
617 ]
618
619 # if is_asp:
620 # # asp各项
621 # hil_contract_1_input.append((consts.SE_HIL_CON_1_FIELD[8], asp_list))
622 # # 购置税校验
623 # if isinstance(gzs_price, str):
624 # hil_contract_1_input.append(
625 # (consts.SE_HIL_CON_1_FIELD[9], tmp_gzs_list))
626 # # 非购置税非车辆保险的其他asp
627 # if have_other_asp:
628 # hil_contract_1_input.append((consts.SE_HIL_CON_1_FIELD[15], 'N'))
629 #
630 # if isinstance(self.company_info, tuple):
631 # if self.is_cdfl:
632 # hil_contract_1_input.append((consts.SE_HIL_CON_1_FIELD[14], self.company_info[2]))
633 # else:
634 # hil_contract_1_input.append((consts.SE_HIL_CON_1_FIELD[10], self.company_info[2]))
635 # contract_info[consts.HIL_CONTRACT_1_EN] = hil_contract_1_input
636
637 # HIL合同 车辆租赁抵押合同 --------------------------------------------------------------------------------------
638 hil_contract_2_input = [
639 (pos_consts.SE_HIL_CON_2_FIELD[0], self.application_id),
640 (pos_consts.SE_HIL_CON_2_FIELD[1], self.vin_no),
641 ('文档', '文档'),
642 ]
643 contract_info[consts.HIL_CONTRACT_2_EN] = hil_contract_2_input
644 self.compare_info['contract'] = contract_info
645 else:
646 # AFC合同------------------------------------------------------------------------------------------------------
647 vehicle_principal_str = str(quotationtInfo.get('vehiclePrincipal', '0.0'))
648 afc_contract_input = []
649 # if is_asp:
650 # afc_contract_input = [
651 # (consts.SE_AFC_CON_FIELD[0], full_no),
652 # ]
653 # else:
654 # afc_contract_input = [
655 # (consts.SE_AFC_CON_FIELD[23], full_no),
656 # ]
657
658 # afc_contract_input.extend([
659 # (consts.SE_AFC_CON_FIELD[1], self.vehicleTransactionAmount),
660 # (consts.SE_AFC_CON_FIELD[2], self.vin_no),
661 # (consts.SE_AFC_CON_FIELD[3],
662 # str(cms_info.get('financialInformation', {}).get('originationPrincipal', '0.0'))),
663 # (consts.SE_AFC_CON_FIELD[4], str(cms_info.get('terms', '0'))),
664 # (consts.SE_AFC_CON_FIELD[5], vehicle_principal_str),
665 # (consts.SE_AFC_CON_FIELD[6],
666 # str(quotationtInfo.get('associatedServicePrincipal', '0.0'))),
667 # (consts.SE_AFC_CON_FIELD[7], self.vehicleTransactionAmount),
668 # (consts.SE_AFC_CON_FIELD[8], self.vin_no),
669 # (consts.SE_AFC_CON_FIELD[9], self.dealer_name),
670 # (consts.SE_AFC_CON_FIELD[10],
671 # str(cms_info.get('financialInformation', {}).get('originationPrincipal', '0.0'))),
672 # (consts.SE_AFC_CON_FIELD[11], vehicle_principal_str),
673 # (consts.SE_AFC_CON_FIELD[12],
674 # str(cms_info.get('financialInformation', {}).get('associatedServicePrincipal', '0.0'))),
675 # (consts.SE_AFC_CON_FIELD[13], str(cms_info.get('terms', '0'))),
676 # (consts.SE_AFC_CON_FIELD[14], self.account_no),
677 # (consts.SE_AFC_CON_FIELD[15], self.account_holder_name),
678 # (consts.SE_AFC_CON_FIELD[16], self.bank_name),
679 # (consts.SE_AFC_CON_FIELD[17], schedule_list_str),
680 # ])
681
682 # if is_asp:
683 # afc_contract_input.append((consts.SE_AFC_CON_FIELD[20], asp_list))
684 # afc_contract_input.append((consts.SE_AFC_CON_FIELD[22], asp_list))
685 # # 购置税校验
686 # if isinstance(gzs_price, str):
687 # afc_contract_input.append(
688 # (consts.SE_AFC_CON_FIELD[21], tmp_gzs_list))
689 # # 非购置税非车辆保险的其他asp
690 # if have_other_asp:
691 # afc_contract_input.append((consts.SE_AFC_CON_FIELD[24], 'N'))
692 # else:
693 # afc_contract_input.pop(5)
694 # afc_contract_input.pop(5)
695 # afc_contract_input.pop(9)
696 # afc_contract_input.pop(9)
697
698 # contract_info[consts.AFC_CONTRACT_EN] = afc_contract_input
699 self.compare_info['contract'] = contract_info
700
701 def getOther(self, quotationtInfo, insurance_info):
702 main_name = main_id_all = main_id = ''
703 for applicant_type in consts.APPLICANT_TYPE_ORDER:
704 if applicant_type in self.main_role_info:
705 main_name, main_id_all, main_id = self.main_role_info[applicant_type][0]
706 # hmh_name, _, hmh_id = main_role_info[applicant_type][0]
707 break
708
709 other_info = {}
710 if quotationtInfo.get('mortgageType', '') == 'MOTGF':
711 hmh_field_input = [
712 (consts.SE_HMH_FIELD[0], self.customer_name),
713 (consts.SE_HMH_FIELD[1], self.id_num),
714 (consts.SE_HMH_FIELD[2], self.application_id),
715 (consts.SE_HMH_FIELD[3], self.application_entity),
716 (consts.SE_HMH_FIELD[4], consts.SE_STAMP_VALUE),
717 ('文档', '')
718 ]
719 other_info[consts.HMH_EN] = hmh_field_input
720
721 # 保险
722 if insurance_info.get('insuranceType') != 'Waive Insurance' and insurance_info.get('insuranceType') != 'Insurance After Check':
723 if insurance_info.get('insuranceType') == 'Comprehensive Insurance':
724 other_info[consts.BD_EN] = [
725 (consts.SE_BD_FIELD[0], self.customer_name),
726 (consts.SE_BD_FIELD[1], self.id_num)
727 (consts.SE_BD_FIELD[2], self.vin_no)
728 ('文档', '')
729 ]
730 if len(other_info) > 0:
731 self.compare_info['other'] = other_info
732
733
734 class PosCompare:
735 @staticmethod
736 def ca_compare(pos_content, ocr_res_dict):
737 compare_info_result = CompareInfo(pos_content).get()
738 compare_result, total_fields, failed_count = ca_compare_process(compare_info_result, ocr_res_dict)
739 return compare_result
740
741 @staticmethod
742 def se_compare(pos_content, ocr_res_dict, id_res_list=None):
743 compare_info_result = CompareInfo(pos_content).get()
744 compare_result, total_fields, failed_count, successful_at_this_level, failure_reason_str, \
745 cn_failure_reason_str, bs_failure_reason_str, rpa_failure_reason = se_compare_process(
746 compare_info_result.compare_info, ocr_res_dict, compare_info_result.is_gsyh, False, id_res_list)
747 return compare_result
1 from common.tools.comparison import cp
2 import os
3 from pos import pos_consts
4 from apps.doc import consts
5 import json
6 from apps.doc.named_enum import RequestTeam, RequestTrigger, ProcessName, ErrorType
7 import time
8
9 empty_str = ''
10 empty_error_type = 1000
11
12
13 class SECompare:
14 @staticmethod
15 def se_mvc34_compare(license_en, ocr_res_dict, field_list):
16 ocr_field, compare_logic, _ = pos_consts.SE_COMPARE_FIELD[license_en]
17 ocr_res_str = ocr_res_dict.get(ocr_field)
18
19 is_find = False
20 result_field_list = []
21 field_img_path_dict = dict()
22
23 if ocr_res_str is not None:
24 ocr_res_list = json.loads(ocr_res_str)
25 length = len(ocr_res_list)
26
27 page34_date_dict = dict()
28 first_res = None
29 for res_idx in range(length - 1, -1, -1):
30 if consts.TRANSFER_DATE in ocr_res_list[res_idx]:
31 img_path = ocr_res_list[res_idx].get(consts.IMG_PATH_KEY_2, '')
32 section_img_path = ocr_res_list[res_idx].get(consts.SECTION_IMG_PATH_KEY_2, '')
33 for idx, transfer_date in enumerate(ocr_res_list[res_idx].get(consts.TRANSFER_DATE, [])):
34 try:
35 transfer_name = ocr_res_list[res_idx].get(consts.TRANSFER_NAME, [])[idx]
36 except Exception as e:
37 transfer_name = empty_str
38 try:
39 transfer_num = ocr_res_list[res_idx].get(consts.TRANSFER_NUM, [])[idx]
40 except Exception as e:
41 transfer_num = empty_str
42 try:
43 position_info_date = ocr_res_list[res_idx].get(consts.ALL_POSITION_KEY_2, dict()).get(
44 consts.TRANSFER_DATE, [])[idx]
45 except Exception as e:
46 position_info_date = {}
47 try:
48 position_info_name = ocr_res_list[res_idx].get(consts.ALL_POSITION_KEY_2, dict()).get(
49 consts.TRANSFER_NAME, [])[idx]
50 except Exception as e:
51 position_info_name = {}
52 try:
53 position_info_num = ocr_res_list[res_idx].get(consts.ALL_POSITION_KEY_2, dict()).get(
54 consts.TRANSFER_NUM, [])[idx]
55 except Exception as e:
56 position_info_num = {}
57 core_info = {
58 consts.TRANSFER_NAME: transfer_name,
59 consts.TRANSFER_NUM: transfer_num,
60 consts.TRANSFER_DATE: transfer_date,
61 consts.IMG_PATH_KEY_2: img_path,
62 consts.SECTION_IMG_PATH_KEY_2: section_img_path,
63 consts.ALL_POSITION_KEY: {
64 consts.TRANSFER_NAME: position_info_name,
65 consts.TRANSFER_NUM: position_info_num,
66 consts.TRANSFER_DATE: position_info_date,
67 },
68 }
69 page34_date_dict.setdefault(transfer_date, []).append(core_info)
70 if first_res is None:
71 first_res = core_info
72
73 max_date = None
74 for date_tmp in page34_date_dict.keys():
75 try:
76 max_date_part = time.strptime(date_tmp, "%Y-%m-%d")
77 except Exception as e:
78 pass
79 else:
80 if max_date is None or max_date_part > max_date:
81 max_date = max_date_part
82
83 if max_date is not None or first_res is not None:
84 is_find = True
85 ocr_res = first_res if max_date is None else page34_date_dict[time.strftime('%Y-%m-%d', max_date)][0]
86 failed_field = []
87 base_img_path = ocr_res.get(consts.IMG_PATH_KEY_2, '')
88 for name, value in field_list:
89 ocr_str = ocr_res.get(compare_logic[name][0])
90 if not isinstance(ocr_str, str):
91 result = consts.RESULT_N
92 ocr_str = empty_str
93 else:
94 result = getattr(cp, compare_logic[name][1])(value, ocr_str, **compare_logic[name][2])
95 img_path = base_img_path if result == consts.RESULT_N else empty_str
96 error_type = empty_error_type if result == consts.RESULT_Y else ErrorType.OCR.value
97 result_field_list.append(
98 (name, value, result, ocr_str, img_path, error_type, compare_logic[name][3]))
99
100 if result == consts.RESULT_N:
101 failed_field.append(name)
102
103 # section_img_path = ocr_res.get(consts.SECTION_IMG_PATH_KEY_2, '')
104 # if len(failed_field) > 0 and os.path.exists(section_img_path):
105 # info = ocr_res.get(consts.ALL_POSITION_KEY, {})
106 # try:
107 # last_img = img_process(section_img_path, {}, 0)
108 # except Exception as e:
109 # for field in failed_field:
110 # field_img_path_dict[field] = base_img_path
111 # else:
112 # pre, suf = os.path.splitext(section_img_path)
113 # for field in failed_field:
114 # try:
115 # res_field = compare_logic[field][0]
116 # is_valid, coord_tuple = field_build_coordinates(info.get(res_field, {}))
117 # if is_valid:
118 # save_path = '{0}_{1}{2}'.format(pre, field, suf)
119 # field_img = last_img[coord_tuple[0]:coord_tuple[1], coord_tuple[2]:coord_tuple[3],
120 # :]
121 # cv2.imwrite(save_path, field_img)
122 # field_img_path_dict[field] = save_path
123 # else:
124 # field_img_path_dict[field] = base_img_path
125 # except Exception as e:
126 # field_img_path_dict[field] = base_img_path
127
128 if not is_find:
129 for name, value in field_list:
130 result_field_list.append((name, value, consts.RESULT_N, empty_str, empty_str, ErrorType.NF.value,
131 '{0}未找到'.format(license_en)))
132
133 return result_field_list, field_img_path_dict
134
135 @staticmethod
136 def se_contract_compare(license_en, ocr_res_dict, strip_list, is_gsyh):
137 ocr_field, compare_logic, _ = pos_consts.SE_COMPARE_FIELD[license_en]
138 ocr_res_str = ocr_res_dict.get(ocr_field)
139
140 result_field_list = []
141 field_img_path_dict = dict()
142
143 ocr_res = dict()
144 if ocr_res_str is not None:
145 ocr_res_list = json.loads(ocr_res_str)
146 ocr_res = ocr_res_list.pop()
147
148 for name, value in strip_list:
149 # 购置税校验
150 # if name == consts.SE_AFC_CON_FIELD[21]:
151 # if len(value) == 3:
152 # reason = []
153 # gzs_verify = value[1] >= value[2]
154 # if gzs_verify:
155 # if value[0] == consts.GZS_STATUS[0]:
156 # reason.append(consts.GZS_REASON_1)
157 # result = consts.RESULT_N
158 # else:
159 # result = consts.RESULT_Y
160 # else:
161 # if value[0] == consts.GZS_STATUS[0]:
162 # reason.append(consts.GZS_REASON_1)
163 # result = consts.RESULT_N
164 # reason.append(consts.GZS_REASON_2)
165 # else:
166 # result = consts.RESULT_N
167 # reason = consts.GZS_REASON_1
168 # ocr_str = empty_str
169 # else:
170
171 if name == consts.SE_HIL_CON_1_FIELD[9] or name == consts.SE_HIL_CON_1_FIELD[15] or \
172 name == consts.SE_AFC_CON_FIELD[21] or name == consts.SE_AFC_CON_FIELD[24]:
173 ocr_str_or_list = ''
174 else:
175 ocr_str_or_list = ocr_res.get(compare_logic[name][0])
176
177 # 招商银行特殊
178 # if ocr_str_or_list is None and license_en == consts.AFC_CONTRACT_EN \
179 # and is_gsyh is True and name in consts.CON_BANK_FIELD:
180 # result = consts.RESULT_Y
181 # ocr_str = empty_str
182 # reason = compare_logic[name][3]
183 # 见证人日期
184 if name == consts.SE_AFC_CON_FIELD[19]:
185 if not isinstance(ocr_str_or_list, str) or len(ocr_str_or_list) == 0:
186 result = consts.RESULT_N
187 ocr_str = empty_str
188 else:
189 is_find_date = False
190 all_date_list = [ocr_str_or_list]
191 for date_name in consts.AFC_HT_DATE_FIELDS:
192 all_date_list.append(ocr_res.get(compare_logic[date_name][0], ''))
193 if not is_find_date and ocr_str_or_list == ocr_res.get(compare_logic[date_name][0], ''):
194 is_find_date = True
195 result = consts.RESULT_Y if is_find_date else consts.RESULT_N
196 ocr_str = json.dumps(all_date_list, ensure_ascii=False)
197 reason = compare_logic[name][3]
198 elif isinstance(ocr_str_or_list, str) or isinstance(ocr_str_or_list, list):
199 # if is_gsyh is True and name in consts.CON_BANK_FIELD:
200 # update_args = {'is_gsyh': is_gsyh}
201 # for k, v in compare_logic[name][2].items():
202 # update_args[k] = v
203 # else:
204 # update_args = compare_logic[name][2]
205 if isinstance(ocr_str_or_list, list):
206 # no-asp 合同编号-每页(no-asp)
207 if name == consts.SE_AFC_CON_FIELD[23]:
208 ocr_str_or_list.pop()
209 ocr_str = json.dumps(ocr_str_or_list, ensure_ascii=False)
210 else:
211 ocr_str_or_list = ocr_str_or_list.strip()
212 ocr_str = ocr_str_or_list
213 result = getattr(cp, compare_logic[name][1])(value, ocr_str_or_list, **compare_logic[name][2])
214 reason = compare_logic[name][3]
215 else:
216 result = consts.RESULT_N
217 ocr_str = empty_str
218 reason = compare_logic[name][3]
219
220 # img_path = empty_str
221 if name not in compare_logic:
222 img_path = empty_str
223 else:
224 img_path = ocr_res.get(consts.IMG_PATH_KEY, {}).get(compare_logic[name][0],
225 empty_str) if result == consts.RESULT_N else empty_str
226 error_type = empty_error_type if result == consts.RESULT_Y else ErrorType.OCR.value
227 if isinstance(value, list):
228 value = json.dumps(value, ensure_ascii=False)
229 result_field_list.append((name, value, result, ocr_str, img_path, error_type, reason))
230 else:
231 for name, value in strip_list:
232 if isinstance(value, list):
233 value = json.dumps(value, ensure_ascii=False)
234 result_field_list.append((name, value, consts.RESULT_N, empty_str, empty_str, ErrorType.NF.value,
235 '{0}未找到'.format(license_en)))
236
237 # if ocr_res_str is not None:
238 # img_map = {}
239 # for name, _, result, _, img_path, _, _ in result_field_list:
240 # if result == consts.RESULT_N:
241 # img_map.setdefault(img_path, []).append(name)
242 # for path, field_list in img_map.items():
243 # if os.path.exists(path):
244 # pre, suf = os.path.splitext(path)
245 # last_img = cv2.imread(path)
246 # for field_idx, field in enumerate(field_list):
247 # try:
248 # save_path = '{0}_{1}{2}'.format(pre, str(field_idx), suf)
249 # section_position_list = ocr_res.get(consts.ALL_POSITION_KEY, {}).get(field, [])
250 # if isinstance(section_position_list, list) and len(section_position_list) == 4:
251 # field_img = last_img[section_position_list[1]: section_position_list[3],
252 # section_position_list[0]: section_position_list[2], :]
253 # cv2.imwrite(save_path, field_img)
254 # field_img_path_dict[field] = save_path
255 # else:
256 # field_img_path_dict[field] = path
257 # except Exception as e:
258 # field_img_path_dict[field] = path
259
260 return result_field_list, field_img_path_dict
261
262 @staticmethod
263 def se_bs_compare(license_en, ocr_res_dict, strip_list, is_auto):
264 # 主共借至少提供一个
265 # 有担保人,担保人必须提供。主共借没有时,修改comment:人工查看担保人亲属关系
266
267 if is_auto:
268 ocr_field, compare_logic, _ = consts.SE_COMPARE_FIELD_AUTO[license_en]
269 else:
270 ocr_field, compare_logic, _ = pos_consts.SE_COMPARE_FIELD[license_en]
271 ocr_res_str = ocr_res_dict.get(ocr_field)
272
273 result_field_list = []
274 field_img_path_dict = dict()
275
276 if ocr_res_str is not None:
277 pre_field_list = strip_list[:3]
278 dbr1_field_list = strip_list[3:6]
279 dbr2_field_list = strip_list[6:]
280
281 ocr_res_list = json.loads(ocr_res_str)
282 # length = len(ocr_res_list)
283
284 # 主共借人
285 pre_best_res = {}
286 max_correct_count = 0
287 verify_list = []
288 verify_false_idx_list = []
289
290 for tmp_idx, ocr_res in enumerate(ocr_res_list):
291 correct_count = 0
292 pre_tmp_res_part = {}
293 verify_bool = ocr_res.get('verify', True)
294 verify_list.append(verify_bool)
295 if not verify_bool:
296 verify_false_idx_list.append(str(tmp_idx + 1))
297 for idx, (name, value) in enumerate(pre_field_list):
298 ocr_str_or_list = ocr_res.get(compare_logic[name][0])
299 if isinstance(ocr_str_or_list, str) or isinstance(ocr_str_or_list, list) \
300 or isinstance(ocr_str_or_list, int):
301 result = getattr(cp, compare_logic[name][1])(value, ocr_str_or_list, **compare_logic[name][2])
302 if isinstance(ocr_str_or_list, list):
303 ocr_str = json.dumps(ocr_str_or_list, ensure_ascii=False)
304 else:
305 ocr_str = ocr_str_or_list
306 reason = compare_logic[name][3]
307 else:
308 result = consts.RESULT_N
309 ocr_str = empty_str
310 reason = compare_logic[name][3]
311
312 if idx == 0 and result == consts.RESULT_N:
313 break
314
315 if result == consts.RESULT_Y:
316 correct_count += 1
317 pre_tmp_res_part[name] = (result, ocr_str, reason)
318
319 if correct_count > 0 and correct_count >= max_correct_count:
320 max_correct_count = correct_count
321 pre_best_res = pre_tmp_res_part
322
323 # 真伪
324 if not is_auto:
325 name = '真伪'
326 result = consts.RESULT_Y if all(verify_list) else consts.RESULT_N
327 reason = '第{0}份银行流水疑似造假,需人工核查'.format('、'.join(verify_false_idx_list))
328 result_field_list.append((name, empty_str, result, json.dumps(verify_list, ensure_ascii=False),
329 empty_str, empty_error_type, reason))
330
331 # 担保人1
332 dbr1_best_res = {}
333 if len(dbr1_field_list) > 0:
334 max_correct_count = 0
335 for ocr_res in ocr_res_list:
336 correct_count = 0
337 dbr1_tmp_res_part = {}
338 for idx, (name, value) in enumerate(dbr1_field_list):
339 ocr_str_or_list = ocr_res.get(compare_logic[name][0])
340 if isinstance(ocr_str_or_list, str) or isinstance(ocr_str_or_list, list) or isinstance(
341 ocr_str_or_list, int):
342 result = getattr(cp, compare_logic[name][1])(value, ocr_str_or_list,
343 **compare_logic[name][2])
344 if isinstance(ocr_str_or_list, list):
345 ocr_str = json.dumps(ocr_str_or_list, ensure_ascii=False)
346 else:
347 ocr_str = ocr_str_or_list
348 reason = compare_logic[name][3]
349 else:
350 result = consts.RESULT_N
351 ocr_str = empty_str
352 reason = compare_logic[name][3]
353
354 if idx == 0 and result == consts.RESULT_N:
355 break
356
357 if result == consts.RESULT_Y:
358 correct_count += 1
359 dbr1_tmp_res_part[name] = (result, ocr_str, reason)
360
361 if correct_count > 0 and correct_count >= max_correct_count:
362 max_correct_count = correct_count
363 dbr1_best_res = dbr1_tmp_res_part
364
365 # 担保人2
366 dbr2_best_res = {}
367 if len(dbr1_field_list) > 0:
368 max_correct_count = 0
369 for ocr_res in ocr_res_list:
370 correct_count = 0
371 dbr2_tmp_res_part = {}
372 for idx, (name, value) in enumerate(dbr2_field_list):
373 ocr_str_or_list = ocr_res.get(compare_logic[name][0])
374 if isinstance(ocr_str_or_list, str) or isinstance(ocr_str_or_list, list) or isinstance(
375 ocr_str_or_list, int):
376 result = getattr(cp, compare_logic[name][1])(value, ocr_str_or_list,
377 **compare_logic[name][2])
378 if isinstance(ocr_str_or_list, list):
379 ocr_str = json.dumps(ocr_str_or_list, ensure_ascii=False)
380 else:
381 ocr_str = ocr_str_or_list
382 reason = compare_logic[name][3]
383 else:
384 result = consts.RESULT_N
385 ocr_str = empty_str
386 reason = compare_logic[name][3]
387
388 if idx == 0 and result == consts.RESULT_N:
389 break
390
391 if result == consts.RESULT_Y:
392 correct_count += 1
393 dbr2_tmp_res_part[name] = (result, ocr_str, reason)
394
395 if correct_count > 0 and correct_count >= max_correct_count:
396 max_correct_count = correct_count
397 dbr2_best_res = dbr2_tmp_res_part
398
399 dbr_ok = False
400 # 有担保人
401 if len(dbr1_field_list) > 0:
402 # 有担保人12
403 if len(dbr2_field_list) > 0:
404 if len(dbr1_best_res) > 0 and len(dbr2_best_res) > 0:
405 dbr_ok = True
406 # 有担保人1
407 else:
408 if len(dbr1_best_res) > 0:
409 dbr_ok = True
410 # 无担保人
411 # else:
412 # pass
413
414 best_res_empty = False
415 if len(pre_best_res) == 0 and len(dbr1_best_res) == 0 and len(dbr2_best_res) == 0:
416 best_res_empty = True
417
418 for name, value in pre_field_list:
419 if len(pre_best_res) > 0:
420 result, ocr_str, reason = pre_best_res[name]
421 else:
422 result = consts.RESULT_N
423 ocr_str = empty_str
424 if best_res_empty:
425 reason = consts.SPECIAL_REASON_3
426 elif dbr_ok: # 有担保人且担保人都提供了流水
427 reason = consts.SPECIAL_REASON
428 else:
429 reason = compare_logic[pre_field_list[0][0]][3]
430 img_path = empty_str
431 error_type = empty_error_type if result == consts.RESULT_Y else ErrorType.OCR.value
432 if isinstance(value, list):
433 value = json.dumps(value, ensure_ascii=False)
434 result_field_list.append((name, value, result, ocr_str, img_path, error_type, reason))
435
436 if len(dbr1_field_list) > 0:
437 for name, value in dbr1_field_list:
438 if len(dbr1_best_res) > 0:
439 result, ocr_str, reason = dbr1_best_res[name]
440 else:
441 result = consts.RESULT_N
442 ocr_str = empty_str
443 if best_res_empty:
444 reason = consts.SPECIAL_REASON_3
445 elif len(pre_best_res) > 0:
446 reason = consts.SPECIAL_REASON_2
447 else:
448 reason = compare_logic[dbr1_field_list[0][0]][3]
449 img_path = empty_str
450 error_type = empty_error_type if result == consts.RESULT_Y else ErrorType.OCR.value
451 if isinstance(value, list):
452 value = json.dumps(value, ensure_ascii=False)
453 result_field_list.append((name, value, result, ocr_str, img_path, error_type, reason))
454
455 if len(dbr2_field_list) > 0:
456 for name, value in dbr2_field_list:
457 if len(dbr2_best_res) > 0:
458 result, ocr_str, reason = dbr2_best_res[name]
459 else:
460 result = consts.RESULT_N
461 ocr_str = empty_str
462 if best_res_empty:
463 reason = consts.SPECIAL_REASON_3
464 elif len(pre_best_res) > 0:
465 reason = consts.SPECIAL_REASON_2
466 else:
467 reason = compare_logic[dbr2_field_list[0][0]][3]
468 img_path = empty_str
469 error_type = empty_error_type if result == consts.RESULT_Y else ErrorType.OCR.value
470 if isinstance(value, list):
471 value = json.dumps(value, ensure_ascii=False)
472 result_field_list.append((name, value, result, ocr_str, img_path, error_type, reason))
473
474 else:
475 for name, value in strip_list:
476 if isinstance(value, list):
477 value = json.dumps(value, ensure_ascii=False)
478 result_field_list.append((name, value, consts.RESULT_N, empty_str, empty_str, ErrorType.NF.value,
479 consts.SPECIAL_REASON_3))
480
481 return result_field_list, field_img_path_dict
482
483 @staticmethod
484 def se_compare_license_id(license_en, id_res_list, field_list):
485 ocr_field, compare_logic, special_expiry_date = pos_consts.SE_COMPARE_FIELD[license_en]
486
487 is_find = False
488 no_ocr_result = True
489 special_expiry_date_slice = False
490 result_field_list = []
491 section_img_info = dict()
492 field_img_path_dict = dict()
493
494 # ocr_res_str = ocr_res_dict.get(ocr_field)
495 for ocr_res_str in id_res_list:
496 if is_find:
497 break
498
499 if ocr_res_str is not None:
500 no_ocr_result = False
501
502 ocr_res_list = json.loads(ocr_res_str)
503
504 # 3/4页去除
505 # if ocr_field == consts.MVC_OCR_FIELD:
506 # tmp_list = []
507 # for res in ocr_res_list:
508 # if compare_logic['vinNo'][0] in res:
509 # tmp_list.append(res)
510 # ocr_res_list = tmp_list
511
512 length = len(ocr_res_list)
513
514 # 身份证、居住证 过期期限特殊处理
515 if special_expiry_date:
516 expiry_dates = dict()
517 key = compare_logic.get('idExpiryDate')[0]
518 for date_tmp_idx, ocr_res in enumerate(ocr_res_list):
519 if key in ocr_res:
520 expiry_dates[ocr_res[key]] = (ocr_res.get(consts.IMG_PATH_KEY_2, ''), date_tmp_idx)
521 else:
522 expiry_dates = dict()
523
524 for res_idx in range(length - 1, -1, -1):
525 if is_find:
526 break
527
528 for idx, (name, value) in enumerate(field_list):
529 # if ocr_field == consts.MVI_OCR_FIELD and name == consts.SE_NEW_ADD_FIELD[9]:
530 # ocr_str = getattr(cp, consts.ZW_METHOD)(
531 # ocr_res_list[res_idx].get(consts.LOWER_AMOUNT_FIELD, ''),
532 # ocr_res_list[res_idx].get(consts.UPPER_AMOUNT_FIELD, ''),
533 # )
534 # else:
535 ocr_str = ocr_res_list[res_idx].get(compare_logic[name][0])
536 if not isinstance(ocr_str, str):
537 result = consts.RESULT_N
538 ocr_str = empty_str
539 no_key = True
540 else:
541 result = getattr(cp, compare_logic[name][1])(value, ocr_str, **compare_logic[name][2])
542 no_key = False
543
544 if idx == 0 and result == consts.RESULT_N and length > 1:
545 break
546
547 is_find = True
548 section_img_info[consts.SECTION_IMG_PATH_KEY] = ocr_res_list[res_idx].get(
549 consts.SECTION_IMG_PATH_KEY, '')
550 section_img_info[consts.ALL_POSITION_KEY] = ocr_res_list[res_idx].get(consts.ALL_POSITION_KEY,
551 {})
552 if special_expiry_date:
553 section_img_info[consts.SECTION_IMG_PATH_KEY_2] = ocr_res_list[res_idx].get(
554 consts.SECTION_IMG_PATH_KEY_2, '')
555 section_img_info[consts.ALL_POSITION_KEY_2] = ocr_res_list[res_idx].get(
556 consts.ALL_POSITION_KEY_2, {})
557
558 # 过期期限特殊处理
559 if special_expiry_date and name == 'idExpiryDate' and result == consts.RESULT_N:
560 if no_key:
561 if len(expiry_dates) == 0:
562 ocr_str = empty_str
563 result = consts.RESULT_N
564 img_path = empty_str
565 else:
566 for expiry_date, (date_img_path, date_res_idx) in expiry_dates.items():
567 expiry_date_res = getattr(cp, compare_logic[name][1])(value, expiry_date,
568 **compare_logic[name][2])
569 if expiry_date_res == consts.RESULT_N:
570 ocr_str = expiry_date
571 img_path = date_img_path
572 special_expiry_date_slice = True
573 section_img_info[consts.SECTION_IMG_PATH_KEY_2] = ocr_res_list[
574 date_res_idx].get(
575 consts.SECTION_IMG_PATH_KEY_2, '')
576 section_img_info[consts.ALL_POSITION_KEY_2] = ocr_res_list[
577 date_res_idx].get(
578 consts.ALL_POSITION_KEY_2, {})
579 break
580 else:
581 ocr_str = empty_str
582 result = consts.RESULT_Y
583 img_path = empty_str
584 else:
585 img_path = ocr_res_list[res_idx].get(consts.IMG_PATH_KEY_2, '')
586 special_expiry_date_slice = True
587 else:
588 img_path = ocr_res_list[res_idx].get(consts.IMG_PATH_KEY,
589 '') if result == consts.RESULT_N else empty_str
590 if isinstance(value, list):
591 value = json.dumps(value, ensure_ascii=False)
592 error_type = empty_error_type if result == consts.RESULT_Y else ErrorType.OCR.value
593 result_field_list.append(
594 (name, value, result, ocr_str, img_path, error_type, compare_logic[name][3]))
595
596 if not is_find:
597 for name, value in field_list:
598 if isinstance(value, list):
599 value = json.dumps(value, ensure_ascii=False)
600 no_find_str = consts.DDA_NO_FIND if license_en == consts.DDA_EN else '{0}未找到'.format(license_en)
601 result_field_list.append(
602 (name, value, consts.RESULT_N, empty_str, empty_str, ErrorType.NF.value, no_find_str))
603
604 # if is_find:
605 # if special_expiry_date_slice:
606 # special_section_img_path = section_img_info.get(consts.SECTION_IMG_PATH_KEY_2, '')
607 # if os.path.exists(special_section_img_path):
608 # field = 'idExpiryDate'
609 # special_info = section_img_info.get(consts.ALL_POSITION_KEY_2, {})
610 # special_section_position = special_info.get(consts.POSITION_KEY, {})
611 # special_section_angle = special_info.get(consts.ANGLE_KEY, 0)
612 # try:
613 # last_img = img_process(special_section_img_path, special_section_position,
614 # special_section_angle)
615 # except Exception as e:
616 # field_img_path_dict[field] = special_section_img_path
617 # else:
618 # pre, suf = os.path.splitext(special_section_img_path)
619 # try:
620 # res_field = compare_logic[field][0]
621 # is_valid, coord_tuple = field_build_coordinates(special_info.get(res_field, {}))
622 # if is_valid:
623 # save_path = '{0}_{1}{2}'.format(pre, field, suf)
624 # field_img = last_img[coord_tuple[0]:coord_tuple[1], coord_tuple[2]:coord_tuple[3], :]
625 # cv2.imwrite(save_path, field_img)
626 # field_img_path_dict[field] = save_path
627 # else:
628 # field_img_path_dict[field] = special_section_img_path
629 # except Exception as e:
630 # field_img_path_dict[field] = special_section_img_path
631 #
632 # section_img_path = section_img_info.get(consts.SECTION_IMG_PATH_KEY, '')
633 # if os.path.exists(section_img_path):
634 # failed_field = []
635 # base_img_path = empty_str
636 # for name, _, result, _, img_path, _, _ in result_field_list:
637 # if result == consts.RESULT_N:
638 # if special_expiry_date_slice and name == 'idExpiryDate':
639 # continue
640 # failed_field.append(name)
641 # if base_img_path == empty_str:
642 # base_img_path = img_path
643 # if len(failed_field) > 0:
644 # info = section_img_info.get(consts.ALL_POSITION_KEY, {})
645 # section_position = info.get(consts.POSITION_KEY, {})
646 # section_angle = info.get(consts.ANGLE_KEY, 0)
647 # try:
648 # last_img = img_process(section_img_path, section_position, section_angle)
649 # except Exception as e:
650 # for field in failed_field:
651 # field_img_path_dict[field] = base_img_path
652 # else:
653 # pre, suf = os.path.splitext(section_img_path)
654 # for field in failed_field:
655 # try:
656 # res_field = compare_logic[field][0]
657 # is_valid, coord_tuple = field_build_coordinates(info.get(res_field, {}))
658 # if is_valid:
659 # save_path = '{0}_{1}{2}'.format(pre, field, suf)
660 # field_img = last_img[coord_tuple[0]:coord_tuple[1], coord_tuple[2]:coord_tuple[3],
661 # :]
662 # cv2.imwrite(save_path, field_img)
663 # field_img_path_dict[field] = save_path
664 # else:
665 # field_img_path_dict[field] = base_img_path
666 # except Exception as e:
667 # field_img_path_dict[field] = base_img_path
668
669 return result_field_list, no_ocr_result, field_img_path_dict
670
671 @staticmethod
672 def se_compare_license(license_en, ocr_res_dict, field_list):
673 ocr_field, compare_logic, special_expiry_date = pos_consts.SE_COMPARE_FIELD[license_en]
674
675 is_find = False
676 no_ocr_result = False
677 special_expiry_date_slice = False
678 result_field_list = []
679 section_img_info = dict()
680 field_img_path_dict = dict()
681 ocr_res_str = ocr_res_dict.get(ocr_field)
682
683 if ocr_res_str is not None:
684 ocr_res_list = json.loads(ocr_res_str)
685
686 # 3/4页去除
687 if ocr_field == consts.MVC_OCR_FIELD:
688 tmp_list = []
689 for res in ocr_res_list:
690 if compare_logic['vinNo'][0] in res:
691 tmp_list.append(res)
692 ocr_res_list = tmp_list
693
694 length = len(ocr_res_list)
695
696 # 身份证、居住证 过期期限特殊处理
697 if special_expiry_date:
698 expiry_dates = dict()
699 key = compare_logic.get('idExpiryDate')[0]
700 for date_tmp_idx, ocr_res in enumerate(ocr_res_list):
701 if key in ocr_res:
702 expiry_dates[ocr_res[key]] = (ocr_res.get(consts.IMG_PATH_KEY_2, ''), date_tmp_idx)
703 else:
704 expiry_dates = dict()
705
706 for res_idx in range(length - 1, -1, -1):
707 if is_find:
708 break
709
710 new_invoice_result = None
711 for idx, (name, value) in enumerate(field_list):
712 # 二手车交易凭证 日期
713 if ocr_field == consts.JYPZ_OCR_FIELD and name == consts.SE_GB_USED_FIELD[2]:
714 date_1 = ocr_res_list[res_idx].get(consts.JYPZ_DATE_FIELD_1, '')
715 if len(date_1) > 0:
716 date_2 = date_3 = ''
717 else:
718 date_1 = ocr_res_list[res_idx].get(consts.JYPZ_DATE_FIELD_2, '')
719 date_2 = ocr_res_list[res_idx].get(consts.JYPZ_DATE_FIELD_3, '')
720 date_3 = ocr_res_list[res_idx].get(consts.JYPZ_DATE_FIELD_4, '')
721 ocr_str = [date_1, date_2, date_3]
722 # 购车发票 价税合计大小写检验
723 elif ocr_field == consts.MVI_OCR_FIELD and name == consts.SE_NEW_ADD_FIELD[9]:
724 ocr_str = getattr(cp, consts.ZW_METHOD)(
725 ocr_res_list[res_idx].get(consts.LOWER_AMOUNT_FIELD, ''),
726 ocr_res_list[res_idx].get(consts.UPPER_AMOUNT_FIELD, ''),
727 )
728 else:
729 ocr_str = ocr_res_list[res_idx].get(compare_logic[name][0])
730
731 if isinstance(ocr_str, str):
732 result = getattr(cp, compare_logic[name][1])(value, ocr_str, **compare_logic[name][2])
733 no_key = False
734 # 二手车交易凭证 日期
735 elif ocr_field == consts.JYPZ_OCR_FIELD and name == consts.SE_GB_USED_FIELD[2]:
736 result = getattr(cp, compare_logic[name][1])(value, ocr_str, **compare_logic[name][2])
737 no_key = False
738 else:
739 result = consts.RESULT_N
740 ocr_str = empty_str
741 no_key = True
742
743 if name == '发票联':
744 new_invoice_result = result
745
746 if name == 'productGroupName' and (name.find('官方认证二手车') > -1 or name.find('官方认证二手车') > -1):
747 # 发票联必须
748 if new_invoice_result and new_invoice_result == consts.RESULT_Y:
749 result = consts.RESULT_Y
750 else:
751 result = consts.RESULT_N
752
753 if idx == 0 and result == consts.RESULT_N and length > 1:
754 break
755
756 is_find = True
757 # section_img_info[consts.SECTION_IMG_PATH_KEY] = ocr_res_list[res_idx].get(
758 # consts.SECTION_IMG_PATH_KEY, '')
759 # section_img_info[consts.ALL_POSITION_KEY] = ocr_res_list[res_idx].get(consts.ALL_POSITION_KEY, {})
760 # if special_expiry_date:
761 # section_img_info[consts.SECTION_IMG_PATH_KEY_2] = ocr_res_list[res_idx].get(
762 # consts.SECTION_IMG_PATH_KEY_2, '')
763 # section_img_info[consts.ALL_POSITION_KEY_2] = ocr_res_list[res_idx].get(
764 # consts.ALL_POSITION_KEY_2, {})
765
766 # 过期期限特殊处理
767 if special_expiry_date and name == 'idExpiryDate' and result == consts.RESULT_N:
768 if no_key:
769 if len(expiry_dates) == 0:
770 ocr_str = empty_str
771 result = consts.RESULT_N
772 img_path = empty_str
773 else:
774 for expiry_date, (date_img_path, date_res_idx) in expiry_dates.items():
775 expiry_date_res = getattr(cp, compare_logic[name][1])(value, expiry_date,
776 **compare_logic[name][2])
777 if expiry_date_res == consts.RESULT_N:
778 ocr_str = expiry_date
779 img_path = date_img_path
780 special_expiry_date_slice = True
781 section_img_info[consts.SECTION_IMG_PATH_KEY_2] = ocr_res_list[
782 date_res_idx].get(
783 consts.SECTION_IMG_PATH_KEY_2, '')
784 section_img_info[consts.ALL_POSITION_KEY_2] = ocr_res_list[date_res_idx].get(
785 consts.ALL_POSITION_KEY_2, {})
786 break
787 else:
788 ocr_str = empty_str
789 result = consts.RESULT_Y
790 img_path = empty_str
791 else:
792 img_path = ocr_res_list[res_idx].get(consts.IMG_PATH_KEY_2, '')
793 special_expiry_date_slice = True
794 else:
795 img_path = ocr_res_list[res_idx].get(consts.IMG_PATH_KEY,
796 '') if result == consts.RESULT_N else empty_str
797 if isinstance(value, list):
798 value = json.dumps(value, ensure_ascii=False)
799 error_type = empty_error_type if result == consts.RESULT_Y else ErrorType.OCR.value
800
801 if ocr_field == pos_consts.IC_OCR_FIELD and name == 'idExpiryDate':
802 result_field_list.append(
803 (name, value, result, ocr_str, img_path, error_type, compare_logic[name][-1][result]))
804 else:
805 result_field_list.append((name, value, result, ocr_str, img_path, error_type, compare_logic[name][-1]))
806
807 else:
808 no_ocr_result = True
809
810 # 针对license文档类型输出
811 if no_ocr_result:
812 # 保险
813 if license_en == pos_consts.BD_EN:
814 # 整体文档相关
815 pos_field, value = field_list[0]
816 if pos_field == 'insuranceType' and value == 'Comprehensive Insurance':
817 if no_ocr_result:
818 result_field_list.append((pos_field, value, consts.RESULT_N, ocr_str, img_path, error_type,
819 compare_logic['文档'][-1]))
820 elif license_en == pos_consts.HMH_EN: # 抵押登记豁免函
821 pos_field, value = field_list[0]
822 if pos_field == 'mortgageType' and value == 'MOTGF':
823 if no_ocr_result:
824 result_field_list.append((pos_field, value, consts.RESULT_N, ocr_str, img_path, error_type,
825 compare_logic['文档'][-1]))
826 elif license_en == pos_consts.MVI_EN: # 新车发票
827 pos_field, value = field_list[0]
828 if pos_field == 'productGroupName' and no_ocr_result:
829 result_field_list.append(
830 (pos_field, value, consts.RESULT_N, ocr_str, img_path, error_type,
831 compare_logic['文档'][-1]))
832 elif license_en == pos_consts.BC_EN: # 银行卡
833 pos_field, value = field_list[0]
834 if pos_field == 'bankVerificationStatus' and (value == 'N/A' or value == 'FAIL'):
835 if no_ocr_result:
836 result_field_list.append(
837 (pos_field, value, consts.RESULT_N, ocr_str, img_path, error_type,
838 compare_logic['文档'][-1]))
839 elif license_en == pos_consts.AFC_CONTRACT_EN: # AFC 车辆抵押贷款合同(E-Contract-Non ASP/ASP)
840 pos_field, value = field_list[0]
841 if pos_field == 'applicationEntity' and value == 'AFC':
842 if no_ocr_result:
843 result_field_list.append((pos_field, value, consts.RESULT_N, ocr_str, img_path, error_type,
844 compare_logic['文档'][-1]))
845 elif license_en == pos_consts.HIL_CONTRACT_1_EN: # 售后回租合同(E-Sign-SLB / OC)
846 pos_field, value = field_list[0]
847 if pos_field == 'applicationEntity' and value == 'HIL':
848 if no_ocr_result:
849 result_field_list.append((pos_field, value, consts.RESULT_N, ocr_str, img_path, error_type,
850 compare_logic['文档'][-1]))
851 elif license_en == pos_consts.HIL_CONTRACT_2_EN: # 车辆租赁抵押合同(E-Sign-SLB / OC)
852 pos_field, value = field_list[0]
853 if pos_field == 'applicationEntity' and value == 'HIL':
854 if no_ocr_result:
855 result_field_list.append(
856 (pos_field, value, consts.RESULT_N, ocr_str, img_path, error_type,
857 compare_logic['文档'][-1]))
858
859 if not is_find:
860 for name, value in field_list:
861 if isinstance(value, list):
862 value = json.dumps(value, ensure_ascii=False)
863 no_find_str = consts.DDA_NO_FIND if license_en == consts.DDA_EN else '{0}未找到'.format(license_en)
864 result_field_list.append(
865 (name, value, consts.RESULT_N, empty_str, empty_str, ErrorType.NF.value, no_find_str))
866
867 # if is_find:
868 # if special_expiry_date_slice:
869 # special_section_img_path = section_img_info.get(consts.SECTION_IMG_PATH_KEY_2, '')
870 # if os.path.exists(special_section_img_path):
871 # field = 'idExpiryDate'
872 # special_info = section_img_info.get(consts.ALL_POSITION_KEY_2, {})
873 # special_section_position = special_info.get(consts.POSITION_KEY, {})
874 # special_section_angle = special_info.get(consts.ANGLE_KEY, 0)
875 # try:
876 # last_img = img_process(special_section_img_path, special_section_position,
877 # special_section_angle)
878 # except Exception as e:
879 # field_img_path_dict[field] = special_section_img_path
880 # else:
881 # pre, suf = os.path.splitext(special_section_img_path)
882 # try:
883 # res_field = compare_logic[field][0]
884 # is_valid, coord_tuple = field_build_coordinates(special_info.get(res_field, {}))
885 # if is_valid:
886 # save_path = '{0}_{1}{2}'.format(pre, field, suf)
887 # field_img = last_img[coord_tuple[0]:coord_tuple[1], coord_tuple[2]:coord_tuple[3], :]
888 # cv2.imwrite(save_path, field_img)
889 # field_img_path_dict[field] = save_path
890 # else:
891 # field_img_path_dict[field] = special_section_img_path
892 # except Exception as e:
893 # field_img_path_dict[field] = special_section_img_path
894 #
895 # section_img_path = section_img_info.get(consts.SECTION_IMG_PATH_KEY, '')
896 # if os.path.exists(section_img_path):
897 # failed_field = []
898 # base_img_path = empty_str
899 # for name, _, result, _, img_path, _, _ in result_field_list:
900 # if result == consts.RESULT_N:
901 # if special_expiry_date_slice and name == 'idExpiryDate':
902 # continue
903 # failed_field.append(name)
904 # if base_img_path == empty_str:
905 # base_img_path = img_path
906 # if len(failed_field) > 0:
907 # info = section_img_info.get(consts.ALL_POSITION_KEY, {})
908 # section_position = info.get(consts.POSITION_KEY, {})
909 # section_angle = info.get(consts.ANGLE_KEY, 0)
910 # try:
911 # last_img = img_process(section_img_path, section_position, section_angle)
912 # except Exception as e:
913 # for field in failed_field:
914 # field_img_path_dict[field] = base_img_path
915 # else:
916 # pre, suf = os.path.splitext(section_img_path)
917 # for field in failed_field:
918 # try:
919 # res_field = compare_logic[field][0]
920 # is_valid, coord_tuple = field_build_coordinates(info.get(res_field, {}))
921 # if is_valid:
922 # save_path = '{0}_{1}{2}'.format(pre, field, suf)
923 # field_img = last_img[coord_tuple[0]:coord_tuple[1], coord_tuple[2]:coord_tuple[3],
924 # :]
925 # cv2.imwrite(save_path, field_img)
926 # field_img_path_dict[field] = save_path
927 # else:
928 # field_img_path_dict[field] = base_img_path
929 # except Exception as e:
930 # field_img_path_dict[field] = base_img_path
931
932 return result_field_list, no_ocr_result, field_img_path_dict
933
934
935 class CACompare:
936 @staticmethod
937 def ca_compare_license(license_en, ocr_res_dict, field_list):
938 ocr_field, compare_logic, special_expiry_date = consts.CA_COMPARE_FIELD[license_en]
939
940 is_find = False
941 special_expiry_date_slice = False
942 result_field_list = []
943 section_img_info = dict()
944 field_img_path_dict = dict()
945 ocr_res_str = ocr_res_dict.get(ocr_field)
946 if ocr_res_str is not None:
947 ocr_res_list = json.loads(ocr_res_str)
948
949 # 副页去除 3/4页去除
950 if ocr_field == consts.DL_OCR_FIELD or ocr_field == consts.MVC_OCR_FIELD:
951 tmp_list = []
952 for res in ocr_res_list:
953 if compare_logic['vinNo'][0] in res:
954 tmp_list.append(res)
955 ocr_res_list = tmp_list
956
957 length = len(ocr_res_list)
958
959 # 身份证、居住证 过期期限特殊处理
960 if special_expiry_date:
961 expiry_dates = set()
962 expiry_dates_img_path = set()
963 key = compare_logic.get('idExpiryDate')[0]
964 for ocr_res in ocr_res_list:
965 if key in ocr_res:
966 expiry_dates.add(ocr_res[key])
967 expiry_dates_img_path.add(ocr_res.get(consts.IMG_PATH_KEY_2, ''))
968 else:
969 expiry_dates = set()
970 expiry_dates_img_path = set()
971
972 for res_idx in range(length - 1, -1, -1):
973 if is_find:
974 break
975
976 for idx, (name, value) in enumerate(field_list):
977 ocr_str = ocr_res_list[res_idx].get(compare_logic[name][0])
978 if not isinstance(ocr_str, str):
979 result = consts.RESULT_N
980 ocr_str = empty_str
981 else:
982 result = getattr(cp, compare_logic[name][1])(value, ocr_str, **compare_logic[name][2])
983
984 if idx == 0 and result == consts.RESULT_N and length > 1:
985 break
986
987 is_find = True
988 # section_img_info[consts.SECTION_IMG_PATH_KEY] = ocr_res_list[res_idx].get(
989 # consts.SECTION_IMG_PATH_KEY, '')
990 # section_img_info[consts.ALL_POSITION_KEY] = ocr_res_list[res_idx].get(consts.ALL_POSITION_KEY, {})
991 # if special_expiry_date:
992 # section_img_info[consts.SECTION_IMG_PATH_KEY_2] = ocr_res_list[res_idx].get(
993 # consts.SECTION_IMG_PATH_KEY_2, '')
994 # section_img_info[consts.ALL_POSITION_KEY_2] = ocr_res_list[res_idx].get(
995 # consts.ALL_POSITION_KEY_2, {})
996
997 # 过期期限特殊处理
998 if special_expiry_date and name == 'idExpiryDate' and result == consts.RESULT_N:
999 for expiry_date in expiry_dates:
1000 expiry_date_res = getattr(cp, compare_logic[name][1])(value, expiry_date,
1001 **compare_logic[name][2])
1002 if expiry_date_res == consts.RESULT_Y:
1003 ocr_str = expiry_date
1004 result = expiry_date_res
1005 break
1006
1007 if result == consts.RESULT_N:
1008 if consts.IMG_PATH_KEY_2 in ocr_res_list[res_idx]:
1009 img_path = ocr_res_list[res_idx].get(consts.IMG_PATH_KEY_2, '')
1010 special_expiry_date_slice = True
1011 else:
1012 img_path = expiry_dates_img_path.pop() if len(expiry_dates_img_path) > 0 else empty_str
1013 else:
1014 img_path = empty_str
1015 else:
1016 img_path = ocr_res_list[res_idx].get(consts.IMG_PATH_KEY,
1017 '') if result == consts.RESULT_N else empty_str
1018 error_type = empty_error_type if result == consts.RESULT_Y else ErrorType.OCR.value
1019 result_field_list.append((name, value, result, ocr_str, img_path, error_type, compare_logic[name][-1]))
1020
1021 if not is_find:
1022 for name, value in field_list:
1023 result_field_list.append((name, value, consts.RESULT_N, empty_str, empty_str, ErrorType.NF.value, compare_logic[name][-1]))
1024
1025 # if is_find:
1026 # if special_expiry_date_slice:
1027 # special_section_img_path = section_img_info.get(consts.SECTION_IMG_PATH_KEY_2, '')
1028 # if os.path.exists(special_section_img_path):
1029 # field = 'idExpiryDate'
1030 # special_info = section_img_info.get(consts.ALL_POSITION_KEY_2, {})
1031 # special_section_position = special_info.get(consts.POSITION_KEY, {})
1032 # special_section_angle = special_info.get(consts.ANGLE_KEY, 0)
1033 # try:
1034 # last_img = img_process(special_section_img_path, special_section_position,
1035 # special_section_angle)
1036 # except Exception as e:
1037 # field_img_path_dict[field] = special_section_img_path
1038 # else:
1039 # pre, suf = os.path.splitext(special_section_img_path)
1040 # try:
1041 # res_field = compare_logic[field][0]
1042 # is_valid, coord_tuple = field_build_coordinates(special_info.get(res_field, {}))
1043 # if is_valid:
1044 # save_path = '{0}_{1}{2}'.format(pre, field, suf)
1045 # field_img = last_img[coord_tuple[0]:coord_tuple[1], coord_tuple[2]:coord_tuple[3], :]
1046 # cv2.imwrite(save_path, field_img)
1047 # field_img_path_dict[field] = save_path
1048 # else:
1049 # field_img_path_dict[field] = special_section_img_path
1050 # except Exception as e:
1051 # field_img_path_dict[field] = special_section_img_path
1052 #
1053 # section_img_path = section_img_info.get(consts.SECTION_IMG_PATH_KEY, '')
1054 # if os.path.exists(section_img_path):
1055 # failed_field = []
1056 # base_img_path = empty_str
1057 # for name, _, result, _, img_path, _ in result_field_list:
1058 # if result == consts.RESULT_N:
1059 # if special_expiry_date_slice and name == 'idExpiryDate':
1060 # continue
1061 # failed_field.append(name)
1062 # if base_img_path == empty_str:
1063 # base_img_path = img_path
1064 # if len(failed_field) > 0:
1065 # info = section_img_info.get(consts.ALL_POSITION_KEY, {})
1066 # section_position = info.get(consts.POSITION_KEY, {})
1067 # section_angle = info.get(consts.ANGLE_KEY, 0)
1068 # try:
1069 # last_img = img_process(section_img_path, section_position, section_angle)
1070 # except Exception as e:
1071 # for field in failed_field:
1072 # field_img_path_dict[field] = base_img_path
1073 # else:
1074 # pre, suf = os.path.splitext(section_img_path)
1075 # for field in failed_field:
1076 # try:
1077 # if license_en == consts.PP_EN:
1078 # res_field = consts.PP_SLICE_MAP[field]
1079 # else:
1080 # res_field = compare_logic[field][0]
1081 # is_valid, coord_tuple = field_build_coordinates(info.get(res_field, {}))
1082 # if is_valid:
1083 # save_path = '{0}_{1}{2}'.format(pre, field, suf)
1084 # field_img = last_img[coord_tuple[0]:coord_tuple[1], coord_tuple[2]:coord_tuple[3],
1085 # :]
1086 # cv2.imwrite(save_path, field_img)
1087 # field_img_path_dict[field] = save_path
1088 # else:
1089 # field_img_path_dict[field] = base_img_path
1090 # except Exception as e:
1091 # field_img_path_dict[field] = base_img_path
1092
1093 return result_field_list, field_img_path_dict
...\ No newline at end of file ...\ No newline at end of file
1
2 GZS_REASON_1 = '此申请有ASP产品,需人工核查'
3 GZS_REASON_2 = 'ASP购置税金额小于系统金额'
4
5 # license (license_en)
6 ID_EN = 'PRC ID'
7 PP_EN = 'Passport'
8 EEP_EN = 'Resident Permit to Mainland'
9 RP_EN = 'Resident ID'
10 BL_EN = 'Business permit'
11 SME_BL_EN = 'SME Business permit'
12 MVI_EN = 'newCar Invoice'
13 UCI_EN = 'usedCar Invoice'
14 MVC_EN = 'Green Book(1/2)'
15 MVC34_EN = 'Green Book(3/4)'
16 BC_EN = 'Bank Card'
17 DDA_EN = 'DDA'
18 HMH_EN = 'Mortgage Waiver Letter'
19 JYPZ_EN = 'Used Car Document'
20 AFC_CONTRACT_EN = 'AFC Contract'
21 BD_EN = 'Insurance'
22 BS_EN = 'Bank Statement'
23 HIL_CONTRACT_1_EN = '售后回租合同'
24 HIL_CONTRACT_2_EN = '车辆租赁抵押合同'
25 HIL_CONTRACT_3_EN = '车辆处置协议'
26
27 # 对应ocr_result 表中的字段
28 IC_OCR_FIELD = 'ic_ocr'
29 RP_OCR_FIELD = 'rp_ocr'
30 BL_OCR_FIELD = 'bl_ocr'
31 EEP_OCR_FIELD = 'eep_ocr'
32 DL_OCR_FIELD = 'dl_ocr'
33 PP_OCR_FIELD = 'pp_ocr'
34 MVC_OCR_FIELD = 'mvc_ocr'
35 MVI_OCR_FIELD = 'mvi_ocr'
36 BC_OCR_FIELD = 'bc_ocr'
37 UCI_OCR_FIELD = 'uci_ocr'
38 DDA_OCR_FIELD = 'bs_ocr'
39 HMH_OCR_FIELD = 'hmh_ocr'
40 JYPZ_OCR_FIELD = 'jypz_ocr'
41 HT_FIELD = 'ht_ocr'
42 BD_FIELD = 'bd_ocr'
43 BS_FIELD = 'bss_ocr'
44 HIL_CONTRACT_1_FIELD = 'hil_contract_1_ocr'
45 HIL_CONTRACT_2_FIELD = 'hil_contract_2_ocr'
46 HIL_CONTRACT_3_FIELD = 'hil_contract_3_ocr'
47
48 SE_AFC_CON_FIELD = ['合同编号-每页', '所购车辆价格-小写-重要条款', '车架号-重要条款', '贷款本金金额-重要条款', '贷款期限-重要条款',
49 '车辆贷款本金金额-重要条款', '附加产品融资贷款本金总额-重要条款', '所购车辆价格', '车架号', '经销商',
50 '贷款本金金额', '车辆贷款本金金额', '附加产品融资贷款本金总额', '贷款期限', '还款账号', '户名', '开户行',
51 '还款计划表', '见证人签字', '见证人日期', 'ASP项目详情-重要条款', '购置税校验', 'ASP项目详情',
52 '合同编号-每页(no-asp)', '无ASP产品']
53 # '承租人姓名', '承租人证件号码', '承租人法定代表人或授权代表'
54 SE_HIL_CON_1_FIELD = ['合同编号-每页', '车辆识别代码', '车辆卖方', '车辆原始销售价格', '融资成本总额', '租期',
55 '还款计划表', 'ASP项目详情', '购置税校验', '承租人法定代表人或授权代表', '还款账号', '户名', '开户行',
56 '共同承租人法定代表人或授权代表', '无ASP产品']
57
58 SE_HIL_CON_2_FIELD = ['合同编号', '车辆识别代码']
59
60 # 大陆二代身份证
61 ID_COMPARE_LOGIC = {
62 'customerName': ('姓名', 'se_name_compare', {}, '身份证姓名与系统不一致'),
63 'idNum': ('公民身份号码', 'se_common_compare', {}, '身份证号码与系统不一致'),
64 'dateOfBirth': ('出生年月', 'se_date_compare', {'input_replace': ''}),
65 'idExpiryDate': ('有效期限', 'se_date_compare_pos', {'long': True, 'ocr_split': True, 'input_replace': '', 'today': True}, {
66 'N1': '身份证疑似过期',
67 'N2': '身份证即将过期,请尽快提交放款申请'
68 })
69 }
70
71
72 # 新车发票
73 # key: pos field
74 # value: (ocr_result中的映射key,比较方法, 选项, comments/reason)
75 MVI_COMPARE_LOGIC = {
76 'firstSubmmisonDate': ('开票日期', 'se_date_compare_2', {'three_month': True}, '请确认发票开票日期,若发票开票日期早于首次提交审批日期则无法受理放款申请'),
77 'productGroupName': ('productGroupName', 'se_common_compare', {}, '请确认是否提供发票'),
78 'vinNo': ('车辆识别代码', 'se_common_compare', {}, '发票车架号与系统不一致'),
79 'vehicleTransactionAmount': ('价税合计小写', 'se_amount_compare', {}, '发票车辆价格与系统不一致'),
80 'customerName': ('购方名称', 'se_name_compare', {'is_passport': True, 'replace_kuohao': True}, '发票购买方姓名与系统不一致'),
81 'idNum': ('购买方身份证号或组织机构代码', 'se_common_compare', {}, '发票购买方证件号码与系统不一致'),
82 '发票联': ('发票联', 'se_common_compare', {}, '发票疑似非发票联'),
83 '文档': ('发票联', 'se_have_compare', {}, '请确认是否提供发票'),
84 }
85
86 # 银行卡
87 BC_COMPARE_LOGIC = {
88 'accountNo': ('CardNum', 'se_common_compare', {'remove_space': True}, '银行卡卡号与系统不一致'),
89 'bankName': ('BankName', 'se_both_contain_compare', {}, '银行卡开户行与系统不一致'),
90 'type': ('CardType', 'se_common_compare', {}, '银行卡非借记卡'),
91 'bankVerificationStatus': ('CardType', 'se_have_compare', {}, '请确认是否提供银行卡'),
92 '文档': ('文档', 'se_common_compare', {}, '请确认是否提供银行卡'),
93 }
94
95 # AFC 车辆抵押贷款合同(E-Contract-Non ASP/ASP)
96 HT_COMPARE_LOGIC = {
97 '合同编号-每页': ('合同编号-每页', 'se_list_compare', {}, '合同编号与系统不一致'),
98 # '合同编号-每页(no-asp)': ('合同编号-每页', 'se_list_compare', {'pop_last': True}, '合同编号与系统不一致'),
99 '合同编号-每页(no-asp)': ('合同编号-每页', 'se_list_compare', {}, '合同编号与系统不一致'),
100 '所购车辆价格-小写-重要条款': ('所购车辆价格-小写-重要条款', 'se_amount_str_compare', {}, '合同首页中车辆价格与系统不一致'),
101 '车架号-重要条款': ('车架号-重要条款', 'se_common_compare', {}, '合同首页中车架号与系统不一致'),
102 '贷款本金金额-重要条款': ('贷款本金金额-重要条款', 'se_amount_str_compare', {}, '合同首页中贷款本金与系统不一致'),
103 '贷款期限-重要条款': ('贷款期限-重要条款', 'se_common_compare', {}, '合同首页中贷款期限与系统不一致'),
104 '车辆贷款本金金额-重要条款': ('车辆贷款本金金额-重要条款', 'se_amount_str_compare', {}, '合同车辆贷款本金金额-重要条款'),
105 '附加产品融资贷款本金总额-重要条款': ('附加产品融资贷款本金总额-重要条款', 'se_amount_str_compare', {}, '合同首页中附加产品融资金额与系统不一致'),
106 '所购车辆价格': ('所购车辆价格', 'se_amount_str_compare', {}, '主合同页中车辆价格与系统不一致'),
107 '车架号': ('车架号', 'se_common_compare', {}, '主合同页中车架号与系统不一致'),
108 '经销商': ('经销商', 'se_common_compare', {}, '主合同页中经销商与系统不一致'),
109 '贷款本金金额': ('贷款本金金额', 'se_amount_str_compare', {}, '主合同页中贷款本金金额与系统不一致'),
110 '车辆贷款本金金额': ('车辆贷款本金金额', 'se_amount_str_compare', {}, '主合同页中车辆贷款本金金额与系统不一致'),
111 '附加产品融资贷款本金总额': ('附加产品融资贷款本金总额', 'se_amount_str_compare', {}, '主合同页中附加产品融资贷款本金总额与系统不一致'),
112 '贷款期限': ('贷款期限', 'se_common_compare', {}, '主合同页中贷款期限与系统不一致'),
113 '还款账号': ('还款账号', 'se_common_compare', {'remove_space': True}, '主合同页中还款账号与系统不一致'),
114 '户名': ('户名', 'se_common_compare', {}, '主合同页中户名与系统不一致'),
115 '开户行': ('开户行', 'se_both_contain_compare', {}, '主合同页中开户行与系统不一致'),
116
117 '借款人签字及时间': ('借款人签字及时间', 'se_both_contain_compare', {}, '合同首页签字项与系统不一致'),
118 '借款人姓名': ('借款人姓名', 'se_common_compare', {}, '主合同主借人姓名与系统不一致'),
119 '借款人证件号': ('借款人证件号', 'se_common_compare', {}, '主合同主借人证件号码与系统不一致'),
120 '共借人姓名': ('共借人姓名', 'se_common_compare', {}, '主合同共借人姓名与系统不一致'),
121 '共借人&抵押人姓名': ('共借人姓名', 'se_common_compare', {}, '主合同共借人&抵押人姓名与系统不一致'),
122 '共借人证件号': ('共借人证件号', 'se_common_compare', {}, '主合同共借人证件号码与系统不一致'),
123 '共借人&抵押人证件号': ('共借人证件号', 'se_common_compare', {}, '主合同共借人&抵押人证件号与系统不一致'),
124 '保证人姓名1': ('保证人姓名1', 'se_common_compare', {}, '主合同担保人1姓名与系统不一致'),
125 '保证人证件号1': ('保证人证件号1', 'se_common_compare', {}, '主合同担保人1证件号码与系统不一致'),
126 '保证人姓名2': ('保证人姓名2', 'se_common_compare', {}, '主合同担保人2姓名与系统不一致'),
127 '保证人证件号2': ('保证人证件号2', 'se_common_compare', {}, '主合同担保人2证件号码与系统不一致'),
128
129 '主借人签字': ('主借人签字', 'se_common_compare', {}, '合同主借款人签字与系统不一致'),
130 '主借人日期': ('主借人日期', 'se_have_compare', {}, '合同主借款人签字日期无'),
131 '共借人签字': ('共借人签字', 'se_common_compare', {}, '合同共借人签字与系统不一致'),
132 '共借人日期': ('共借人日期', 'se_have_compare', {}, '合同共借人签字日期无'),
133 '保证人签字1': ('保证人签字1', 'se_common_compare', {}, '合同担保人1签字与系统不一致'),
134 '保证人日期1': ('保证人日期1', 'se_have_compare', {}, '合同担保人1签字日期无'),
135 '保证人签字2': ('保证人签字2', 'se_common_compare', {}, '合同担保人2签字与系统不一致'),
136 '保证人日期2': ('保证人日期2', 'se_have_compare', {}, '合同担保人2签字日期无'),
137
138 '见证人签字': ('见证人签字', 'se_have_compare', {}, '合同见证人无'),
139 '见证人日期': ('见证人日期', 'se_date_contain_compare', {}, '合同见证人签字日期不符合逻辑'),
140
141 '还款计划表': ('还款计划表', 'se_schedule_compare', {"value_idx": 1}, '合同还款计划表与系统不一致'),
142
143 'ASP项目详情-重要条款': ('ASP项目详情-重要条款', 'se_asp_compare', {}, '合同(重要条款)ASP名称或者金额与系统不一致'),
144 'ASP项目详情': ('ASP项目详情', 'se_asp_compare', {}, '合同ASP名称或者金额与系统不一致'),
145
146 '购置税校验': ('购置税校验', 'se_self_compare_gzs', {}, GZS_REASON_2),
147 '无ASP产品': ('无ASP产品', 'se_self_compare_other_asp', {}, GZS_REASON_1),
148 '文档': ('文档', 'se_common_compare', {}, '请确认是否已完成车辆抵押贷款合同签署'),
149 }
150
151 # 售后回租合同(E-Sign-SLB / OC)
152 HIL_CONTRACT_1_COMPARE_LOGIC = {
153 '合同编号-每页': ('合同编号-每页', 'se_list_compare', {}, '售后回租合同中合同编号系统不一致'),
154 '合同编号-正文': ('合同编号-正文', 'se_common_compare', {}, '售后回租合同正文中合同编号系统不一致'),
155 '车辆识别代码': ('车辆识别代码', 'se_common_compare', {}, '售后回租合同车辆识别代码与系统车架号不一致'),
156 '车辆卖方': ('车辆卖方', 'se_common_compare', {}, '售后回租合同车辆卖方与系统经销商不一致'),
157 '车辆原始销售价格': ('车辆原始销售价格', 'se_amount_str_compare', {}, '售后回租合同车辆原始销售价格与系统车辆价格不一致'),
158 '融资成本总额': ('融资成本总额', 'se_amount_str_compare', {}, '售后回租合同融资成本总额与系统不一致'),
159 '租期': ('租期', 'se_contain_compare', {}, '售后回租合同首页中贷款期限系统不一致'),
160 '还款计划表': ('还款计划表', 'se_schedule_compare', {"value_idx": 1}, '售后回租合同还款计划表与系统不一致'),
161 'ASP项目详情': ('ASP项目详情', 'se_asp_compare', {}, '售后回租合同ASP名称或者金额与系统不一致'),
162 '承租人法定代表人或授权代表': ('承租人法定代表人或授权代表', 'se_name_compare', {}, '售后回租合同承租人法定代表人或授权代表与系统不一致'),
163 '共同承租人法定代表人或授权代表': ('共同承租人法定代表人或授权代表', 'se_name_compare', {}, '售后回租合同共同承租人法定代表人或授权代表与系统不一致'),
164 '还款账号': ('还款账号', 'se_common_compare', {'remove_space': True}, '售后回租合同还款账号与系统不一致'),
165 '户名': ('户名', 'se_common_compare', {}, '售后回租合同户名与系统不一致'),
166 '开户行': ('开户行', 'se_both_contain_compare', {}, '售后回租合同开户行与系统不一致'),
167
168 '承租人姓名': ('承租人姓名', 'se_name_compare', {}, '售后回租合同承租人姓名与系统不一致'),
169 '承租人证件号': ('承租人证件号', 'se_common_compare', {}, '售后回租合同承租人证件号与系统不一致'),
170 '承租人签字': ('承租人签字', 'se_contain_compare', {}, '售后回租合同承租人签字与系统不一致'),
171
172 '共同承租人姓名': ('共同承租人姓名', 'se_name_compare', {}, '售后回租合同共同承租人姓名与系统不一致'),
173 '共同承租人&抵押人姓名': ('共同承租人&抵押人姓名', 'se_name_compare', {}, '售后回租合同共同承租人&抵押人姓名与系统不一致'),
174 '共同承租人证件号': ('共同承租人证件号', 'se_common_compare', {}, '售后回租合同共同承租人证件号与系统不一致'),
175 '共同承租人&抵押人证件号': ('共同承租人&抵押人证件号', 'se_common_compare', {}, '售后回租合同共同承租人&抵押人证件号与系统不一致'),
176 '共同承租人签字': ('共同承租人签字', 'se_contain_compare', {}, '售后回租合同共同承租人签字与系统不一致'),
177
178 '保证人姓名1': ('保证人姓名1', 'se_name_compare', {}, '售后回租合同保证人姓名1与系统不一致'),
179 '保证人证件号1': ('保证人证件号1', 'se_common_compare', {}, '售后回租合同保证人证件号1与系统不一致'),
180 '保证人签字1': ('保证人签字1', 'se_contain_compare', {}, '售后回租合同保证人签字1与系统不一致'),
181
182 '保证人姓名2': ('保证人姓名2', 'se_name_compare', {}, '售后回租合同保证人姓名2与系统不一致'),
183 '保证人证件号2': ('保证人证件号2', 'se_common_compare', {}, '售后回租合同保证人证件号2与系统不一致'),
184 '保证人签字2': ('保证人签字2', 'se_contain_compare', {}, '售后回租合同保证人签字2与系统不一致'),
185
186 '购置税校验': ('购置税校验', 'se_self_compare_gzs', {}, GZS_REASON_2),
187 '无ASP产品': ('无ASP产品', 'se_self_compare_other_asp', {}, GZS_REASON_1),
188 '文档': ('文档', 'se_common_compare', {}, '请确认是否已完成售后回租合同签署'),
189 }
190
191 # 车辆租赁抵押合同(E-Sign-SLB / OC)
192 HIL_CONTRACT_2_COMPARE_LOGIC = {
193 '合同编号': ('合同编号', 'se_common_compare', {}, '车辆租赁抵押合同合同编号与系统合同编号不一致'),
194 '合同编号-正文': ('合同编号-正文', 'se_common_compare', {}, '车辆租赁抵押合同正文合同编号与系统合同编号不一致'),
195 '车辆识别代码': ('车辆识别代码', 'se_common_compare', {}, '车辆租赁抵押合同车辆识别代码与系统车架号不一致'),
196 '租金总额': ('租金总额', 'se_amount_str_compare', {}, '车辆租赁抵押合同租金总额与系统租金总额不一致'),
197 '融资租赁期限': ('融资租赁期限', 'se_common_compare', {}, '车辆租赁抵押合同融资租赁期限与系统不一致'),
198 '抵押人': ('抵押人', 'se_name_compare', {}, '车辆租赁抵押合同抵押人姓名与系统不一致'),
199 '抵押人证件号码': ('抵押人证件号码', 'se_common_compare', {}, '车辆租赁抵押合同抵押人证件号码与系统不一致'),
200 '抵押人签字': ('抵押人签字', 'se_contain_compare', {}, '车辆租赁抵押合同抵押人签字与系统承租人姓名不一致'),
201 '抵押人配偶': ('抵押人配偶', 'se_name_compare', {}, '车辆租赁抵押合同抵押人配偶姓名与系统不一致'),
202 '抵押人配偶证件号码': ('抵押人配偶证件号码', 'se_common_compare', {}, '车辆租赁抵押合同抵押人配偶证件号码与系统不一致'),
203 '抵押人配偶签字': ('抵押人配偶签字', 'se_contain_compare', {}, '车辆租赁抵押合同抵押人签字与系统承租人配偶姓名不一致'),
204 '文档': ('文档', 'se_common_compare', {}, '请确认是否已完成车辆租赁抵押合同签署'),
205 }
206
207 # 抵押登记豁免函
208 HMH_COMPARE_LOGIC = {
209 '借款人/承租人姓名': ('借款/承租人姓名', 'se_name_compare', {}, '抵押登记豁免函借款人/承租人姓名与系统不符'),
210 '借款人/承租人证件号': ('证件号码', 'se_common_compare', {}, '抵押登记豁免函借款人/承租人证件号码与系统不符'),
211 '申请号': ('合同编号', 'se_common_compare', {}, '抵押登记豁免函申请号与系统不符'),
212 '渠道': ('渠道', 'se_channel_compare', {}, '抵押登记豁免函渠道与系统不符'),
213 '签字': ('借款人签字/盖章', 'se_have_compare', {}, '抵押登记豁免函签字需人工核查'),
214 '文档': ('文档', 'se_common_compare', {}, '请确认是否已完成抵押登记豁免函签署')
215 }
216
217 # 保单
218 BD_COMPARE_LOGIC = {
219 '被保险人姓名': ('被保险人姓名', 'super_list_compare', {'method': 'name'}, '保单被保险人姓名与系统不一致'),
220 '被保险人证件号码': ('被保险人证件号码', 'super_list_compare', {'method': 'common', 'is_bd_id': True}, '保单身份证号需人工核查'),
221 '车架号': ('车架号', 'se_common_compare', {}, '保单车架号与系统不一致'),
222 '机动车损失保险金额': ('机动车损失保险金额', 'se_amount_lte_compare', {}, '保单车损险异常'),
223 '第三者责任保险金额': ('机动车第三者责任保险金额', 'se_amount_lte_compare', {}, '保单三者险异常'),
224 '绝对免赔率': ('机动车损失保险绝对免赔率/绝对免赔额', 'se_one_compare', {}, '保单无绝对免赔项'),
225 '保险起始日期': ('保险起始日期', 'se_bd_date_compare', {'start': True}, '保单起始时间有误'),
226 '保险截止日期': ('保险截止日期', 'se_bd_date_compare', {}, '保单截止时间有误'),
227 '保单章': ('保单章', 'se_common_compare', {}, '保单无保单章'),
228 '第一受益人': ('特别约定第一受益人', 'se_common_compare', {}, '保单第一受益人需人工核查'),
229 '保险费合计': ('保险费合计', 'se_amount_lte_compare', {}, '保单保费疑似无法覆盖ASP保险融资'),
230 '文档': ('文档', 'se_common_compare', {}, '请确认是否提供保单')
231 }
232
233
234 SE_COMPARE_FIELD = {
235 ID_EN: (IC_OCR_FIELD, ID_COMPARE_LOGIC, True),
236 MVI_EN: (MVI_OCR_FIELD, MVI_COMPARE_LOGIC, False),
237 BC_EN: (BC_OCR_FIELD, BC_COMPARE_LOGIC, False),
238 HMH_EN: (HMH_OCR_FIELD, HMH_COMPARE_LOGIC, False),
239 AFC_CONTRACT_EN: (HT_FIELD, HT_COMPARE_LOGIC, False),
240 BD_EN: (BD_FIELD, BD_COMPARE_LOGIC, False),
241 HIL_CONTRACT_1_EN: (HIL_CONTRACT_1_FIELD, HIL_CONTRACT_1_COMPARE_LOGIC, False),
242 HIL_CONTRACT_2_EN: (HIL_CONTRACT_2_FIELD, HIL_CONTRACT_2_COMPARE_LOGIC, False)
243 }
244
245
246 OCR_COMPARE_COMMENT = {
247 ID_EN: {
248 'idExpiryDate': '身份证疑似过期',
249 'customerName': '身份证姓名与系统不一致',
250 'idNum': '身份证号码与系统不一致',
251 'other': '请确认是否提供身份证件'
252 },
253 MVI_EN: {
254 'firstSubmmisonDate': '请确认发票开票日期,若发票开票日期早于首次提交审批日期则无法受理放款申请',
255 'customerName': '发票购买方姓名与系统不一致',
256 'idNum': '发票购买方证件号码与系统不一致',
257 'vinNo': '发票车架号与系统不一致',
258 'vehicleTransactionAmount': '发票车辆价格与系统不一致',
259 'productGroupName': '请确认是否提供发票'
260 },
261 BC_EN: {
262 'bankName': '银行卡开户行与系统不一致',
263 'accountNo': '银行卡卡号与系统不一致',
264 'bankVerificationStatus': '请确认是否提供银行卡'
265 },
266 AFC_CONTRACT_EN: {
267 'applicationId & applicationVersion': '',
268 'service': '',
269 'amount': '',
270 'financedAmount': '',
271 'associatedServicePrincipal': '',
272 'vinNo': '',
273 'accountNo': '',
274 'accountHolderName': '',
275 'bankName': '',
276 'term': '',
277 'applicationEntity': ''
278 },
279 HIL_CONTRACT_1_EN: {
280
281 },
282 HIL_CONTRACT_2_EN: {
283
284 },
285 BD_EN: {
286 '': ''
287 }
288 }
1 import json
2 import consts
3 from common.tools.comparison import cp
4
5
6 empty_str = ''
7
8
9 def get_pos_compare_info(pos_info):
10 compare_info = {}
11
12 application_entity = pos_info.get('applicationEntity', 'AFC')
13 application_id = pos_info.get('applicationId', '')
14 application_version = str(pos_info.get('applicationVersion', ''))
15 first_submission_date = pos_info.get('firstSubmmisonDate', '')
16
17 application_id_version = '{0}-{1}'.format(application_id, application_version)
18
19 custr_name = custr_id = ''
20
21 # 身份证
22 individual_cus_info_list = pos_info.get('individualCusInfo', [])
23 for individual_cus_info in individual_cus_info_list:
24 customer_name = individual_cus_info.get('customerName', '').strip()
25 id_num = individual_cus_info.get('idNum', '')
26
27 if individual_cus_info.get('applicantType', '') == 'CUSTR':
28 custr_name = customer_name
29 custr_id = id_num
30
31 if individual_cus_info.get('idType', '') == consts.ID_TYPE:
32 field_input = [(consts.ID_FIELDS[0], customer_name),
33 (consts.ID_FIELDS[1], id_num),
34 (consts.ID_FIELDS[2], individual_cus_info.get('idExpiryDate', ''))]
35 compare_info.setdefault(consts.ID_EN, []).append(field_input)
36
37 # 新车发票
38 vehicle_info = pos_info.get('vehicleInfo', {})
39 vin_no = vehicle_info.get('vinNo', '')
40 amount = str(vehicle_info.get('vehicleTransactionAmount', '0.0'))
41 field_input = [
42 (consts.MVI_FIELDS[0], vin_no),
43 (consts.MVI_FIELDS[1], amount),
44 (consts.MVI_FIELDS[2], custr_name),
45 (consts.MVI_FIELDS[3], custr_id),
46 (consts.MVI_FIELDS[4], first_submission_date),
47 (consts.MVI_FIELDS[5], consts.MVI_FPL_VALUE),
48 ]
49 compare_info.setdefault(consts.MVI_EN, []).append(field_input)
50
51 # 银行卡
52 bank_info = pos_info.get('bankInfo', {})
53 bank_status = bank_info.get('bankVerificationStatus', '')
54
55 if bank_status != 'PASS':
56 account_no = bank_info.get('accountNo', '')
57 bank_name = bank_info.get('bankName', '')
58
59 field_input = [
60 (consts.BC_FIELDS[0], account_no),
61 (consts.BC_FIELDS[1], bank_name),
62 (consts.BC_FIELDS[2], consts.BC_TYPE_VALUE) # 是否为借记卡
63 ]
64 compare_info.setdefault(consts.BC_EN, []).append(field_input)
65
66 # 抵押登记豁免函
67 quotationt_info = pos_info.get('quotationtInfo', {})
68 if quotationt_info.get('mortgageType', '') == 'MOTGF':
69 field_input = [
70 (consts.HMH_FIELDS[0], custr_name),
71 (consts.HMH_FIELDS[1], custr_id),
72 (consts.HMH_FIELDS[2], application_id_version),
73 # 宝马金融(中国)有限公司 先锋国际融资租赁有限公司
74 (consts.HMH_FIELDS[3], consts.HMH_CHANNEL_MAP.get(application_entity, '')),
75 (consts.HMH_FIELDS[4], consts.HAVE_CN),
76 ]
77 compare_info.setdefault(consts.HMH_EN, []).append(field_input)
78
79 # 保单
80 insurance_info = pos_info.get('insuranceInfo', {})
81 if insurance_info.get('insuranceType') == 'ITCOM':
82 field_input = [
83 (consts.BD_FIELDS[0], [custr_name, ]),
84 (consts.BD_FIELDS[1], [custr_id, ]),
85 (consts.BD_FIELDS[2], vin_no)
86 ]
87 compare_info.setdefault(consts.BD_EN, []).append(field_input)
88
89 # HIL合同
90 if application_entity in consts.HIL_SET:
91 pass
92 # AFC合同
93 else:
94 pass
95
96 return compare_info
97
98
99 def pre_compare_process(compare_info, ocr_res_dict, id_res_list):
100 compare_result = {}
101 for license_en, items_list in compare_info.items():
102 if license_en == consts.ID_EN:
103 for field_list in items_list:
104 result_list = pre_compare_license_id(license_en, id_res_list, field_list)
105 compare_result.setdefault(license_en, []).append(result_list)
106 elif license_en in [consts.HIL_CONTRACT_1_EN, consts.HIL_CONTRACT_2_EN,
107 consts.HIL_CONTRACT_3_EN, consts.AFC_CONTRACT_EN]:
108 pass
109 else:
110 for field_list in items_list:
111 result_list = pre_compare_license(license_en, ocr_res_dict, field_list)
112 compare_result.setdefault(license_en, []).append(result_list)
113 return compare_result
114
115
116 def pre_compare_license(license_en, ocr_res_dict, field_list):
117 ocr_field, compare_logic, no_find_comment = consts.PRE_COMPARE_LOGIC_MAP[license_en]
118
119 is_find = False
120 result_field_list = []
121
122 ocr_res_str = ocr_res_dict.get(ocr_field)
123 if ocr_res_str is not None:
124 ocr_res_list = json.loads(ocr_res_str)
125 length = len(ocr_res_list)
126
127 for res_idx in range(length-1, -1, -1):
128 if is_find:
129 break
130
131 for idx, (name, value) in enumerate(field_list):
132 ocr_str = ocr_res_list[res_idx].get(compare_logic[name][0])
133
134 if isinstance(ocr_str, str):
135 result = getattr(cp, compare_logic[name][1])(value, ocr_str, **compare_logic[name][2])
136 else:
137 result = consts.RESULT_N
138 ocr_str = empty_str
139
140 if idx == 0 and result == consts.RESULT_N and length > 1:
141 break
142
143 is_find = True
144
145 if isinstance(value, list):
146 value = json.dumps(value, ensure_ascii=False)
147 result_field_list.append((value, ocr_str, result, compare_logic[name][3]))
148
149 if not is_find:
150 result_field_list.append((empty_str, empty_str, consts.RESULT_N, no_find_comment))
151
152 return result_field_list
153
154
155 def pre_compare_license_id(license_en, id_res_list, field_list):
156 ocr_field, compare_logic, no_find_comment = consts.PRE_COMPARE_LOGIC_MAP[license_en]
157
158 is_find = False
159 result_field_list = []
160 field_last_idx = len(field_list) - 1
161
162 for ca_or_se_idx, ocr_res_str in enumerate(id_res_list):
163 if is_find:
164 break
165
166 if ocr_res_str is not None:
167 ocr_res_list = json.loads(ocr_res_str)
168 length = len(ocr_res_list)
169
170 # 身份证、居住证 过期期限特殊处理
171 expiry_dates = set()
172 key = compare_logic.get('idExpiryDate')[0]
173 for ocr_res in ocr_res_list:
174 if key in ocr_res:
175 expiry_dates.add(ocr_res[key])
176
177 for res_idx in range(length-1, -1, -1):
178 if is_find:
179 break
180
181 result_field_list.clear()
182 for idx, (name, value) in enumerate(field_list):
183 ocr_str = ocr_res_list[res_idx].get(compare_logic[name][0])
184 if not isinstance(ocr_str, str):
185 result = consts.RESULT_N
186 ocr_str = empty_str
187 else:
188 result = getattr(cp, compare_logic[name][1])(value, ocr_str, **compare_logic[name][2])
189
190 if idx == 0 and result == consts.RESULT_N:
191 if ca_or_se_idx == 0:
192 break
193 elif length > 1:
194 break
195
196 # 过期期限特殊处理
197 if name == 'idExpiryDate' and result == consts.RESULT_N:
198 if len(expiry_dates) == 0:
199 ocr_str = empty_str
200 result = consts.RESULT_N
201 else:
202 for expiry_date in expiry_dates:
203 expiry_date_res = getattr(cp, compare_logic[name][1])(value, expiry_date,
204 **compare_logic[name][2])
205 if expiry_date_res == consts.RESULT_N:
206 ocr_str = expiry_date
207 break
208 else:
209 ocr_str = empty_str
210 result = consts.RESULT_Y
211
212 if ca_or_se_idx == 0 and result == consts.RESULT_N:
213 break
214
215 if ca_or_se_idx == 1:
216 is_find = True
217 elif idx == field_last_idx:
218 is_find = True
219
220 if isinstance(value, list):
221 value = json.dumps(value, ensure_ascii=False)
222 result_field_list.append((value, ocr_str, result, compare_logic[name][3]))
223
224 if not is_find:
225 result_field_list = [(empty_str, empty_str, consts.RESULT_N, no_find_comment)]
226
227 return result_field_list
228
229
230 def rebuild_result(compare_result):
231 # compare_result = {
232 # "is_pass": True,
233 # "particulars": [{
234 # "object_name": "PRC ID",
235 # "fields": [{
236 # "input": "张三",
237 # "ocr": "张三",
238 # "field_is_pass": True,
239 # "comments": "身份证姓名与系统不一致"
240 # }]
241 # }]
242 # }
243 is_pass = True
244 particulars_list = []
245 for license_en, items_list in compare_result.items():
246 for result_field_list in items_list:
247 field_list = []
248 for input_str, ocr_str, result, comments in result_field_list:
249 if result == consts.RESULT_N:
250 is_pass = False
251 field_list.append(
252 {
253 'input': input_str,
254 'ocr': ocr_str,
255 'field_is_pass': result == consts.RESULT_Y,
256 'comments': comments,
257 }
258 )
259 particulars_list.append(
260 {
261 'object_name': license_en,
262 'fields': field_list
263 }
264 )
265 rebuild_compare_result = {
266 'is_pass': is_pass,
267 'particulars': particulars_list
268 }
269 return rebuild_compare_result
270
271
272 def pre_compare(pos_info, ocr_res_dict, id_res_list):
273 compare_info = get_pos_compare_info(pos_info)
274 compare_result = pre_compare_process(compare_info, ocr_res_dict, id_res_list)
275 rebuild_compare_result = rebuild_result(compare_result)
276 return rebuild_compare_result
277
278
279 def get_empty_result():
280 empty_result = {
281 "is_pass": False,
282 "particulars": [{
283 "object_name": "",
284 "fields": [{
285 "input": "",
286 "ocr": "",
287 "field_is_pass": False,
288 "comments": "未查找到OCR识别结果"
289 }]
290 }]
291 }
292 return empty_result
293
294
295
296
1 HIL_SET = {'HIL', 'HIl', 'HiL', 'Hil', 'hIL', 'hIl', 'hiL', 'hil', 'CO00002', 'SF5_CL'}
2
3 ID_TYPE = 'ITPRC'
4 ID_FIELDS = ['姓名', '身份证号码', '有效期限']
5
6 MVI_FIELDS = ['车架号', '价税合计(小写)', '购买方姓名', '购买方证件号码', '开票日期', '发票联']
7 MVI_FPL_VALUE = '发票联'
8
9 BC_FIELDS = ['卡号', '开户行名称', '卡片类型']
10 BC_TYPE_VALUE = '借记卡'
11
12 HMH_FIELDS = ['借款人/承租人姓名', '借款人/承租人证件号', '申请号', '渠道', '签字']
13 HMH_CHANNEL_MAP = {
14 'AFC': '宝马金融(中国)有限公司',
15 'HIL': '先锋国际融资租赁有限公司'
16 }
17 HAVE_CN = '有'
18
19 BD_FIELDS = ['被保险人姓名', '被保险人证件号码', '车架号']
20
21 ID_EN = 'idCard'
22 MVI_EN = 'newCar Invoice'
23 BC_EN = 'Bank Card'
24 HMH_EN = 'Mortgage Waiver Letter'
25 BD_EN = 'Insurance'
26
27 ID_OCR_FIELD = 'ic_ocr'
28 MVI_OCR_FIELD = 'mvi_ocr'
29 BC_OCR_FIELD = 'bc_ocr'
30 HMH_OCR_FIELD = 'hmh_ocr'
31 BD_FIELD = 'bd_ocr'
32
33 MVI_COMPARE_LOGIC = {
34 MVI_FIELDS[0]: ('车辆识别代码', 'se_common_compare', {}, '发票车架号与系统不一致'),
35 MVI_FIELDS[1]: ('价税合计小写', 'se_amount_compare', {}, '发票车辆价格与系统不一致'),
36 MVI_FIELDS[2]: ('购方名称', 'se_name_compare', {'is_passport': True, 'replace_kuohao': True}, '发票购买方姓名与系统不一致'),
37 MVI_FIELDS[3]: ('购买方身份证号或组织机构代码', 'se_common_compare', {}, '发票购买方证件号码与系统不一致'),
38 MVI_FIELDS[4]: ('开票日期', 'se_date_compare_2', {'three_month': True}, '请确认发票开票日期,若发票开票日期早于首次提交审批日期则无法受理放款申请'),
39 MVI_FIELDS[5]: ('发票类型', 'se_common_compare', {}, '发票疑似非发票联'),
40 }
41
42 BC_COMPARE_LOGIC = {
43 BC_FIELDS[0]: ('CardNum', 'se_common_compare', {'remove_space': True}, '银行卡卡号与系统不一致'),
44 BC_FIELDS[1]: ('BankName', 'se_both_contain_compare', {}, '银行卡开户行与系统不一致'),
45 BC_FIELDS[2]: ('CardType', 'se_common_compare', {}, '银行卡疑似非借记卡'),
46 }
47
48 HMH_COMPARE_LOGIC = {
49 HMH_FIELDS[0]: ('借款/承租人姓名', 'se_name_compare', {}, '抵押登记豁免函借款人/承租人姓名与系统不符'),
50 HMH_FIELDS[1]: ('证件号码', 'se_common_compare', {}, '抵押登记豁免函借款人/承租人证件号码与系统不符'),
51 HMH_FIELDS[2]: ('合同编号', 'se_common_compare', {}, '抵押登记豁免函申请号与系统不符'),
52 HMH_FIELDS[3]: ('渠道', 'se_channel_compare', {}, '抵押登记豁免函渠道与系统不符'),
53 HMH_FIELDS[4]: ('借款人签字/盖章', 'se_common_compare', {}, '抵押登记豁免函无签字'),
54 }
55
56 BD_COMPARE_LOGIC = {
57 BD_FIELDS[0]: ('被保险人姓名', 'super_list_compare', {'method': 'name'}, '保单被保险人姓名与系统不一致'),
58 BD_FIELDS[1]: ('被保险人证件号码', 'super_list_compare', {'method': 'common', 'is_bd_id': True}, '保单身份证号需人工核查'),
59 BD_FIELDS[2]: ('车架号', 'se_common_compare', {}, '保单车架号与系统不一致'),
60 }
61
62 PRE_COMPARE_LOGIC_MAP = {
63 ID_EN: (ID_OCR_FIELD, ID_COMPARE_LOGIC, '请确认是否提供身份证件'),
64 MVI_EN: (MVI_OCR_FIELD, MVI_COMPARE_LOGIC, '请确认是否提供发票'),
65 BC_EN: (BC_OCR_FIELD, BC_COMPARE_LOGIC, '请确认是否提供银行卡'),
66 HMH_EN: (HMH_OCR_FIELD, HMH_COMPARE_LOGIC, '请确认是否已完成抵押登记豁免函签署'),
67 BD_EN: (BD_FIELD, BD_COMPARE_LOGIC, '请确认是否提供保单'),
68 AFC_CONTRACT_EN: (HT_FIELD, HT_COMPARE_LOGIC, '请确认是否已完成车辆抵押贷款合同签署'),
69 HIL_CONTRACT_1_EN: (HIL_CONTRACT_1_FIELD, HIL_CONTRACT_1_COMPARE_LOGIC, '请确认是否已完成售后回租合同签署'),
70 HIL_CONTRACT_2_EN: (HIL_CONTRACT_2_FIELD, HIL_CONTRACT_2_COMPARE_LOGIC, '请确认是否已完成车辆租赁抵押合同签署'),
71 }
72
73 RESULT_Y = 'Y'
74 RESULT_N = 'N'
75
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!