369697a8 by 周伟奇

fix merge

2 parents db2ce2cf ec8b39ff
...@@ -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="唯一序列号") # 索引?
......
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 = '''
......
...@@ -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
......
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
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()
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!