from datetime import UTC, datetime from fastapi.testclient import TestClient from zbt.commands.seed import build_seed_manifest from zbt.core.config import Settings from zbt.core.passwords import PasswordService from zbt.domains.catalog.repository import InMemoryCatalogRepository from zbt.domains.enrollment.repository import InMemoryEnrollmentRepository from zbt.domains.identity.repository import InMemoryIdentityRepository from zbt.main import create_app def build_test_app(): catalog = InMemoryCatalogRepository() identities = InMemoryIdentityRepository() manifest = build_seed_manifest(PasswordService().hash("zaq1XSW@")) for admin in manifest.admin_users: identities.save_admin_user(admin) for product in manifest.products: catalog.save_product(product) for version in manifest.versions: catalog.save_version(version) return create_app( settings=Settings( app_env="test", jwt_access_secret="a" * 32, jwt_refresh_secret="b" * 32, field_encryption_key="c" * 32, ), identity_repository=identities, catalog_repository=catalog, enrollment_repository=InMemoryEnrollmentRepository(), clock=lambda: datetime(2026, 7, 26, tzinfo=UTC), ) def login_headers(client: TestClient) -> dict[str, str]: token = client.post( "/api/v1/h5/auth/login", json={"mobile": "18800000001", "code": "147258"}, ).json()["data"]["tokens"]["access_token"] return {"Authorization": f"Bearer {token}"} def test_eligible_customer_receives_deterministic_quote() -> None: with TestClient(build_test_app()) as client: headers = login_headers(client) product = next( item for item in client.get("/api/v1/h5/products", headers=headers).json()["data"]["items"] if item["product_code"] == "MED-SENIOR" ) response = client.post( "/api/v1/h5/quotes", headers=headers, json={ "product_id": product["product_id"], "plan_id": product["plans"][0]["id"], "insured": { "age": 65, "region_code": "510100", "occupation_code": "GENERAL", }, "relationship": "PARENT", }, ) assert response.status_code == 201 assert response.json()["data"]["eligible"] is True assert response.json()["data"]["premium_cents"] == 19900 assert response.json()["data"]["rate_version"] == "rate-v1" def test_confirmed_draft_creates_one_idempotent_order() -> None: with TestClient(build_test_app()) as client: headers = login_headers(client) product = next( item for item in client.get("/api/v1/h5/products", headers=headers).json()["data"]["items"] if item["product_code"] == "MED-SENIOR" ) quote_id = client.post( "/api/v1/h5/quotes", headers=headers, json={ "product_id": product["product_id"], "plan_id": product["plans"][0]["id"], "insured": { "age": 65, "region_code": "510100", "occupation_code": "GENERAL", }, "relationship": "PARENT", }, ).json()["data"]["quote_id"] draft = client.post( "/api/v1/h5/enrollment-drafts", headers=headers, json={ "quote_id": quote_id, "applicant": {"name": "张三", "id_no": "510100199001010001"}, "insured": {"name": "张父", "id_no": "510100196101010001"}, "contact": {"mobile": "18800000001"}, }, ) confirmation = client.post( f"/api/v1/h5/enrollment-drafts/{draft.json()['data']['draft_id']}/confirmation", headers=headers, ) order_headers = { **headers, "Idempotency-Key": "order-client-001", } first = client.post( "/api/v1/h5/orders", headers=order_headers, json={ "draft_id": draft.json()["data"]["draft_id"], "confirmation_token": confirmation.json()["data"]["confirmation_token"], }, ) repeated = client.post( "/api/v1/h5/orders", headers=order_headers, json={ "draft_id": draft.json()["data"]["draft_id"], "confirmation_token": confirmation.json()["data"]["confirmation_token"], }, ) assert draft.status_code == 201 assert confirmation.status_code == 201 assert first.status_code == 201 assert first.json()["data"]["status"] == "PENDING_PAYMENT" assert first.json()["data"]["amount_cents"] == 19900 assert repeated.status_code == 200 assert repeated.json()["data"]["order_id"] == first.json()["data"]["order_id"] def test_mock_payment_callback_is_idempotent_and_issues_one_policy() -> None: with TestClient(build_test_app()) as client: headers = login_headers(client) product = next( item for item in client.get("/api/v1/h5/products", headers=headers).json()["data"]["items"] if item["product_code"] == "MED-SENIOR" ) quote_id = client.post( "/api/v1/h5/quotes", headers=headers, json={ "product_id": product["product_id"], "plan_id": product["plans"][0]["id"], "insured": { "age": 65, "region_code": "510100", "occupation_code": "GENERAL", }, "relationship": "PARENT", }, ).json()["data"]["quote_id"] draft_id = client.post( "/api/v1/h5/enrollment-drafts", headers=headers, json={ "quote_id": quote_id, "applicant": {"name": "张三", "id_no": "510100199001010001"}, "insured": {"name": "张父", "id_no": "510100196101010001"}, "contact": {"mobile": "18800000001"}, }, ).json()["data"]["draft_id"] confirmation_token = client.post( f"/api/v1/h5/enrollment-drafts/{draft_id}/confirmation", headers=headers, ).json()["data"]["confirmation_token"] order = client.post( "/api/v1/h5/orders", headers={**headers, "Idempotency-Key": "order-client-002"}, json={ "draft_id": draft_id, "confirmation_token": confirmation_token, }, ).json()["data"] payment = client.post( f"/api/v1/h5/orders/{order['order_id']}/payments", headers={**headers, "Idempotency-Key": "payment-client-001"}, ) invalid_callback = client.post( "/api/v1/callbacks/mock-payment", headers={"X-Mock-Pay-Signature": "invalid-signature"}, json={ "callback_no": "CB-INVALID-001", "provider_transaction_no": "MP-INVALID-001", "payment_no": payment.json()["data"]["payment_no"], "status": "SUCCEEDED", "amount_cents": 19900, "occurred_at": "2026-07-25T08:30:00.000Z", }, ) first_callback = client.post( f"/api/v1/dev/mock-payments/{payment.json()['data']['payment_id']}/complete", headers=headers, ) repeated_callback = client.post( f"/api/v1/dev/mock-payments/{payment.json()['data']['payment_id']}/complete", headers=headers, ) policies = client.get("/api/v1/h5/policies", headers=headers) admin_token = client.post( "/api/v1/admin/auth/login", json={"username": "admin", "password": "zaq1XSW@"}, ).json()["data"]["tokens"]["access_token"] admin_dashboard = client.get( "/api/v1/admin/dashboard", headers={"Authorization": f"Bearer {admin_token}"}, ) admin_orders = client.get( "/api/v1/admin/orders", headers={"Authorization": f"Bearer {admin_token}"}, ) assert payment.status_code == 201 assert invalid_callback.status_code == 401 assert first_callback.status_code == 200 assert first_callback.json()["data"]["payment_status"] == "SUCCEEDED" assert first_callback.json()["data"]["order_status"] == "ISSUED" assert first_callback.json()["data"]["policy"]["status"] == "ACTIVE" assert ( repeated_callback.json()["data"]["policy"]["policy_id"] == (first_callback.json()["data"]["policy"]["policy_id"]) ) assert policies.json()["data"]["total"] == 1 policy = policies.json()["data"]["items"][0] assert policy["product_name"] == "银龄守护医疗险" assert policy["plan_name"] == "银龄标准计划" assert policy["relationship"] == "PARENT" assert policy["order_no"] == order["order_no"] assert policy["applicant"]["name"] == "张三" assert policy["insured"]["name"] == "张父" assert admin_dashboard.status_code == 200 assert admin_dashboard.json()["data"]["order_count"] == 1 assert admin_dashboard.json()["data"]["policy_count"] == 1 admin_order = admin_orders.json()["data"]["items"][0] assert admin_order["product_name"] == "银龄守护医疗险" assert admin_order["plan_name"] == "银龄标准计划" assert admin_order["relationship"] == "PARENT" assert admin_order["applicant"]["name"] == "张三" assert admin_order["contact"]["mobile"] == "18800000001" assert admin_order["payment"]["status"] == "SUCCEEDED" assert admin_order["policy_no"] == policy["policy_no"] def test_super_admin_can_update_role_permissions() -> None: with TestClient(build_test_app()) as client: admin_token = client.post( "/api/v1/admin/auth/login", json={"username": "admin", "password": "zaq1XSW@"}, ).json()["data"]["tokens"]["access_token"] headers = {"Authorization": f"Bearer {admin_token}"} roles = client.get("/api/v1/admin/roles", headers=headers) update = client.put( "/api/v1/admin/roles/OPERATOR", headers=headers, json={ "permissions": [ "dashboard:read", "order:read", "policy:read", "role:read", ], "data_scope": "MASKED_ALL", }, ) protected = client.put( "/api/v1/admin/roles/SUPER_ADMIN", headers=headers, json={"permissions": [], "data_scope": "SELF"}, ) operator_login = client.post( "/api/v1/admin/auth/login", json={"username": "operator01", "password": "zaq1XSW@"}, ) assert roles.status_code == 200 assert len(roles.json()["data"]["items"]) == 4 assert update.status_code == 200 assert update.json()["data"]["permissions"] == [ "dashboard:read", "order:read", "policy:read", "role:read", ] assert protected.status_code == 409 assert operator_login.json()["data"]["user"]["permissions"] == [ "dashboard:read", "order:read", "policy:read", "role:read", ] def test_super_admin_can_maintain_admin_accounts_and_customers() -> None: with TestClient(build_test_app()) as client: customer_login = client.post( "/api/v1/h5/auth/login", json={"mobile": "18800000001", "code": "147258"}, ) customer_id = customer_login.json()["data"]["user"]["id"] admin_token = client.post( "/api/v1/admin/auth/login", json={"username": "admin", "password": "zaq1XSW@"}, ).json()["data"]["tokens"]["access_token"] headers = {"Authorization": f"Bearer {admin_token}"} created = client.post( "/api/v1/admin/users/admins", headers=headers, json={ "username": "service01", "password": "Initial1!", "display_name": "客服专员", "role_code": "OPERATOR", }, ) created_user = created.json()["data"] updated = client.put( f"/api/v1/admin/users/admins/{created_user['id']}", headers=headers, json={ "display_name": "客服主管", "status": "ACTIVE", "role_code": "REVIEWER", }, ) password_reset = client.post( f"/api/v1/admin/users/admins/{created_user['id']}/password", headers=headers, json={"new_password": "Changed1!"}, ) customer_disabled = client.put( f"/api/v1/admin/users/customers/{customer_id}/status", headers=headers, json={"status": "DISABLED"}, ) users = client.get("/api/v1/admin/users", headers=headers) new_login = client.post( "/api/v1/admin/auth/login", json={"username": "service01", "password": "Changed1!"}, ) disabled_customer_login = client.post( "/api/v1/h5/auth/login", json={"mobile": "18800000001", "code": "147258"}, ) assert created.status_code == 201 assert updated.status_code == 200 assert updated.json()["data"]["display_name"] == "客服主管" assert updated.json()["data"]["roles"] == ["REVIEWER"] assert password_reset.status_code == 200 assert customer_disabled.json()["data"]["status"] == "DISABLED" assert len(users.json()["data"]["admin_users"]) == 10 assert len(users.json()["data"]["customers"]) == 1 assert new_login.status_code == 200 assert disabled_customer_login.status_code == 403