test_party_customer_sync.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. """当事人三角色客户同步 / 撞库合并"""
  2. import unittest
  3. from unittest.mock import MagicMock, patch
  4. from app.services.party_customer_sync import (
  5. merge_customer_fields,
  6. sync_party_customers,
  7. ROLE_MOTHER,
  8. ROLE_FATHER,
  9. ROLE_NEWBORN,
  10. )
  11. class TestMergeCustomerFields(unittest.TestCase):
  12. def test_fill_empty_only_and_union_tags(self):
  13. target = MagicMock(
  14. customer_name="已有",
  15. phone_no="111",
  16. age=None,
  17. sex="2",
  18. remark="",
  19. customer_tags="vip",
  20. )
  21. source = MagicMock(
  22. phone_no="222",
  23. age=30,
  24. sex="1",
  25. remark="备注A",
  26. customer_tags="a,vip",
  27. )
  28. merge_customer_fields(target, source)
  29. self.assertEqual(target.phone_no, "111") # 不覆盖
  30. self.assertEqual(target.age, 30)
  31. self.assertEqual(target.sex, "1") # 目标为未知才补
  32. self.assertEqual(target.remark, "备注A")
  33. tags = set((target.customer_tags or "").split(","))
  34. self.assertEqual(tags, {"vip", "a"})
  35. self.assertEqual(target.customer_name, "已有")
  36. class TestSyncPartyCustomers(unittest.TestCase):
  37. def test_role_constants(self):
  38. self.assertEqual(ROLE_MOTHER, "mother")
  39. self.assertEqual(ROLE_FATHER, "father")
  40. self.assertEqual(ROLE_NEWBORN, "newborn")
  41. def test_no_name_clears_role_id(self):
  42. db = MagicMock()
  43. party = {
  44. "motherName": "",
  45. "customerId": "old-m",
  46. "fatherName": "",
  47. "fatherCustomerId": "old-f",
  48. }
  49. out = sync_party_customers(db, party, tenant_no="zkxw", user_id="u1")
  50. self.assertEqual(out.get("customer_id") or out.get("customerId"), "")
  51. self.assertEqual(out.get("father_customer_id") or out.get("fatherCustomerId"), "")
  52. def test_three_names_without_id_card_creates_three(self):
  53. db = MagicMock()
  54. created = []
  55. def fake_create(db_, **kwargs):
  56. obj = MagicMock()
  57. obj.id = f"c{len(created)+1}"
  58. created.append(kwargs)
  59. return obj
  60. party = {
  61. "motherName": "妈",
  62. "fatherName": "爸",
  63. "newbornName": "宝",
  64. "newbornSex": "0",
  65. }
  66. with patch("app.services.party_customer_sync.customer_crud.create_customer", side_effect=fake_create):
  67. with patch("app.services.party_customer_sync.find_customer_by_id_card", return_value=None):
  68. with patch("app.services.party_customer_sync.get_customer", return_value=None):
  69. out = sync_party_customers(db, party, tenant_no="zkxw", user_id="u1")
  70. self.assertEqual(len(created), 3)
  71. self.assertTrue(out.get("customer_id") or out.get("customerId"))
  72. self.assertTrue(out.get("father_customer_id") or out.get("fatherCustomerId"))
  73. self.assertTrue(out.get("newborn_customer_id") or out.get("newbornCustomerId"))
  74. sexes = {c["customer_name"]: c.get("sex") for c in created}
  75. self.assertEqual(sexes["妈"], "1")
  76. self.assertEqual(sexes["爸"], "0")
  77. self.assertEqual(sexes["宝"], "0")
  78. def test_snake_case_input_clears_and_keeps_other_fields(self):
  79. db = MagicMock()
  80. party = {
  81. "mother_name": "",
  82. "customer_id": "old-m",
  83. "remark": "keep-me",
  84. }
  85. out = sync_party_customers(db, party, tenant_no="zkxw", user_id="u1")
  86. self.assertEqual(out.get("customer_id"), "")
  87. self.assertEqual(out.get("remark"), "keep-me")
  88. def test_name_and_id_card_keeps_linked_id_when_not_found(self):
  89. db = MagicMock()
  90. linked = MagicMock()
  91. linked.id = "cust-a"
  92. linked.customer_name = "旧名"
  93. linked.phone_no = None
  94. linked.id_card_no = None
  95. party = {
  96. "mother_name": "妈",
  97. "mother_phone": "13900000000",
  98. "mother_id_card": "110101199001011234",
  99. "customer_id": "cust-a",
  100. }
  101. with patch("app.services.party_customer_sync.find_customer_by_id_card", return_value=None):
  102. with patch("app.services.party_customer_sync.get_customer", return_value=linked):
  103. with patch("app.services.party_customer_sync.customer_crud.create_customer") as create:
  104. out = sync_party_customers(db, party, tenant_no="zkxw", user_id="u1")
  105. create.assert_not_called()
  106. self.assertEqual(out.get("customer_id"), "cust-a")
  107. self.assertEqual(linked.customer_name, "妈")
  108. self.assertEqual(linked.phone_no, "13900000000")
  109. self.assertEqual(linked.id_card_no, "110101199001011234")
  110. def test_id_card_collision_merges_and_repoints(self):
  111. db = MagicMock()
  112. customer_a = MagicMock(
  113. id="A",
  114. customer_name="临时",
  115. phone_no="111",
  116. age=None,
  117. sex="2",
  118. remark="",
  119. customer_tags="tmp",
  120. )
  121. customer_b = MagicMock(
  122. id="B",
  123. customer_name="已有",
  124. phone_no="",
  125. age=None,
  126. sex="2",
  127. remark="",
  128. customer_tags="vip",
  129. )
  130. party = {
  131. "motherName": "妈",
  132. "motherIdCard": "110101199001011234",
  133. "customerId": "A",
  134. }
  135. def fake_get(db_, customer_id, tenant_no=None):
  136. mapping = {"A": customer_a, "B": customer_b}
  137. return mapping.get(customer_id)
  138. with patch("app.services.party_customer_sync.find_customer_by_id_card", return_value=customer_b):
  139. with patch("app.services.party_customer_sync.get_customer", side_effect=fake_get):
  140. with patch("app.services.party_customer_sync.repoint_customer_refs") as repoint:
  141. with patch(
  142. "app.services.party_customer_sync.customer_crud.soft_delete_customer"
  143. ) as soft_delete:
  144. out = sync_party_customers(db, party, tenant_no="zkxw", user_id="u1")
  145. self.assertEqual(out.get("customer_id") or out.get("customerId"), "B")
  146. repoint.assert_called_once()
  147. args, kwargs = repoint.call_args
  148. if args and len(args) >= 4:
  149. self.assertEqual(args[1], "A")
  150. self.assertEqual(args[2], "B")
  151. self.assertEqual(args[3], "zkxw")
  152. else:
  153. self.assertEqual(kwargs.get("from_id"), "A")
  154. self.assertEqual(kwargs.get("to_id"), "B")
  155. self.assertEqual(kwargs.get("tenant_no"), "zkxw")
  156. soft_delete.assert_called_once()
  157. sd_args, sd_kwargs = soft_delete.call_args
  158. deleted_id = sd_args[1] if len(sd_args) > 1 else sd_kwargs.get("customer_id")
  159. self.assertEqual(deleted_id, "A")
  160. self.assertEqual(customer_b.phone_no, "111")
  161. self.assertEqual(customer_b.customer_name, "已有")
  162. tags = set((customer_b.customer_tags or "").split(","))
  163. self.assertEqual(tags, {"vip", "tmp"})