This commit is contained in:
27942
2026-01-20 19:30:36 +08:00
parent dd730ed9a1
commit 48c361edba

View File

@@ -76,22 +76,18 @@ def search_related_records(client_info, party_info, exclude_project_id=None):
if not client_info and not party_info:
return result
# 从client_info和party_info中提取姓名/名称(简单提取,假设第一个逗号前的部分或整个字符串)
# 这里使用包含匹配icontains来查找
client_name = client_info.strip() if client_info else ""
party_name = party_info.strip() if party_info else ""
# 解析委托人信息和相对方信息
client_parsed = parse_person_info(client_info) if client_info else {'name': '', 'id_number': '', 'original': ''}
party_parsed = parse_person_info(party_info) if party_info else {'name': '', 'id_number': '', 'original': ''}
# 提取可能的姓名取逗号、空格、换行符前的部分或整个字符串的前50个字符
if client_name:
# 尝试提取姓名(去除身份证号、统一社会信用代码等)
client_match = re.match(r'^[^,\n\r\t\d]{1,50}', client_name)
if client_match:
client_name = client_match.group(0).strip()
# 提取姓名/名称(用于匹配
client_name = client_parsed['name']
client_id_number = client_parsed['id_number']
client_original = client_parsed['original']
if party_name:
party_match = re.match(r'^[^,\n\r\t\d]{1,50}', party_name)
if party_match:
party_name = party_match.group(0).strip()
party_name = party_parsed['name']
party_id_number = party_parsed['id_number']
party_original = party_parsed['original']
# 检索预立案表 - 查找委托人和相对方都匹配的记录(冲突数据)
# 注意:预立案和立项是完全独立的,没有关联关系,只根据委托人和相对方信息匹配
@@ -109,12 +105,9 @@ def search_related_records(client_info, party_info, exclude_project_id=None):
is_same_person_in_project = False
if client_name and party_name and client_name.strip() == party_name.strip():
is_same_person_in_project = True
elif client_info and party_info:
# 提取第一个逗号前的部分进行比较
client_first_part = client_info.split('')[0].split(',')[0].strip() if '' in client_info or ',' in client_info else client_info[:30].strip()
party_first_part = party_info.split('')[0].split(',')[0].strip() if '' in party_info or ',' in party_info else party_info[:30].strip()
if client_first_part and party_first_part and client_first_part == party_first_part:
is_same_person_in_project = True
elif client_id_number and party_id_number and client_id_number == party_id_number:
# 通过身份证号判断是否为同一人
is_same_person_in_project = True
# 遍历预立案记录解析JSON格式并匹配
prefiling_all = PreFiling.objects.filter(is_deleted=False)
@@ -168,35 +161,35 @@ def search_related_records(client_info, party_info, exclude_project_id=None):
# 检查正向匹配:预立案的委托人是否在立项的委托人信息中,预立案的相对方是否在立项的相对方信息中
for pf_client in pf_client_names:
if client_info and pf_client in client_info:
if client_name and pf_client in client_name:
client_match = True
break
elif client_name and pf_client in client_name:
elif client_original and pf_client in client_original:
client_match = True
break
for pf_party in pf_party_names:
if party_info and pf_party in party_info:
if party_name and pf_party in party_name:
party_match = True
break
elif party_name and pf_party in party_name:
elif party_original and pf_party in party_original:
party_match = True
break
# 检查反向匹配:预立案的委托人是否在立项的相对方信息中,预立案的相对方是否在立项的委托人信息中
for pf_client in pf_client_names:
if party_info and pf_client in party_info:
if party_name and pf_client in party_name:
reverse_client_match = True
break
elif party_name and pf_client in party_name:
elif party_original and pf_client in party_original:
reverse_client_match = True
break
for pf_party in pf_party_names:
if client_info and pf_party in client_info:
if client_name and pf_party in client_name:
reverse_party_match = True
break
elif client_name and pf_party in client_name:
elif client_original and pf_party in client_original:
reverse_party_match = True
break
@@ -212,21 +205,21 @@ def search_related_records(client_info, party_info, exclude_project_id=None):
# 预立案中委托人和相对方是同一个人,检查这个共同的名字是否在立项信息中
common_names = set(pf_client_names) & set(pf_party_names)
for common_name in common_names:
if (client_info and common_name in client_info) or (client_name and common_name in client_name) or \
(party_info and common_name in party_info) or (party_name and common_name in party_name):
if (client_name and common_name in client_name) or (party_name and common_name in party_name) or \
(client_original and common_name in client_original) or (party_original and common_name in party_original):
is_conflict = True
break
elif is_same_person_in_project:
# 立项中委托人和相对方是同一个人,检查这个共同的名字是否在预立案信息中
for pf_client in pf_client_names:
if (client_info and pf_client in client_info) or (client_name and pf_client in client_name) or \
(party_info and pf_client in party_info) or (party_name and pf_client in party_name):
if (client_name and pf_client in client_name) or (party_name and pf_client in party_name) or \
(client_original and pf_client in client_original) or (party_original and pf_client in party_original):
is_conflict = True
break
if not is_conflict:
for pf_party in pf_party_names:
if (client_info and pf_party in client_info) or (client_name and pf_party in client_name) or \
(party_info and pf_party in party_info) or (party_name and pf_party in party_name):
if (client_name and pf_party in client_name) or (party_name and pf_party in party_name) or \
(client_original and pf_party in client_original) or (party_original and pf_party in party_original):
is_conflict = True
break
@@ -248,10 +241,20 @@ def search_related_records(client_info, party_info, exclude_project_id=None):
project_records = project_records.exclude(id=exclude_project_id)
# 委托人和相对方都匹配,或者相对方和委托人都匹配(可能是顺序相反)
project_records = project_records.filter(
(Q(client_info__icontains=client_info[:50]) & Q(party_info__icontains=party_info[:50])) |
(Q(client_info__icontains=party_info[:50]) & Q(party_info__icontains=client_info[:50]))
)
# 支持姓名和完整信息匹配
project_q = Q()
if client_name and party_name:
project_q |= (Q(client_info__icontains=client_name) & Q(party_info__icontains=party_name))
project_q |= (Q(client_info__icontains=party_name) & Q(party_info__icontains=client_name))
if client_original and party_original:
project_q |= (Q(client_info__icontains=client_original[:50]) & Q(party_info__icontains=party_original[:50]))
project_q |= (Q(client_info__icontains=party_original[:50]) & Q(party_info__icontains=client_original[:50]))
if client_id_number and party_id_number:
project_q |= (Q(client_info__icontains=client_id_number) & Q(party_info__icontains=party_id_number))
project_q |= (Q(client_info__icontains=party_id_number) & Q(party_info__icontains=client_id_number))
if project_q:
project_records = project_records.filter(project_q)
# 获取项目列表最多10条
project_list = list(project_records[:10].values('id', 'ContractNo', 'times', 'type', 'client_info', 'party_info'))
@@ -268,18 +271,17 @@ def search_related_records(client_info, party_info, exclude_project_id=None):
if party_name:
bid_q |= Q(BiddingUnit__icontains=party_name)
# 如果有完整的client_info和party_info也尝试匹配截取前50个字符
if client_info:
# 提取client_info中的关键信息去除标点符号和数字后的名称部分
client_info_clean = client_info[:50].strip()
if client_info_clean:
bid_q |= Q(BiddingUnit__icontains=client_info_clean)
# 如果有完整信息,也尝试匹配
if client_original:
bid_q |= Q(BiddingUnit__icontains=client_original[:50])
if party_original:
bid_q |= Q(BiddingUnit__icontains=party_original[:50])
if party_info:
# 提取party_info中的关键信息
party_info_clean = party_info[:50].strip()
if party_info_clean:
bid_q |= Q(BiddingUnit__icontains=party_info_clean)
# 如果有身份证号,也尝试匹配
if client_id_number:
bid_q |= Q(BiddingUnit__icontains=client_id_number)
if party_id_number:
bid_q |= Q(BiddingUnit__icontains=party_id_number)
# 如果构建了查询条件,执行查询
if bid_q:
@@ -3758,6 +3760,68 @@ class CaseChangeRequestDetail(APIView):
}, status=status.HTTP_200_OK)
def parse_person_info(person_str):
"""
解析人员信息字符串,支持多种格式:
- "张三3263452342342342"
- "张三身份证号3263452342342342"
- "张三,3263452342342342"
- "张三"
Returns:
dict: {
'name': '张三',
'id_number': '3263452342342342', # 可能为空
'original': '张三3263452342342342' # 原始字符串
}
"""
if not person_str:
return {'name': '', 'id_number': '', 'original': ''}
person_str = str(person_str).strip()
result = {
'name': '',
'id_number': '',
'original': person_str
}
# 匹配格式张三3263452342342342或张三(3263452342342342)
match = re.match(r'^([^(]+?)[(]([^)]+)[)]', person_str)
if match:
result['name'] = match.group(1).strip()
result['id_number'] = match.group(2).strip()
return result
# 匹配格式张三身份证号3263452342342342 或 张三,身份证号:3263452342342342
match = re.match(r'^([^,]+?)[,]\s*[身身]份证[号号]?[:]?\s*([^\s,]+)', person_str)
if match:
result['name'] = match.group(1).strip()
result['id_number'] = match.group(2).strip()
return result
# 匹配格式:张三,3263452342342342逗号分隔
match = re.match(r'^([^,]+?)[,]\s*(\d{15,18})', person_str)
if match:
result['name'] = match.group(1).strip()
result['id_number'] = match.group(2).strip()
return result
# 如果没有匹配到特定格式,尝试提取姓名(去除可能的身份证号)
# 先尝试提取姓名部分(去除末尾的数字)
name_match = re.match(r'^([^,\d(]+)', person_str)
if name_match:
result['name'] = name_match.group(1).strip()
else:
result['name'] = person_str
# 尝试提取身份证号15-18位数字
id_match = re.search(r'(\d{15,18})', person_str)
if id_match:
result['id_number'] = id_match.group(1)
return result
def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_unit=None, exclude_prefiling_id=None, exclude_project_id=None, exclude_bid_id=None):
"""
利益冲突检索函数 - 比对预立案登记、投标登记、立项登记三张表
@@ -3789,22 +3853,18 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_
if not any([client_info, party_info, undertaker, bidding_unit]):
return result
# 解析委托人信息和相对方信息
client_parsed = parse_person_info(client_info) if client_info else {'name': '', 'id_number': '', 'original': ''}
party_parsed = parse_person_info(party_info) if party_info else {'name': '', 'id_number': '', 'original': ''}
# 提取姓名/名称(用于匹配)
client_name = ""
party_name = ""
client_name = client_parsed['name']
client_id_number = client_parsed['id_number']
client_original = client_parsed['original']
if client_info:
client_name = client_info.strip()
# 提取可能的姓名(取逗号、空格、换行符前的部分)
client_match = re.match(r'^[^,\n\r\t\d]{1,50}', client_name)
if client_match:
client_name = client_match.group(0).strip()
if party_info:
party_name = party_info.strip()
party_match = re.match(r'^[^,\n\r\t\d]{1,50}', party_name)
if party_match:
party_name = party_match.group(0).strip()
party_name = party_parsed['name']
party_id_number = party_parsed['id_number']
party_original = party_parsed['original']
# 1. 检索预立案表
prefiling_q = Q(is_deleted=False)
@@ -3847,33 +3907,94 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_
except (json.JSONDecodeError, TypeError, AttributeError):
pf_party_names = [pf.party_username.strip()] if pf.party_username else []
# 检查委托人匹配
# 检查委托人匹配(支持姓名和身份证号匹配)
if client_info or client_name:
for pf_client in pf_client_names:
if (client_info and pf_client in client_info) or (client_name and pf_client in client_name):
# 匹配姓名
if client_name and pf_client in client_name:
is_match = True
match_reason.append(f"委托人匹配:{pf_client}")
match_reason.append(f"委托人姓名匹配:{pf_client}")
break
# 匹配完整信息
if client_original and pf_client in client_original:
is_match = True
match_reason.append(f"委托人信息匹配:{pf_client}")
break
# 检查相对方是否匹配委托人
for pf_party in pf_party_names:
if (client_info and pf_party in client_info) or (client_name and pf_party in client_name):
if client_name and pf_party in client_name:
is_match = True
match_reason.append(f"相对方与委托人匹配:{pf_party}")
match_reason.append(f"相对方与委托人姓名匹配:{pf_party}")
break
if client_original and pf_party in client_original:
is_match = True
match_reason.append(f"相对方与委托人信息匹配:{pf_party}")
break
# 检查相对方匹配
# 检查相对方匹配(支持姓名和身份证号匹配)
if party_info or party_name:
for pf_party in pf_party_names:
if (party_info and pf_party in party_info) or (party_name and pf_party in party_name):
# 匹配姓名
if party_name and pf_party in party_name:
is_match = True
match_reason.append(f"相对方匹配:{pf_party}")
match_reason.append(f"相对方姓名匹配:{pf_party}")
break
# 匹配完整信息
if party_original and pf_party in party_original:
is_match = True
match_reason.append(f"相对方信息匹配:{pf_party}")
break
# 检查委托人是否匹配相对方
for pf_client in pf_client_names:
if (party_info and pf_client in party_info) or (party_name and pf_client in party_name):
if party_name and pf_client in party_name:
is_match = True
match_reason.append(f"委托人与相对方匹配:{pf_client}")
match_reason.append(f"委托人与相对方姓名匹配:{pf_client}")
break
if party_original and pf_client in party_original:
is_match = True
match_reason.append(f"委托人与相对方信息匹配:{pf_client}")
break
# 检查身份证号匹配(如果提供了身份证号)
if client_id_number:
# 检查预立案中的身份证号
try:
client_data = json.loads(pf.client_username) if isinstance(pf.client_username, str) else pf.client_username
if isinstance(client_data, list):
for item in client_data:
if isinstance(item, dict):
pf_id = item.get('idNumber', '') or item.get('id_number', '')
if pf_id and client_id_number in str(pf_id):
is_match = True
match_reason.append(f"委托人身份证号匹配")
break
elif isinstance(client_data, dict):
pf_id = client_data.get('idNumber', '') or client_data.get('id_number', '')
if pf_id and client_id_number in str(pf_id):
is_match = True
match_reason.append(f"委托人身份证号匹配")
except (json.JSONDecodeError, TypeError, AttributeError):
pass
if party_id_number:
# 检查预立案中的身份证号
try:
party_data = json.loads(pf.party_username) if isinstance(pf.party_username, str) else pf.party_username
if isinstance(party_data, list):
for item in party_data:
if isinstance(item, dict):
pf_id = item.get('idNumber', '') or item.get('id_number', '')
if pf_id and party_id_number in str(pf_id):
is_match = True
match_reason.append(f"相对方身份证号匹配")
break
elif isinstance(party_data, dict):
pf_id = party_data.get('idNumber', '') or party_data.get('id_number', '')
if pf_id and party_id_number in str(pf_id):
is_match = True
match_reason.append(f"相对方身份证号匹配")
except (json.JSONDecodeError, TypeError, AttributeError):
pass
# 检查承办人员匹配
if undertaker and pf.Undertaker:
@@ -3906,22 +4027,64 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_
is_match = False
match_reason = []
# 检查委托人/相对方匹配
# 检查委托人/相对方匹配(支持姓名和身份证号匹配)
if client_info or client_name:
if pro.client_info and ((client_info and client_info[:50] in pro.client_info) or (client_name and client_name in pro.client_info)):
is_match = True
match_reason.append("委托人匹配")
if pro.party_info and ((client_info and client_info[:50] in pro.party_info) or (client_name and client_name in pro.party_info)):
is_match = True
match_reason.append("相对方与委托人匹配")
if pro.client_info:
# 匹配姓名
if client_name and client_name in pro.client_info:
is_match = True
match_reason.append("委托人姓名匹配")
# 匹配完整信息
elif client_original and client_original in pro.client_info:
is_match = True
match_reason.append("委托人信息匹配")
# 匹配身份证号
elif client_id_number and client_id_number in pro.client_info:
is_match = True
match_reason.append("委托人身份证号匹配")
if pro.party_info:
# 匹配姓名
if client_name and client_name in pro.party_info:
is_match = True
match_reason.append("相对方与委托人姓名匹配")
# 匹配完整信息
elif client_original and client_original in pro.party_info:
is_match = True
match_reason.append("相对方与委托人信息匹配")
# 匹配身份证号
elif client_id_number and client_id_number in pro.party_info:
is_match = True
match_reason.append("相对方与委托人身份证号匹配")
if party_info or party_name:
if pro.party_info and ((party_info and party_info[:50] in pro.party_info) or (party_name and party_name in pro.party_info)):
is_match = True
match_reason.append("相对方匹配")
if pro.client_info and ((party_info and party_info[:50] in pro.client_info) or (party_name and party_name in pro.client_info)):
is_match = True
match_reason.append("委托人与相对方匹配")
if pro.party_info:
# 匹配姓名
if party_name and party_name in pro.party_info:
is_match = True
match_reason.append("相对方姓名匹配")
# 匹配完整信息
elif party_original and party_original in pro.party_info:
is_match = True
match_reason.append("相对方信息匹配")
# 匹配身份证号
elif party_id_number and party_id_number in pro.party_info:
is_match = True
match_reason.append("相对方身份证号匹配")
if pro.client_info:
# 匹配姓名
if party_name and party_name in pro.client_info:
is_match = True
match_reason.append("委托人与相对方姓名匹配")
# 匹配完整信息
elif party_original and party_original in pro.client_info:
is_match = True
match_reason.append("委托人与相对方信息匹配")
# 匹配身份证号
elif party_id_number and party_id_number in pro.client_info:
is_match = True
match_reason.append("委托人与相对方身份证号匹配")
# 检查负责人匹配
if undertaker and pro.responsiblefor:
@@ -3975,16 +4138,28 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_
is_match = True
match_reason.append("招标单位匹配")
# 检查委托人/相对方是否在招标单位中
# 检查委托人/相对方是否在招标单位中(支持姓名和身份证号匹配)
if (client_info or client_name) and bid.BiddingUnit:
if (client_info and client_info[:50] in bid.BiddingUnit) or (client_name and client_name in bid.BiddingUnit):
if client_name and client_name in bid.BiddingUnit:
is_match = True
match_reason.append("委托人姓名在招标单位中")
elif client_original and client_original in bid.BiddingUnit:
is_match = True
match_reason.append("委托人信息在招标单位中")
elif client_id_number and client_id_number in bid.BiddingUnit:
is_match = True
match_reason.append("委托人身份证号在招标单位中")
if (party_info or party_name) and bid.BiddingUnit:
if (party_info and party_info[:50] in bid.BiddingUnit) or (party_name and party_name in bid.BiddingUnit):
if party_name and party_name in bid.BiddingUnit:
is_match = True
match_reason.append("相对方姓名在招标单位中")
elif party_original and party_original in bid.BiddingUnit:
is_match = True
match_reason.append("相对方信息在招标单位中")
elif party_id_number and party_id_number in bid.BiddingUnit:
is_match = True
match_reason.append("相对方身份证号在招标单位中")
if is_match:
bid_list.append({
@@ -4011,8 +4186,12 @@ class ConflictSearch(APIView):
利益冲突检索
请求参数(至少提供一个):
- client_info: 委托人身份信息(可选)
- party_info: 相对方身份信息(可选)
- client_info: 委托人身份信息(可选),支持格式:
* "张三3263452342342342"
* "张三身份证号3263452342342342"
* "张三,3263452342342342"
* "张三"
- party_info: 相对方身份信息(可选),支持格式同上
- undertaker: 承办人员(可选)
- bidding_unit: 招标单位(可选)
- exclude_prefiling_id: 要排除的预立案ID可选