test_notifications.py 4.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import pytest
  2. from sqlalchemy import delete
  3. from test_after_sales import scenario # noqa: F401
  4. from test_conversations import setup
  5. from zhifu.modules.identity.access_models import StoreGrant
  6. pytestmark = pytest.mark.integration
  7. async def inbox(context, actor="agent"):
  8. response = await context["call"](
  9. "GET", f"/admin/v1/notifications?store_id={context['store']}&limit=100", actor
  10. )
  11. assert response.status_code == 200, response.text
  12. return response.json()
  13. async def test_customer_message_recipient_and_read_snapshot(scenario): # noqa: F811
  14. path = await setup(scenario)
  15. call = scenario["call"]
  16. takeover = await call("POST", path + "/takeover", "agent", {"expected_control_version": 1})
  17. assert takeover.status_code == 200, takeover.text
  18. message = {"text": "请人工核实商品信息", "expected_control_version": 2}
  19. first = await call("POST", path + "/messages", payload=message, key="notification-message")
  20. repeated = await call("POST", path + "/messages", payload=message, key="notification-message")
  21. assert first.status_code == 201 and first.json() == repeated.json()
  22. initial = await inbox(scenario)
  23. assert initial["unread_count"] == 1
  24. item = initial["items"][0]
  25. assert item["target_id"] == path.rsplit("/", 1)[1]
  26. assert message["text"] not in item["summary"]
  27. assert (await inbox(scenario, "reviewer"))["items"] == []
  28. unauthorized = await call("GET", f"/admin/v1/notifications/{item['id']}", "reviewer")
  29. assert unauthorized.status_code == 404
  30. second = await call("POST", path + "/messages", payload={**message, "text": "补充说明"})
  31. assert second.status_code == 201
  32. read = await call("POST", "/admin/v1/notifications/read-all", "agent", {
  33. "store_id": str(scenario["store"]), "through_id": initial["snapshot_id"],
  34. })
  35. assert read.json() == {"updated": 1}
  36. again = await call("POST", "/admin/v1/notifications/read", "agent", {"ids": [item["id"]]})
  37. assert again.json() == {"updated": 0}
  38. latest = await inbox(scenario)
  39. assert latest["unread_count"] == 1 and len(latest["items"]) == 2
  40. unread = next(row for row in latest["items"] if not row["read"])
  41. detail = await call("GET", f"/admin/v1/notifications/{unread['id']}", "agent")
  42. assert detail.status_code == 200 and detail.json()["read"]
  43. assert (await inbox(scenario))["unread_count"] == 0
  44. customer = await call("GET", f"/admin/v1/notifications?store_id={scenario['store']}")
  45. assert customer.status_code == 403
  46. async def test_notifications_follow_current_permission_and_tenant(scenario): # noqa: F811
  47. path = await setup(scenario)
  48. call = scenario["call"]
  49. assert (await call(
  50. "POST", path + "/takeover", "agent", {"expected_control_version": 1}
  51. )).status_code == 200
  52. assert (await call(
  53. "POST", path + "/messages", payload={"text": "请查看", "expected_control_version": 2}
  54. )).status_code == 201
  55. item = (await inbox(scenario))["items"][0]
  56. foreign = await call("GET", f"/admin/v1/notifications/{item['id']}", "foreign")
  57. assert foreign.status_code == 403
  58. async with scenario["app"].state.sessions.begin() as session:
  59. await session.execute(delete(StoreGrant).where(
  60. StoreGrant.tenant_id == scenario["tenant"].bytes,
  61. StoreGrant.principal_id == scenario["accounts"]["agent"].bytes,
  62. StoreGrant.permission == "conversations:read",
  63. ))
  64. assert (await inbox(scenario))["items"] == []
  65. assert (await call("GET", f"/admin/v1/notifications/{item['id']}", "agent")).status_code == 404
  66. async def test_confirmed_proposal_creates_persistent_approval_notice(scenario): # noqa: F811
  67. call = scenario["call"]
  68. created = await call("POST", "/openapi/v1/after-sales/proposals", payload=scenario["proposal"])
  69. assert created.status_code == 201, created.text
  70. ticket = created.json()
  71. response = await call(
  72. "POST", f"/openapi/v1/after-sales/proposals/{ticket['proposal_id']}/confirm",
  73. payload={"proposal_version": ticket["proposal_version"],
  74. "expected_ticket_version": ticket["version"]}, key="confirm-notice",
  75. )
  76. assert response.status_code == 200, response.text
  77. notices = (await inbox(scenario, "reviewer"))["items"]
  78. assert len(notices) == 1 and notices[0]["target_id"] == ticket["ticket_id"]
  79. assert notices[0]["page"] == "approvals" and not notices[0]["read"]