| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677 |
- """证书保存状态保护:仅使用数据库边界替身,不连接业务数据库。"""
- from types import SimpleNamespace
- from unittest.mock import MagicMock
- import pytest
- from fastapi import HTTPException
- from app.services import pl_plan_service as svc
- @pytest.fixture
- def cert_case(monkeypatch):
- plan = SimpleNamespace(
- archive_status="pending", follow_status="pending_arrange",
- update_by="original", hazard_cert_ready=0,
- )
- product = SimpleNamespace(
- id="product-1", product_id="crm-1", product_name="测试危化品",
- purchase_cert_url="old.pdf", transport_cert_url=None,
- legal_use_cert_url=None, update_by="original",
- )
- db = MagicMock()
- plan_query, product_query = MagicMock(), MagicMock()
- plan_query.filter.return_value.first.return_value = plan
- product_query.filter.return_value.first.return_value = product
- product_query.filter.return_value.all.return_value = [product]
- db.query.side_effect = lambda model: plan_query if model is svc.PlPlan else product_query
- monkeypatch.setattr(svc, "fetch_hazard_flags_map", lambda *args: {})
- monkeypatch.setattr(svc, "resolve_hazard_flags_from_crm", lambda *args, **kwargs: (True, False))
- auto_ready = MagicMock()
- monkeypatch.setattr(svc, "maybe_auto_set_hazard_cert_ready", auto_ready)
- item = SimpleNamespace(
- id=product.id, purchase_cert_url=" new.pdf,other.pdf ",
- transport_cert_url=" ", legal_use_cert_url=None,
- )
- def save():
- return svc.update_plan_product_certs(
- db, tenant_no="test-tenant", plan_id="plan-1", items=[item], user_id="editor"
- )
- return SimpleNamespace(
- plan=plan, product=product, db=db, save=save,
- auto_ready=auto_ready, plan_query=plan_query,
- )
- @pytest.mark.parametrize("state", ["cancelled", "archived", "missing"])
- def test_invalid_plan_rejected_before_any_certificate_write(cert_case, state):
- c = cert_case
- if state == "cancelled":
- c.plan.follow_status = "cancelled"
- elif state == "archived":
- c.plan.archive_status = "archived"
- else:
- c.plan_query.filter.return_value.first.return_value = None
- with pytest.raises(HTTPException) as error:
- c.save()
- assert error.value.status_code == (404 if state == "missing" else 400)
- if state == "cancelled":
- assert "已作废" in error.value.detail
- assert c.product.purchase_cert_url == "old.pdf"
- assert c.product.update_by == c.plan.update_by == "original"
- assert c.plan.hazard_cert_ready == 0
- c.db.query.assert_called_once_with(svc.PlPlan)
- c.db.commit.assert_not_called()
- c.auto_ready.assert_not_called()
- def test_active_plan_can_save_and_clear_certificate_urls(cert_case):
- c = cert_case
- assert c.save() == [c.product]
- assert c.product.purchase_cert_url == "new.pdf,other.pdf"
- assert c.product.transport_cert_url is None
- assert c.product.legal_use_cert_url is None
- assert c.product.update_by == c.plan.update_by == "editor"
- c.db.commit.assert_called_once()
- c.db.refresh.assert_called_once_with(c.product)
- c.auto_ready.assert_called_once()
|