diff --git a/business/views.py b/business/views.py index 95cf7a5..7171187 100644 --- a/business/views.py +++ b/business/views.py @@ -4377,9 +4377,29 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_ client_names, client_id_numbers, client_originals = _extract_all_person_info(client_info) party_names, party_id_numbers, party_originals = _extract_all_person_info(party_info) - # 身份证号统一用规范化后的值做精准匹配(完全相等才命中) - _client_ids_set = {_normalize_id(c) for c in client_id_numbers if _normalize_id(c)} - _party_ids_set = {_normalize_id(p) for p in party_id_numbers if _normalize_id(p)} + # 按「人」成对:每人 (姓名, 规范化身份证)。当同时填了姓名+身份证时,必须同一人两项都一致才命中 + def _person_pairs(names, id_numbers): + out = [] + for i in range(max(len(names), len(id_numbers))): + name = (names[i] if i < len(names) else '').strip() + id_norm = _normalize_id(id_numbers[i]) if i < len(id_numbers) else '' + if name or id_norm: + out.append((name, id_norm)) + return out + + client_persons = _person_pairs(client_names, client_id_numbers) + party_persons = _person_pairs(party_names, party_id_numbers) + + def _person_match(record_name, record_id_norm, search_persons): + """记录中的一人 (record_name, record_id_norm) 是否与任意搜索人精准匹配(姓名+身份证都一致)。""" + for sn, si in search_persons: + if not sn and not si: + continue + name_ok = (not sn) or (record_name == sn) + id_ok = (not si) or (record_id_norm == si) + if name_ok and id_ok: + return True + return False # 1. 检索预立案表 prefiling_q = Q(is_deleted=False) @@ -4445,50 +4465,20 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_ if pf.party_username: pf_party_names = [pf.party_username.strip()] - # 冲突规则:精准匹配。当前委托人只与历史「委托人」匹配,当前相对方只与历史「相对方」匹配;身份证号规范化后完全相等才匹配 - _client_names_set = {cn.strip() for cn in client_names} - _party_names_set = {pn.strip() for pn in party_names} - # 委托人姓名精准匹配 - if client_names and pf_client_names: - for pf_c in pf_client_names: - if pf_c.strip() in _client_names_set: + # 冲突规则:按「人」精准匹配,同一人必须姓名+身份证都一致才命中 + pf_client_persons = _person_pairs(pf_client_names, [_normalize_id(x) for x in pf_client_ids]) + pf_party_persons = _person_pairs(pf_party_names, [_normalize_id(x) for x in pf_party_ids]) + if client_persons and pf_client_persons: + for rn, ri in pf_client_persons: + if _person_match(rn, ri, client_persons): is_match = True - match_reason.append(f"委托人姓名匹配:{pf_c}") + match_reason.append(f"委托人匹配:{rn or ri or '身份证'}") break - if not is_match and client_originals: - _originals_set = {co.strip() for co in client_originals} - for pf_c in pf_client_names: - if pf_c.strip() in _originals_set: - is_match = True - match_reason.append(f"委托人信息匹配:{pf_c}") - break - # 委托人身份证号精准匹配(规范化后完全一致) - if _client_ids_set and pf_client_ids: - for pf_cid in pf_client_ids: - if _normalize_id(pf_cid) in _client_ids_set: + if party_persons and pf_party_persons: + for rn, ri in pf_party_persons: + if _person_match(rn, ri, party_persons): is_match = True - match_reason.append("委托人身份证号匹配") - break - # 相对方姓名精准匹配 - if party_names and pf_party_names: - for pf_p in pf_party_names: - if pf_p.strip() in _party_names_set: - is_match = True - match_reason.append(f"相对方姓名匹配:{pf_p}") - break - if not any("相对方" in r for r in match_reason) and party_originals: - _party_originals_set = {po.strip() for po in party_originals} - for pf_p in pf_party_names: - if pf_p.strip() in _party_originals_set: - is_match = True - match_reason.append(f"相对方信息匹配:{pf_p}") - break - # 相对方身份证号精准匹配(规范化后完全一致) - if _party_ids_set and pf_party_ids: - for pf_pid in pf_party_ids: - if _normalize_id(pf_pid) in _party_ids_set: - is_match = True - match_reason.append("相对方身份证号匹配") + match_reason.append(f"相对方匹配:{rn or ri or '身份证'}") break # 承办人员精准匹配 @@ -4518,34 +4508,27 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_ project_records = ProjectRegistration.objects.filter(project_q) project_list = [] - _client_names_set = {cn.strip() for cn in client_names} - _party_names_set = {pn.strip() for pn in party_names} - for pro in project_records[:50]: is_match = False match_reason = [] - # 冲突规则:精准匹配。从立项记录的 client_info/party_info 解析出姓名、身份证号再比对;身份证号规范化后完全一致才匹配 - if (client_names or client_id_numbers) and pro.client_info: + # 冲突规则:按「人」精准匹配,同一人必须姓名+身份证都一致才命中 + if client_persons and pro.client_info: pro_client_names, pro_client_ids, _ = _extract_all_person_info(pro.client_info) - pro_cn_set = {n.strip() for n in pro_client_names} - pro_cid_set = {_normalize_id(i) for i in pro_client_ids if _normalize_id(i)} - if client_names and (pro_cn_set & _client_names_set): - is_match = True - match_reason.append("委托人姓名匹配") - elif _client_ids_set and (pro_cid_set & _client_ids_set): - is_match = True - match_reason.append("委托人身份证号匹配") - if (party_names or party_id_numbers) and pro.party_info: + pro_client_persons = _person_pairs(pro_client_names, pro_client_ids) + for rn, ri in pro_client_persons: + if _person_match(rn, ri, client_persons): + is_match = True + match_reason.append("委托人匹配") + break + if party_persons and pro.party_info: pro_party_names, pro_party_ids, _ = _extract_all_person_info(pro.party_info) - pro_pn_set = {n.strip() for n in pro_party_names} - pro_pid_set = {_normalize_id(i) for i in pro_party_ids if _normalize_id(i)} - if party_names and (pro_pn_set & _party_names_set): - is_match = True - match_reason.append("相对方姓名匹配") - elif _party_ids_set and (pro_pid_set & _party_ids_set): - is_match = True - match_reason.append("相对方身份证号匹配") + pro_party_persons = _person_pairs(pro_party_names, pro_party_ids) + for rn, ri in pro_party_persons: + if _person_match(rn, ri, party_persons): + is_match = True + match_reason.append("相对方匹配") + break # 负责人精准匹配(与承办人字段完全一致才算匹配) if undertaker and pro.responsiblefor: @@ -4592,34 +4575,33 @@ def conflict_search(client_info=None, party_info=None, undertaker=None, bidding_ is_match = False match_reason = [] - # 从招标单位解析出名称、身份证/统一代码,用于精准匹配;身份证号规范化后完全一致才匹配 + # 从招标单位解析出人员列表,按「人」精准匹配(姓名+身份证都一致才命中) bid_names, bid_ids, _ = _extract_all_person_info(bid.BiddingUnit) if bid.BiddingUnit else ([], [], []) - bid_names_set = {n.strip() for n in bid_names} - bid_ids_set = {_normalize_id(i) for i in bid_ids if _normalize_id(i)} + bid_persons = _person_pairs(bid_names, bid_ids) - # 招标单位精准匹配:查询的招标单位与记录中的名称或证件号完全一致(证件号按规范化后比较) + # 招标单位精准匹配:查询的招标单位与记录中某一人完全一致(姓名或证件号单独查时按原逻辑) if bidding_unit and bid.BiddingUnit: ut = bidding_unit.strip() ut_norm = _normalize_id(bidding_unit) - if ut in bid_names_set or (ut_norm and ut_norm in bid_ids_set): - is_match = True - match_reason.append("招标单位匹配") + for rn, ri in bid_persons: + if ut == rn or (ut_norm and ut_norm == ri): + is_match = True + match_reason.append("招标单位匹配") + break - # 委托人/相对方与招标单位精准匹配(姓名或身份证号完全一致) - if (client_names or _client_ids_set) and bid.BiddingUnit: - if client_names and (bid_names_set & _client_names_set): - is_match = True - match_reason.append("委托人姓名在招标单位中") - elif _client_ids_set and (bid_ids_set & _client_ids_set): - is_match = True - match_reason.append("委托人身份证号在招标单位中") - if (party_names or _party_ids_set) and bid.BiddingUnit: - if party_names and (bid_names_set & _party_names_set): - is_match = True - match_reason.append("相对方姓名在招标单位中") - elif _party_ids_set and (bid_ids_set & _party_ids_set): - is_match = True - match_reason.append("相对方身份证号在招标单位中") + # 委托人/相对方与招标单位:同一人姓名+身份证都一致才命中 + if client_persons and bid_persons: + for rn, ri in bid_persons: + if _person_match(rn, ri, client_persons): + is_match = True + match_reason.append("委托人匹配招标单位") + break + if party_persons and bid_persons: + for rn, ri in bid_persons: + if _person_match(rn, ri, party_persons): + is_match = True + match_reason.append("相对方匹配招标单位") + break if is_match: bid_list.append({