fix merge
Showing
9 changed files
with
544 additions
and
26 deletions
... | @@ -1649,3 +1649,69 @@ CA_COMPARE_FIELD = { | ... | @@ -1649,3 +1649,69 @@ CA_COMPARE_FIELD = { |
1649 | } | 1649 | } |
1650 | 1650 | ||
1651 | CONTRACT_SHEET_NAME = '合同' | 1651 | CONTRACT_SHEET_NAME = '合同' |
1652 | |||
1653 | # ------------------CMS-------------------------------------- | ||
1654 | BANK_INFO_MAP = ( | ||
1655 | ('accountNo', 'bankAccountDetails.accountNo'), | ||
1656 | ('bankName', 'bankAccountDetails.bankName'), | ||
1657 | ('accountHolderName', 'bankAccountDetails.accountHolderName'), | ||
1658 | ) | ||
1659 | |||
1660 | VEHICLE_INFO_MAP = ( | ||
1661 | ('vehicleStatus', 'vehicleStatus'), | ||
1662 | ('vinNo', 'vehicleInformation.vinNo'), | ||
1663 | ('dealer', 'dealerName'), | ||
1664 | ('vehicleTransactionAmount', 'totalFinanceAmount'), | ||
1665 | ) | ||
1666 | |||
1667 | CORPORATE_INFO_MAP = ( | ||
1668 | ('firstIdType', ), | ||
1669 | ('firstIdNo', ), | ||
1670 | ('companyName', ), | ||
1671 | ('legalRepName', ), | ||
1672 | ('businessLicenseNo', ), | ||
1673 | ('organizationCreditCode', ), | ||
1674 | ('taxRegistrationCertificateNo', ), | ||
1675 | ('establishmentDate', ), | ||
1676 | ('businessLicenseDueDate', ), | ||
1677 | ) | ||
1678 | |||
1679 | INDIVIDUAL_INFO_MAP = ( | ||
1680 | ('applicantType', 'applicantInformation.applicantType'), | ||
1681 | ('customerType', 'applicantInformation.customersubType'), | ||
1682 | |||
1683 | ('idType', 'applicantInformation.IDInformation.idType'), | ||
1684 | ('customerName', 'applicantInformation.name'), | ||
1685 | ('idNum', 'applicantInformation.IDInformation.idNum'), | ||
1686 | ('dateOfBirth', 'applicantInformation.dateOfBirth'), | ||
1687 | ('idExpiryDate', 'applicantInformation.IDInformation.idExpiryDate'), | ||
1688 | ('hukouProvince', ), | ||
1689 | ('hukouCity', ), | ||
1690 | |||
1691 | ('secondIdType', 'applicantInformation.IDInformation.idType'), | ||
1692 | ('secondIdNum', 'applicantInformation.IDInformation.idNum'), | ||
1693 | |||
1694 | ('companyName', ), | ||
1695 | ('registeredCapital', ), | ||
1696 | ('selfEmployedSubType', ), | ||
1697 | ) | ||
1698 | |||
1699 | CMS_TO_POS = [ | ||
1700 | ('bank_info', BANK_INFO_MAP), | ||
1701 | ('vehicle_info', VEHICLE_INFO_MAP), | ||
1702 | ('corporate_cus_info', CORPORATE_INFO_MAP), | ||
1703 | ('individual_cus_info', INDIVIDUAL_INFO_MAP), | ||
1704 | ] | ||
1705 | |||
1706 | TENANT_MAP = { | ||
1707 | AFC_PREFIX: 1, | ||
1708 | HIL_PREFIX: 2, | ||
1709 | } | ||
1710 | |||
1711 | APPLICANT_TYPE_MAP = { | ||
1712 | 'Borrower': 'CUSTR', | ||
1713 | 'Co Borrower': 'COAPP', | ||
1714 | 'Guarantor': 'GAUTR1', | ||
1715 | 'Mortgager': 'GAUTR2' | ||
1716 | } | ||
1717 | ... | ... |
... | @@ -13,9 +13,14 @@ class OCR2Exception(Exception): | ... | @@ -13,9 +13,14 @@ class OCR2Exception(Exception): |
13 | class OCR4Exception(Exception): | 13 | class OCR4Exception(Exception): |
14 | pass | 14 | pass |
15 | 15 | ||
16 | |||
16 | class LTGTException(Exception): | 17 | class LTGTException(Exception): |
17 | pass | 18 | pass |
18 | 19 | ||
19 | 20 | ||
20 | class GCAPException(Exception): | 21 | class GCAPException(Exception): |
21 | pass | 22 | pass |
23 | |||
24 | |||
25 | class CMSException(Exception): | ||
26 | pass | ... | ... |
... | @@ -244,6 +244,33 @@ class HILSEComparisonInfo(models.Model): | ... | @@ -244,6 +244,33 @@ class HILSEComparisonInfo(models.Model): |
244 | 244 | ||
245 | 245 | ||
246 | # 比对信息表 | 246 | # 比对信息表 |
247 | class AFCSECMSInfo(models.Model): | ||
248 | id = models.BigAutoField(primary_key=True, verbose_name="id") # 主键 | ||
249 | application_id = models.CharField(max_length=64, verbose_name="申请id") # 索引 | ||
250 | content = models.TextField(verbose_name="CMS信息") | ||
251 | update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间') | ||
252 | create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') # 索引 | ||
253 | |||
254 | class Meta: | ||
255 | managed = False | ||
256 | db_table = 'afc_se_cms_info' | ||
257 | situ_db_label = 'afc' | ||
258 | |||
259 | |||
260 | # 比对信息表 | ||
261 | class HILSECMSInfo(models.Model): | ||
262 | id = models.BigAutoField(primary_key=True, verbose_name="id") # 主键 | ||
263 | application_id = models.CharField(max_length=64, verbose_name="申请id") # 索引 | ||
264 | content = models.TextField(verbose_name="CMS信息") | ||
265 | update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间') | ||
266 | create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间') # 索引 | ||
267 | |||
268 | class Meta: | ||
269 | managed = False | ||
270 | db_table = 'hil_se_cms_info' | ||
271 | |||
272 | |||
273 | # 比对信息表 | ||
247 | class HILComparisonInfo(models.Model): | 274 | class HILComparisonInfo(models.Model): |
248 | id = models.BigAutoField(primary_key=True, verbose_name="id") # 主键 | 275 | id = models.BigAutoField(primary_key=True, verbose_name="id") # 主键 |
249 | uniq_seq = models.CharField(max_length=128, verbose_name="唯一序列号") # 索引? | 276 | uniq_seq = models.CharField(max_length=128, verbose_name="唯一序列号") # 索引? | ... | ... |
src/apps/doc/ocr/cms.py
0 → 100644
1 | import requests | ||
2 | from settings import conf | ||
3 | from common.redis_cache import redis_handler as rh | ||
4 | from apps.doc.exceptions import CMSException | ||
5 | |||
6 | |||
7 | class CMS: | ||
8 | |||
9 | def __init__(self): | ||
10 | self.oauth_url = conf.CMS_OAUTH_URL | ||
11 | self.url = conf.CMS_URL | ||
12 | self.oauth_payload = { | ||
13 | 'grant_type': 'client_credentials', | ||
14 | 'client_id': conf.CMS_OAUTH_ID, | ||
15 | 'client_secret': conf.CMS_OAUTH_SECRET, | ||
16 | 'scope': conf.CMS_OAUTH_SCOPE | ||
17 | } | ||
18 | self.token_type = 'bearer' | ||
19 | self.token = None | ||
20 | self.token_key = 'access_token' | ||
21 | self.expires_key = 'expires_in' | ||
22 | self.token_type_key = 'token_type' | ||
23 | |||
24 | def update_token(self): | ||
25 | response = requests.post(self.oauth_url, data=self.oauth_payload, files=[]) | ||
26 | if response.status_code != 200: | ||
27 | raise CMSException('CMS Oauth response with code: {0}'.format(response.status_code)) | ||
28 | token = response.json().get(self.token_key) | ||
29 | if not isinstance(token, str): | ||
30 | raise CMSException('CMS Oauth can not get token: {0}'.format(response.json())) | ||
31 | self.token = token | ||
32 | self.token_type = response.json().get(self.token_type_key, self.token_type) | ||
33 | expires = response.json().get(self.expires_key, 3600) | ||
34 | rh.set_cms_token(self.token, expires) | ||
35 | |||
36 | def get_token(self): | ||
37 | if self.token is None: | ||
38 | self.token = rh.get_cms_token() | ||
39 | if self.token is None: | ||
40 | self.update_token() | ||
41 | return self.token | ||
42 | |||
43 | def send(self, payload): | ||
44 | token = self.get_token() | ||
45 | headers = { | ||
46 | 'Authorization': '{0} {1}'.format(self.token_type.capitalize(), token), | ||
47 | 'Content-Type': 'application/json', | ||
48 | } | ||
49 | response = requests.post(self.url, headers=headers, json=payload) | ||
50 | if response.status_code != 200: | ||
51 | raise CMSException('CMS Oauth response with code: {0}'.format(response.status_code)) | ||
52 | return response.json() | ||
53 | |||
54 | |||
55 | cms = CMS() | ||
56 | |||
57 | |||
58 | |||
59 |
... | @@ -22,8 +22,10 @@ from .models import ( | ... | @@ -22,8 +22,10 @@ from .models import ( |
22 | GCAPRecords, | 22 | GCAPRecords, |
23 | AFCComparisonInfo, | 23 | AFCComparisonInfo, |
24 | AFCSEComparisonInfo, | 24 | AFCSEComparisonInfo, |
25 | AFCSECMSInfo, | ||
25 | HILComparisonInfo, | 26 | HILComparisonInfo, |
26 | HILSEComparisonInfo, | 27 | HILSEComparisonInfo, |
28 | HILSECMSInfo, | ||
27 | AFCCompareOfflineReport, | 29 | AFCCompareOfflineReport, |
28 | HILCompareOfflineReport, | 30 | HILCompareOfflineReport, |
29 | AFCCACompareResult, | 31 | AFCCACompareResult, |
... | @@ -327,7 +329,7 @@ info_args = { | ... | @@ -327,7 +329,7 @@ info_args = { |
327 | 'customersubType': fields.Str(required=True, validate=validate.Length(max=32)), | 329 | 'customersubType': fields.Str(required=True, validate=validate.Length(max=32)), |
328 | 'selfEmployedSubType': fields.Str(required=False, validate=validate.Length(max=32)), | 330 | 'selfEmployedSubType': fields.Str(required=False, validate=validate.Length(max=32)), |
329 | 'name': fields.Str(required=True, validate=validate.Length(max=64)), | 331 | 'name': fields.Str(required=True, validate=validate.Length(max=64)), |
330 | 'legalRepName': fields.Str(required=True, validate=validate.Length(max=64)), | 332 | 'legalRepName': fields.Str(required=False, validate=validate.Length(max=64)), |
331 | 'dateOfBirth': CustomDate(required=False), | 333 | 'dateOfBirth': CustomDate(required=False), |
332 | 'nationality': fields.Str(required=False, validate=validate.Length(max=64)), | 334 | 'nationality': fields.Str(required=False, validate=validate.Length(max=64)), |
333 | 'establishmentDate': CustomDate(required=False), | 335 | 'establishmentDate': CustomDate(required=False), |
... | @@ -358,10 +360,10 @@ payment_schedule = { | ... | @@ -358,10 +360,10 @@ payment_schedule = { |
358 | } | 360 | } |
359 | 361 | ||
360 | associated_services = { | 362 | associated_services = { |
361 | 'associatedServices': fields.Str(required=True, validate=validate.Length(max=64)), | 363 | 'associatedServices': fields.Str(required=False, validate=validate.Length(max=64)), |
362 | 'price': CustomDecimal(required=True), | 364 | 'price': CustomDecimal(required=False), |
363 | 'financed': CustomDecimal(required=True), | 365 | 'financed': CustomDecimal(required=False), |
364 | 'total': CustomDecimal(required=True), | 366 | 'total': CustomDecimal(required=False), |
365 | } | 367 | } |
366 | 368 | ||
367 | vehicle_info = { | 369 | vehicle_info = { |
... | @@ -382,13 +384,13 @@ insurance_details = { | ... | @@ -382,13 +384,13 @@ insurance_details = { |
382 | } | 384 | } |
383 | 385 | ||
384 | corporate_info = { | 386 | corporate_info = { |
385 | 'hashCode': fields.Str(required=True, validate=validate.Length(max=64)), | 387 | 'hashCode': fields.Str(required=False, validate=validate.Length(max=64)), |
386 | 'borrowerName': fields.Str(required=True, validate=validate.Length(max=64)), | 388 | 'borrowerName': fields.Str(required=False, validate=validate.Length(max=64)), |
387 | 'fiscalYear': fields.Int(required=True), | 389 | 'fiscalYear': fields.Int(required=False), |
388 | 'totaAssets': CustomDecimal(required=True), | 390 | 'totaAssets': CustomDecimal(required=False), |
389 | 'totalLiabilitiesAndOwnersEquity': CustomDecimal(required=True), | 391 | 'totalLiabilitiesAndOwnersEquity': CustomDecimal(required=False), |
390 | 'cashAndCashEquivalentAtEndOfPeriod': CustomDecimal(required=True), | 392 | 'cashAndCashEquivalentAtEndOfPeriod': CustomDecimal(required=False), |
391 | 'netProfit': CustomDecimal(required=True), | 393 | 'netProfit': CustomDecimal(required=False), |
392 | } | 394 | } |
393 | 395 | ||
394 | se_verification = { | 396 | se_verification = { |
... | @@ -411,13 +413,13 @@ se_cms_content = { | ... | @@ -411,13 +413,13 @@ se_cms_content = { |
411 | 'dealerName': fields.Str(required=True, validate=validate.Length(max=512)), | 413 | 'dealerName': fields.Str(required=True, validate=validate.Length(max=512)), |
412 | 'tier': fields.Str(required=True, validate=validate.Length(max=64)), | 414 | 'tier': fields.Str(required=True, validate=validate.Length(max=64)), |
413 | 'province': fields.Str(required=True, validate=validate.Length(max=64)), | 415 | 'province': fields.Str(required=True, validate=validate.Length(max=64)), |
414 | 'fapiaoIssuerDealer': fields.Str(required=True, validate=validate.Length(max=512)), | 416 | 'fapiaoIssuerDealer': fields.Str(required=False, validate=validate.Length(max=512)), |
415 | 'customerName': fields.Str(required=True, validate=validate.Length(max=64)), | 417 | 'customerName': fields.Str(required=True, validate=validate.Length(max=64)), |
416 | 'customerIdNo': fields.Str(required=True, validate=validate.Length(max=64)), | 418 | 'customerIdNo': fields.Str(required=True, validate=validate.Length(max=64)), |
417 | 'vehicleStatus': fields.Str(required=True, validate=validate.Length(max=64)), | 419 | 'vehicleStatus': fields.Str(required=True, validate=validate.Length(max=64)), |
418 | 'applicationSource': fields.Str(required=True, validate=validate.Length(max=64)), | 420 | 'applicationSource': fields.Str(required=True, validate=validate.Length(max=64)), |
419 | 'contractSource': fields.Str(required=True, validate=validate.Length(max=64)), | 421 | 'contractSource': fields.Str(required=True, validate=validate.Length(max=64)), |
420 | 'applicationRating': fields.Int(required=True), | 422 | 'applicationRating': fields.Int(required=False), |
421 | 423 | ||
422 | 'applicantInformation': fields.List(fields.Nested(info_args), | 424 | 'applicantInformation': fields.List(fields.Nested(info_args), |
423 | required=True, validate=validate.Length(min=1, max=4)), | 425 | required=True, validate=validate.Length(min=1, max=4)), |
... | @@ -647,7 +649,7 @@ class CompareView(GenericView): | ... | @@ -647,7 +649,7 @@ class CompareView(GenericView): |
647 | corporate_cus_info=corporate_cus_info, | 649 | corporate_cus_info=corporate_cus_info, |
648 | ) | 650 | ) |
649 | # 触发比对 | 651 | # 触发比对 |
650 | compare.apply_async((application_id, business_type, uniq_seq, None, True), | 652 | compare.apply_async((application_id, business_type, uniq_seq, None, True, False), |
651 | queue='queue_compare') | 653 | queue='queue_compare') |
652 | return response.ok() | 654 | return response.ok() |
653 | 655 | ||
... | @@ -708,7 +710,7 @@ class SECompareView(GenericView): | ... | @@ -708,7 +710,7 @@ class SECompareView(GenericView): |
708 | quotationt_info=quotationt_info | 710 | quotationt_info=quotationt_info |
709 | ) | 711 | ) |
710 | # 触发比对 | 712 | # 触发比对 |
711 | compare.apply_async((application_id, business_type, uniq_seq, None, False), | 713 | compare.apply_async((application_id, business_type, uniq_seq, None, False, False), |
712 | queue='queue_compare') | 714 | queue='queue_compare') |
713 | return response.ok() | 715 | return response.ok() |
714 | 716 | ||
... | @@ -1091,7 +1093,21 @@ class SECMSView(GenericView): | ... | @@ -1091,7 +1093,21 @@ class SECMSView(GenericView): |
1091 | # pos上传比对信息接口 SE | 1093 | # pos上传比对信息接口 SE |
1092 | @use_args(se_cms_args, location='data') | 1094 | @use_args(se_cms_args, location='data') |
1093 | def post(self, request, args): | 1095 | def post(self, request, args): |
1094 | self.running_log.info('cms in') | 1096 | cms_info = args.get('content', {}) |
1097 | business_type = consts.AFC_PREFIX if cms_info.get('financeCompany', '').startswith('宝马') else consts.HIL_PREFIX | ||
1098 | src_application_id = cms_info.get('settlemnetVerification', {}).get('applicationNo', '') | ||
1099 | application_id = src_application_id[:src_application_id.rfind('-')] | ||
1100 | content_str = json.dumps(cms_info) | ||
1101 | |||
1102 | comparison_class = HILSECMSInfo if business_type in consts.HIL_SET else AFCSECMSInfo | ||
1103 | comparison_class.objects.create( | ||
1104 | application_id=application_id, | ||
1105 | content=content_str, | ||
1106 | ) | ||
1107 | |||
1108 | # 触发比对 | ||
1109 | compare.apply_async((application_id, business_type, None, None, False, True), | ||
1110 | queue='queue_compare') | ||
1095 | return response.ok() | 1111 | return response.ok() |
1096 | 1112 | ||
1097 | post.openapi_doc = ''' | 1113 | post.openapi_doc = ''' | ... | ... |
... | @@ -13,8 +13,10 @@ from apps.doc.models import ( | ... | @@ -13,8 +13,10 @@ from apps.doc.models import ( |
13 | HILSEOCRResult, | 13 | HILSEOCRResult, |
14 | AFCComparisonInfo, | 14 | AFCComparisonInfo, |
15 | AFCSEComparisonInfo, | 15 | AFCSEComparisonInfo, |
16 | AFCSECMSInfo, | ||
16 | HILComparisonInfo, | 17 | HILComparisonInfo, |
17 | HILSEComparisonInfo, | 18 | HILSEComparisonInfo, |
19 | HILSECMSInfo, | ||
18 | Configs, | 20 | Configs, |
19 | HILCompareReport, | 21 | HILCompareReport, |
20 | AFCCompareReport, | 22 | AFCCompareReport, |
... | @@ -25,14 +27,30 @@ from apps.doc.models import ( | ... | @@ -25,14 +27,30 @@ from apps.doc.models import ( |
25 | ) | 27 | ) |
26 | from apps.doc import consts | 28 | from apps.doc import consts |
27 | from apps.doc.ocr.gcap import gcap | 29 | from apps.doc.ocr.gcap import gcap |
30 | from apps.doc.ocr.cms import cms | ||
28 | from apps.doc.exceptions import GCAPException | 31 | from apps.doc.exceptions import GCAPException |
29 | from apps.doc.named_enum import RequestTeam, RequestTrigger, ProcessName, ErrorType | 32 | from apps.doc.named_enum import RequestTeam, RequestTrigger, ProcessName, ErrorType |
30 | from common.tools.comparison import cp | 33 | from common.tools.comparison import cp |
34 | from common.tools.des import decode_des | ||
31 | 35 | ||
32 | compare_log = logging.getLogger('compare') | 36 | compare_log = logging.getLogger('compare') |
33 | log_base = '[Compare]' | 37 | log_base = '[Compare]' |
34 | empty_str = '' | 38 | empty_str = '' |
35 | empty_error_type = 1000 | 39 | empty_error_type = 1000 |
40 | des_key = conf.CMS_DES_KEY | ||
41 | |||
42 | |||
43 | class FakePOS: | ||
44 | |||
45 | def __init__(self, | ||
46 | application_id, | ||
47 | first_submmison_date, | ||
48 | application_version, | ||
49 | customer_type): | ||
50 | self.application_id = application_id | ||
51 | self.first_submmison_date = first_submmison_date | ||
52 | self.application_version = application_version | ||
53 | self.customer_type = customer_type | ||
36 | 54 | ||
37 | 55 | ||
38 | def name_check(ocr_res_dict, second_ocr_field, second_compare_list, second_id_num, name): | 56 | def name_check(ocr_res_dict, second_ocr_field, second_compare_list, second_id_num, name): |
... | @@ -882,6 +900,173 @@ def get_se_compare_info(last_obj, application_entity, detect_list): | ... | @@ -882,6 +900,173 @@ def get_se_compare_info(last_obj, application_entity, detect_list): |
882 | return compare_info | 900 | return compare_info |
883 | 901 | ||
884 | 902 | ||
903 | def rebuild_compare_info(last_obj, application_id): | ||
904 | # { | ||
905 | # "content": { | ||
906 | # "financeCompany": "宝马汽车金融有限公司", | ||
907 | # "contractNo": "CH-B100000123", | ||
908 | # "status": "HIL", | ||
909 | # "branch": "宝马汽车金融有限公司", | ||
910 | # "fpCampaign": "Q1_2021_BMW_BASIC", | ||
911 | # "applicationVersion": 1, | ||
912 | # "submissionDate": {}, | ||
913 | # "mortgageType": "Mortgage Contract", | ||
914 | # "dealerRegion": "West", | ||
915 | # "insuranceRealNameCity": false, | ||
916 | # "totalFinanceAmount": 1234.56, | ||
917 | # "terms": 24, | ||
918 | # "dealerName": "乐山长宝汽车销售服务有限公司", | ||
919 | # "tier": "2", | ||
920 | # "province": "四川省", | ||
921 | # "fapiaoIssuerDealer": "乐山长宝汽车销售服务有限公司", | ||
922 | # "customerName": "蔡红", | ||
923 | # "customerIdNo": "511102196706080000", | ||
924 | # "vehicleStatus": "Used", | ||
925 | # "applicationSource": "eApp", | ||
926 | # "contractSource": "Online Sign", | ||
927 | # "applicationRating": 100, | ||
928 | # "applicantInformation": [ | ||
929 | # { | ||
930 | # "applicantType": "Borrower", | ||
931 | # "customersubType": "TCCOR", | ||
932 | # "selfEmployedSubType": "CSIBM", | ||
933 | # "name": "李四", | ||
934 | # "legalRepName": "张三", | ||
935 | # "dateOfBirth": {}, | ||
936 | # "nationality": "中国", | ||
937 | # "establishmentDate": {}, | ||
938 | # "IDInformation": [ | ||
939 | # { | ||
940 | # "idType": "ITARI", | ||
941 | # "idNum": "111111199404251100", | ||
942 | # "idExpiryDate": {} | ||
943 | # } | ||
944 | # ] | ||
945 | # } | ||
946 | # ], | ||
947 | # "autoApprovedDetails": { | ||
948 | # "aaType": "CAA1" | ||
949 | # }, | ||
950 | # "financialInformation": { | ||
951 | # "vehiclePrice": 1234.56, | ||
952 | # "grossPrice": 1234.56, | ||
953 | # "associatedServicePrice": 1234.56, | ||
954 | # "vehiclePrincipal": 1234.56, | ||
955 | # "associatedServicePrincipal": 1234.56, | ||
956 | # "originationPrincipal": 1234.56, | ||
957 | # "totalDownPayment": 1234.56, | ||
958 | # "vehicleDownPaymentRatio": 1234.56, | ||
959 | # "optionAmount": 1234.56, | ||
960 | # "sumOfMSRPAndOption": 1234.56 | ||
961 | # }, | ||
962 | # "paymentSchedule": [ | ||
963 | # { | ||
964 | # "no": 3, | ||
965 | # "grossRentalAmount": 1234.56 | ||
966 | # } | ||
967 | # ], | ||
968 | # "associatedServices": [ | ||
969 | # { | ||
970 | # "associatedServices": "机动车保险", | ||
971 | # "price": 1234.56, | ||
972 | # "financed": 1234.56, | ||
973 | # "total": 1234.56 | ||
974 | # } | ||
975 | # ], | ||
976 | # "vehicleInformation": { | ||
977 | # "vinNo": "LBV23482934DJFKD" | ||
978 | # }, | ||
979 | # "bankAccountDetails": { | ||
980 | # "bankName": "中国银行", | ||
981 | # "accountHolderName": "张三", | ||
982 | # "accountNo": "12312123123123124" | ||
983 | # }, | ||
984 | # "insuranceDetails": { | ||
985 | # "insuranceType": "ComprehensiveInsurance", | ||
986 | # "insuranceAmount": "60000000", | ||
987 | # "startDate": {}, | ||
988 | # "endDate": {} | ||
989 | # }, | ||
990 | # "corporateFinancialInformation": { | ||
991 | # "hashCode": "238231", | ||
992 | # "borrowerName": "张三", | ||
993 | # "fiscalYear": 2019, | ||
994 | # "totaAssets": 1234.56, | ||
995 | # "totalLiabilitiesAndOwnersEquity": 1234.56, | ||
996 | # "cashAndCashEquivalentAtEndOfPeriod": 1234.56, | ||
997 | # "netProfit": 1234.56 | ||
998 | # }, | ||
999 | # "settlemnetVerification": { | ||
1000 | # "applicationNo": "CH-B100000123" | ||
1001 | # } | ||
1002 | # } | ||
1003 | # } | ||
1004 | |||
1005 | cms_info = json.loads(last_obj.content) | ||
1006 | |||
1007 | fake_pos = FakePOS(application_id, | ||
1008 | cms_info.get('submissionDate', ''), | ||
1009 | cms_info.get('applicationVersion', 1), | ||
1010 | cms_info.get('applicantInformation', [])[0].get('customersubType', '')) | ||
1011 | |||
1012 | fake_pos.bank_info = json.dumps( | ||
1013 | { | ||
1014 | 'accountNo': decode_des(cms_info.get('bankAccountDetails', {}).get('accountNo', ''), des_key), | ||
1015 | 'bankName': cms_info.get('bankAccountDetails', {}).get('bankName', ''), | ||
1016 | 'accountHolderName': cms_info.get('bankAccountDetails', {}).get('accountHolderName', ''), | ||
1017 | } | ||
1018 | ) | ||
1019 | |||
1020 | fake_pos.vehicle_info = json.dumps( | ||
1021 | { | ||
1022 | 'vehicleStatus': cms_info.get('vehicleStatus', ''), | ||
1023 | 'vinNo': cms_info.get('vehicleInformation', {}).get('vinNo', ''), | ||
1024 | 'dealer': cms_info.get('dealerName', ''), | ||
1025 | 'vehicleTransactionAmount': str(cms_info.get('totalFinanceAmount', '')), | ||
1026 | } | ||
1027 | ) | ||
1028 | |||
1029 | individual_cus_info = [] | ||
1030 | for individual_cus in cms_info.get('applicantInformation', []): | ||
1031 | id_type = id_num = id_date = second_id_type = second_id_num = None | ||
1032 | for idx, id_info in enumerate(individual_cus.get('', [])): | ||
1033 | if idx > 1: | ||
1034 | break | ||
1035 | elif idx == 0: | ||
1036 | id_type = id_info.get('idType') | ||
1037 | id_num = decode_des(id_info.get('idNum')) | ||
1038 | id_date = id_info.get('idExpiryDate') | ||
1039 | else: | ||
1040 | second_id_type = id_info.get('idType') | ||
1041 | second_id_num = decode_des(id_info.get('idNum')) | ||
1042 | individual_cus_info.append( | ||
1043 | { | ||
1044 | 'applicantType': consts.APPLICANT_TYPE_MAP.get(individual_cus.get('applicantType')), | ||
1045 | 'customerType': individual_cus.get('customersubType'), | ||
1046 | |||
1047 | 'idType': id_type, | ||
1048 | 'idNum': id_num, | ||
1049 | 'idExpiryDate': id_date, | ||
1050 | |||
1051 | 'customerName': individual_cus.get('name'), | ||
1052 | 'dateOfBirth': individual_cus.get('dateOfBirth', ''), | ||
1053 | 'hukouProvince': cms_info.get('province', ''), | ||
1054 | |||
1055 | 'secondIdType': second_id_type, | ||
1056 | 'secondIdNum': second_id_num, | ||
1057 | |||
1058 | 'companyName': individual_cus.get('name'), | ||
1059 | 'selfEmployedSubType': individual_cus.get('selfEmployedSubType', ''), | ||
1060 | } | ||
1061 | ) | ||
1062 | |||
1063 | fake_pos.individual_cus_info = json.dumps(individual_cus_info) | ||
1064 | |||
1065 | fake_pos.corporate_cus_info = None | ||
1066 | |||
1067 | return fake_pos | ||
1068 | |||
1069 | |||
885 | def se_compare_license(license_en, ocr_res_dict, field_list): | 1070 | def se_compare_license(license_en, ocr_res_dict, field_list): |
886 | ocr_field, compare_logic, special_expiry_date = consts.SE_COMPARE_FIELD[license_en] | 1071 | ocr_field, compare_logic, special_expiry_date = consts.SE_COMPARE_FIELD[license_en] |
887 | 1072 | ||
... | @@ -1099,12 +1284,14 @@ def se_result_detect(ocr_res_dict): | ... | @@ -1099,12 +1284,14 @@ def se_result_detect(ocr_res_dict): |
1099 | return detect_list | 1284 | return detect_list |
1100 | 1285 | ||
1101 | 1286 | ||
1102 | def se_compare(application_id, application_entity, ocr_res_id, last_obj, ocr_res_dict): | 1287 | def se_compare(application_id, application_entity, ocr_res_id, last_obj, ocr_res_dict, is_cms): |
1103 | try: | 1288 | try: |
1104 | # 比对逻辑 | 1289 | # 比对逻辑 |
1105 | start_time = datetime.now() | 1290 | start_time = datetime.now() |
1106 | detect_list = se_result_detect(ocr_res_dict) | 1291 | detect_list = se_result_detect(ocr_res_dict) |
1107 | compare_info = get_se_compare_info(last_obj, application_entity, detect_list) | 1292 | if is_cms: |
1293 | last_obj = rebuild_compare_info(last_obj, application_id) | ||
1294 | compare_info, is_gsyh = get_se_compare_info(last_obj, application_entity, detect_list) | ||
1108 | compare_result, total_fields, failed_count, successful_at_this_level, failure_reason_str = se_compare_process( | 1295 | compare_result, total_fields, failed_count, successful_at_this_level, failure_reason_str = se_compare_process( |
1109 | compare_info, ocr_res_dict) | 1296 | compare_info, ocr_res_dict) |
1110 | compare_log.info('{0} [SE] [compare success] [entity={1}] [id={2}] [ocr_res_id={3}] [result={4}]'.format( | 1297 | compare_log.info('{0} [SE] [compare success] [entity={1}] [id={2}] [ocr_res_id={3}] [result={4}]'.format( |
... | @@ -1160,24 +1347,54 @@ def se_compare(application_id, application_entity, ocr_res_id, last_obj, ocr_res | ... | @@ -1160,24 +1347,54 @@ def se_compare(application_id, application_entity, ocr_res_id, last_obj, ocr_res |
1160 | '[error={4}]'.format(log_base, application_entity, application_id, ocr_res_id, | 1347 | '[error={4}]'.format(log_base, application_entity, application_id, ocr_res_id, |
1161 | traceback.format_exc())) | 1348 | traceback.format_exc())) |
1162 | 1349 | ||
1350 | # cms结果发送 | ||
1351 | if is_cms: | ||
1352 | try: | ||
1353 | application_link = '{0}/showList/showList?entity={1}&scheme={2}&case_id={3}'.format( | ||
1354 | conf.BASE_URL, application_entity, consts.COMPARE_DOC_SCHEME_LIST[1], application_id) | ||
1355 | data = { | ||
1356 | "SubtenantId": consts.TENANT_MAP[application_entity], | ||
1357 | "Data": { | ||
1358 | "Result_Message": "Pass" if successful_at_this_level else "Fail", | ||
1359 | "Failure_Reason": failure_reason_str, | ||
1360 | "Application_Number": application_id, | ||
1361 | "Bank_Statement": "", | ||
1362 | "Link_URL": application_link, | ||
1363 | "OCR_Version": 1, | ||
1364 | "Origin": consts.INFO_SOURCE[1] | ||
1365 | } | ||
1366 | } | ||
1367 | response = cms.send(data) | ||
1368 | except Exception as e: | ||
1369 | compare_log.error('{0} [SE] [cms error] [entity={1}] [id={2}] [ocr_res_id={3}] ' | ||
1370 | '[error={4}]'.format(log_base, application_entity, application_id, ocr_res_id, | ||
1371 | traceback.format_exc())) | ||
1372 | else: | ||
1373 | compare_log.info('{0} [SE] [cms success] [entity={1}] [id={2}] [ocr_res_id={3}] [response={4}]'.format( | ||
1374 | log_base, application_entity, application_id, ocr_res_id, response)) | ||
1163 | 1375 | ||
1164 | @app.task | 1376 | @app.task |
1165 | def compare(application_id, application_entity, uniq_seq, ocr_res_id, is_ca=True): | 1377 | def compare(application_id, application_entity, uniq_seq, ocr_res_id, is_ca=True, is_cms=False): |
1166 | # POS: application_id, application_entity, uniq_seq, None | 1378 | # POS: application_id, application_entity, uniq_seq, None |
1167 | # OCR: application_id, business_type(application_entity), None, ocr_res_id | 1379 | # OCR: application_id, business_type(application_entity), None, ocr_res_id |
1168 | 1380 | ||
1169 | compare_log.info('{0} [receive task] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] [is_ca={5}]'.format( | 1381 | compare_log.info('{0} [receive task] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] [is_ca={5}] ' |
1170 | log_base, application_entity, application_id, uniq_seq, ocr_res_id, is_ca)) | 1382 | '[is_cms={6}]'.format(log_base, application_entity, application_id, uniq_seq, ocr_res_id, |
1383 | is_ca, is_cms)) | ||
1171 | 1384 | ||
1172 | # 根据application_id查找最新的比对信息,如果没有,结束 | 1385 | # 根据application_id查找最新的比对信息,如果没有,结束 |
1173 | if is_ca: | 1386 | if is_ca: |
1174 | comparison_class = HILComparisonInfo if application_entity == consts.HIL_PREFIX else AFCComparisonInfo | 1387 | comparison_class = HILComparisonInfo if application_entity == consts.HIL_PREFIX else AFCComparisonInfo |
1175 | else: | 1388 | else: |
1176 | comparison_class = HILSEComparisonInfo if application_entity == consts.HIL_PREFIX else AFCSEComparisonInfo | 1389 | if application_entity == consts.HIL_PREFIX: |
1390 | comparison_class = HILSECMSInfo if is_cms else HILSEComparisonInfo | ||
1391 | else: | ||
1392 | comparison_class = AFCSECMSInfo if is_cms else AFCSEComparisonInfo | ||
1177 | last_obj = comparison_class.objects.filter(application_id=application_id).last() | 1393 | last_obj = comparison_class.objects.filter(application_id=application_id).last() |
1178 | if last_obj is None: | 1394 | if last_obj is None: |
1179 | compare_log.info('{0} [comparison info empty] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] ' | 1395 | compare_log.info('{0} [comparison info empty] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] ' |
1180 | '[is_ca={5}]'.format(log_base, application_entity, application_id, uniq_seq, ocr_res_id, is_ca)) | 1396 | '[is_ca={5}] [is_cms]={6}'.format(log_base, application_entity, application_id, uniq_seq, |
1397 | ocr_res_id, is_ca, is_cms)) | ||
1181 | return | 1398 | return |
1182 | 1399 | ||
1183 | # 根据application_id查找OCR累计结果指定license字段,如果没有,结束 | 1400 | # 根据application_id查找OCR累计结果指定license字段,如果没有,结束 |
... | @@ -1191,13 +1408,14 @@ def compare(application_id, application_entity, uniq_seq, ocr_res_id, is_ca=True | ... | @@ -1191,13 +1408,14 @@ def compare(application_id, application_entity, uniq_seq, ocr_res_id, is_ca=True |
1191 | ocr_res_dict = result_class.objects.filter(id=ocr_res_id).values(*consts.COMPARE_FIELDS).first() | 1408 | ocr_res_dict = result_class.objects.filter(id=ocr_res_id).values(*consts.COMPARE_FIELDS).first() |
1192 | if ocr_res_dict is None: | 1409 | if ocr_res_dict is None: |
1193 | compare_log.info('{0} [ocr info empty] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] ' | 1410 | compare_log.info('{0} [ocr info empty] [entity={1}] [id={2}] [uniq_seq={3}] [ocr_res_id={4}] ' |
1194 | '[is_ca={5}]'.format(log_base, application_entity, application_id, uniq_seq, ocr_res_id, is_ca)) | 1411 | '[is_ca={5}] [is_cms]={6}'.format(log_base, application_entity, application_id, |
1412 | uniq_seq, ocr_res_id, is_ca, is_cms)) | ||
1195 | return | 1413 | return |
1196 | 1414 | ||
1197 | if is_ca: | 1415 | if is_ca: |
1198 | ca_compare(application_id, application_entity, ocr_res_id, last_obj, ocr_res_dict) | 1416 | ca_compare(application_id, application_entity, ocr_res_id, last_obj, ocr_res_dict) |
1199 | else: | 1417 | else: |
1200 | se_compare(application_id, application_entity, ocr_res_id, last_obj, ocr_res_dict) | 1418 | se_compare(application_id, application_entity, ocr_res_id, last_obj, ocr_res_dict, is_cms) |
1201 | 1419 | ||
1202 | 1420 | ||
1203 | 1421 | ... | ... |
... | @@ -36,6 +36,7 @@ class RedisHandler: | ... | @@ -36,6 +36,7 @@ class RedisHandler: |
36 | self.common_queue_key = '{0}:common_queue'.format(self.prefix) | 36 | self.common_queue_key = '{0}:common_queue'.format(self.prefix) |
37 | self.priority_queue_key = '{0}:priority_queue'.format(self.prefix) | 37 | self.priority_queue_key = '{0}:priority_queue'.format(self.prefix) |
38 | self.session_id_key = '{0}:session_id'.format(self.prefix) | 38 | self.session_id_key = '{0}:session_id'.format(self.prefix) |
39 | self.cms_token_key = '{0}:cms_token'.format(self.prefix) | ||
39 | 40 | ||
40 | def enqueue(self, tasks, is_priority=False): | 41 | def enqueue(self, tasks, is_priority=False): |
41 | # 1 | 42 | # 1 |
... | @@ -57,3 +58,9 @@ class RedisHandler: | ... | @@ -57,3 +58,9 @@ class RedisHandler: |
57 | def get_session_id(self): | 58 | def get_session_id(self): |
58 | return self.redis.get(self.session_id_key) | 59 | return self.redis.get(self.session_id_key) |
59 | 60 | ||
61 | def get_cms_token(self): | ||
62 | return self.redis.get(self.cms_token_key) | ||
63 | |||
64 | def set_cms_token(self, token, expires=None): | ||
65 | return self.redis.set(self.cms_token_key, token, expires) | ||
66 | ... | ... |
src/common/tools/des.py
0 → 100644
1 | from Crypto.Cipher import DES3 | ||
2 | from Crypto.Hash import MD5 | ||
3 | import struct | ||
4 | import base64 | ||
5 | import codecs | ||
6 | |||
7 | |||
8 | def mds_hash(target_str): | ||
9 | h = MD5.new() | ||
10 | h.update(target_str.encode('utf-8')) | ||
11 | return h.digest() | ||
12 | |||
13 | |||
14 | def des_pad(data): | ||
15 | data = data.encode('utf-8') | ||
16 | e = len(data) | ||
17 | x = (e + 4) % 8 | ||
18 | y = 0 if x == 0 else 8 - x | ||
19 | size_byte = struct.pack('>I', e) | ||
20 | result_byte = list(range(len(size_byte) + e + y)) | ||
21 | result_byte[0:4] = size_byte | ||
22 | result_byte[4:4 + e] = data | ||
23 | for i in range(0, y): | ||
24 | result_byte[e + 4 + i] = 0 | ||
25 | result_str = bytearray(result_byte).decode('utf-8') | ||
26 | return result_str | ||
27 | |||
28 | |||
29 | # DES3加密数据 | ||
30 | def encode_des(to_encode_str, des_key): | ||
31 | """ | ||
32 | DES3加密数据 | ||
33 | Args: | ||
34 | to_encode_str(str): 要被加密的原字符串,这里的字符串需要被des_pad一下 | ||
35 | des_key(str): 加密的key | ||
36 | Returns: | ||
37 | |||
38 | """ | ||
39 | key = mds_hash(des_key) | ||
40 | des3 = DES3.new(key, DES3.MODE_ECB) | ||
41 | data = des3.encrypt(des_pad(to_encode_str)) | ||
42 | data = codecs.encode(data, 'hex') | ||
43 | return data | ||
44 | |||
45 | |||
46 | def un_des_pad(data): | ||
47 | result_byte = data[0:4] | ||
48 | e = struct.unpack('>I', result_byte)[0] | ||
49 | x = (e + 4) % 8 | ||
50 | y = 0 if x == 0 else 8 - x | ||
51 | return data[4:] if y == 0 else data[4:-y] | ||
52 | |||
53 | |||
54 | def decode_des(to_decode_str, des_key): | ||
55 | """ | ||
56 | 解密数据 | ||
57 | Args: | ||
58 | to_decode_str(str): 要解密的原字符串 | ||
59 | des_key(str): 解密的key | ||
60 | Returns: | ||
61 | |||
62 | """ | ||
63 | key = mds_hash(des_key) | ||
64 | des3 = DES3.new(key, DES3.MODE_ECB) | ||
65 | param = base64.b64decode(to_decode_str) | ||
66 | |||
67 | param = des3.decrypt(param) | ||
68 | param = un_des_pad(param).decode('utf-8') | ||
69 | return param |
src/common/tools/mssql_script9.py
0 → 100644
1 | import pyodbc | ||
2 | |||
3 | hil_sql = """ | ||
4 | create table afc_se_cms_info | ||
5 | ( | ||
6 | id bigint identity primary key, | ||
7 | application_id nvarchar(64) not null, | ||
8 | content nvarchar(max) not null, | ||
9 | update_time datetime not null, | ||
10 | create_time datetime not null | ||
11 | ); | ||
12 | |||
13 | create index afc_se_cms_info_application_id_index | ||
14 | on afc_se_cms_info (application_id); | ||
15 | |||
16 | create index afc_se_cms_info_create_time_index | ||
17 | on afc_se_cms_info (create_time); | ||
18 | """ | ||
19 | |||
20 | afc_sql = """ | ||
21 | create table hil_se_cms_info | ||
22 | ( | ||
23 | id bigint identity primary key, | ||
24 | application_id nvarchar(64) not null, | ||
25 | content nvarchar(max) not null, | ||
26 | update_time datetime not null, | ||
27 | create_time datetime not null | ||
28 | ); | ||
29 | |||
30 | create index hil_se_cms_info_application_id_index | ||
31 | on hil_se_cms_info (application_id); | ||
32 | |||
33 | create index hil_se_cms_info_create_time_index | ||
34 | on hil_se_cms_info (create_time); | ||
35 | """ | ||
36 | |||
37 | hil_cnxn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};', autocommit=True) | ||
38 | |||
39 | hil_cursor = hil_cnxn.cursor() | ||
40 | hil_cursor.execute(hil_sql) | ||
41 | |||
42 | hil_cursor.close() | ||
43 | hil_cnxn.close() | ||
44 | |||
45 | afc_cnxn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};', autocommit=True) | ||
46 | |||
47 | afc_cursor = afc_cnxn.cursor() | ||
48 | afc_cursor.execute(afc_sql) | ||
49 | |||
50 | afc_cursor.close() | ||
51 | afc_cnxn.close() |
-
Please register or sign in to post a comment