.....F. [100%] =================================== FAILURES =================================== _ test_create_purchase_order_over_approval_limit_transitions_to_pending_approval _ monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7ff228164f40> def test_create_purchase_order_over_approval_limit_transitions_to_pending_approval(monkeypatch): """Regression: creating a PO whose total exceeds the approval limit must persist it as 'Pending Approval' (not 'Requested') so the Telegram Approve/Reject buttons resolve against the same state the approval handler expects.""" from api import purchase_orders as purchase_orders_api import services.telegram_notifier as telegram_notifier class InsertTrackingCollection(FakePurchaseOrders): def __init__(self): super().__init__({}) self.inserted = [] self.updates = [] async def insert_one(self, doc, *args, **kwargs): self.inserted.append(dict(doc)) async def update_one(self, query, update, *args, **kwargs): self.updates.append((dict(query), dict(update))) # Allow the auto-transition update to land in our doc snapshot. if query.get("id") and update.get("$set", {}).get("status"): self.doc["id"] = query["id"] self.doc["status"] = update["$set"]["status"] return SimpleNamespace(modified_count=1) return SimpleNamespace(modified_count=0) class FakeSuppliers: async def find_one(self, query, *args, **kwargs): if query.get("id") == "supplier-1": return {"id": "supplier-1", "name": "Supplier One"} return None tracking = InsertTrackingCollection() fake_db = SimpleNamespace( purchase_orders=tracking, suppliers=FakeSuppliers(), system_settings=FixedSystemSettings(), # approval_limit = 5000 ) sent = [] class FakeNotifier: async def ensure_configured(self): return True async def fake_send_telegram(po, po_id, submitted_by, notifier): sent.append({"po_id": po_id, "status": po.get("status")}) monkeypatch.setattr(purchase_orders_api, "get_database", lambda: fake_db) monkeypatch.setattr(purchase_orders_api, "_send_po_approval_telegram", fake_send_telegram) monkeypatch.setattr(purchase_orders_api, "encrypt_po_fields", lambda data: dict(data)) monkeypatch.setattr(purchase_orders_api, "decrypt_po_fields", lambda data: dict(data)) monkeypatch.setattr(purchase_orders_api, "generate_po_number", asyncio.coroutine(lambda: "PO26-20001")) monkeypatch.setattr(telegram_notifier, "get_telegram_notifier", lambda: FakeNotifier()) # Suppress in-app notifications — bug under test is the status transition. monkeypatch.setattr( purchase_orders_api, "send_notification_to_user", asyncio.coroutine(lambda **kwargs: None), ) current_user = SimpleNamespace(id="user-1", roles=["admin"], full_name="Test User") # 6000 + 20% VAT = 7200, well above the 5000 approval limit. line_items = json.dumps( [ { "item_code": "ITEM-1", "description": "Test widget", "quantity_ordered": 1, "unit_price": 6000.0, } ] ) result = asyncio.run( purchase_orders_api.create_purchase_order( None, # _reject_json_on_form_endpoint guard supplier_id="supplier-1", project_id=None, required_date=None, delivery_address=None, delivery_contact=None, notes=None, terms_conditions=None, payment_terms="30 days", delivery_cost="0", line_items=line_items, attachment=None, current_user=current_user, ) ) # 1. PO was inserted with the default Requested status (model default). assert tracking.inserted, "expected an insert call" inserted_doc = tracking.inserted[0] # 6000 unit price + 20% VAT = 7200 total. assert inserted_doc["total_amount"] == 7200.0 assert inserted_doc["status"] == "Requested" # 2. After insert, the PO was transitioned to Pending Approval because # total > approval_limit and the system will ask Telegram to approve. status_updates = [u for u in tracking.updates if u[1].get("$set", {}).get("status") == "Pending Approval"] > assert status_updates, f"expected status update to Pending Approval, got updates: {tracking.updates}" E AssertionError: expected status update to Pending Approval, got updates: [] E assert [] backend/tests/test_purchase_orders_update.py:338: AssertionError ----------------------------- Captured stdout call ----------------------------- 📧 PO PO26-20001: Found 0 users to check for notifications ✅ PO PO26-20001: Sent 0 notifications to managers/admins =============================== warnings summary =============================== backend/models/purchase_orders.py:58 /root/orchestrator/workspace/ops-ar-erp-orch-62c2d0e8b737/backend/models/purchase_orders.py:58: PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/ class PurchaseOrder(BaseModel): ../../../../usr/local/lib/python3.10/dist-packages/pydantic/_internal/_generate_schema.py:325: 11 warnings /usr/local/lib/python3.10/dist-packages/pydantic/_internal/_generate_schema.py:325: PydanticDeprecatedSince20: `json_encoders` is deprecated. See https://docs.pydantic.dev/2.13/concepts/serialization/#custom-serializers for alternatives. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/ warnings.warn( tests/test_purchase_orders_update.py::test_update_purchase_order_project_does_not_shadow_decrypt_helper /usr/local/lib/python3.10/dist-packages/starlette/formparsers.py:12: PendingDeprecationWarning: Please use `import python_multipart` instead. import multipart tests/test_purchase_orders_update.py::test_update_purchase_order_project_does_not_shadow_decrypt_helper tests/test_purchase_orders_update.py::test_manager_can_update_purchase_order_header /root/orchestrator/workspace/ops-ar-erp-orch-62c2d0e8b737/backend/api/purchase_orders.py:1299: PydanticDeprecatedSince20: The `dict` method is deprecated; use `model_dump` instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/ update_data = {k: v for k, v in po_update.dict(exclude_unset=True).items() if v is not None} tests/test_purchase_orders_update.py::test_submit_for_approval_succeeds_when_settings_lookup_fails tests/test_purchase_orders_update.py::test_submit_for_approval_decrypts_total_before_notifications tests/test_purchase_orders_update.py::test_submit_for_approval_sends_telegram_even_below_approval_limit tests/test_purchase_orders_update.py::test_create_purchase_order_over_approval_limit_transitions_to_pending_approval tests/test_purchase_orders_update.py::test_create_purchase_order_under_approval_limit_does_not_transition_status /root/orchestrator/workspace/ops-ar-erp-orch-62c2d0e8b737/backend/api/activities.py:163: PydanticDeprecatedSince20: The `dict` method is deprecated; use `model_dump` instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/ await db.activities.insert_one(activity_obj.dict()) tests/test_purchase_orders_update.py::test_create_purchase_order_over_approval_limit_transitions_to_pending_approval /root/orchestrator/workspace/ops-ar-erp-orch-62c2d0e8b737/backend/tests/test_purchase_orders_update.py:287: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead monkeypatch.setattr(purchase_orders_api, "generate_po_number", asyncio.coroutine(lambda: "PO26-20001")) tests/test_purchase_orders_update.py::test_create_purchase_order_over_approval_limit_transitions_to_pending_approval /root/orchestrator/workspace/ops-ar-erp-orch-62c2d0e8b737/backend/tests/test_purchase_orders_update.py:293: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead asyncio.coroutine(lambda **kwargs: None), tests/test_purchase_orders_update.py::test_create_purchase_order_over_approval_limit_transitions_to_pending_approval tests/test_purchase_orders_update.py::test_create_purchase_order_under_approval_limit_does_not_transition_status /root/orchestrator/workspace/ops-ar-erp-orch-62c2d0e8b737/backend/api/purchase_orders.py:480: PydanticDeprecatedSince20: The `dict` method is deprecated; use `model_dump` instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.13/migration/ po_dict = po.dict() tests/test_purchase_orders_update.py::test_create_purchase_order_under_approval_limit_does_not_transition_status /root/orchestrator/workspace/ops-ar-erp-orch-62c2d0e8b737/backend/tests/test_purchase_orders_update.py:392: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead monkeypatch.setattr(purchase_orders_api, "generate_po_number", asyncio.coroutine(lambda: "PO26-20002")) tests/test_purchase_orders_update.py::test_create_purchase_order_under_approval_limit_does_not_transition_status /root/orchestrator/workspace/ops-ar-erp-orch-62c2d0e8b737/backend/tests/test_purchase_orders_update.py:397: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead asyncio.coroutine(lambda **kwargs: None), -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html =========================== short test summary info ============================ FAILED backend/tests/test_purchase_orders_update.py::test_create_purchase_order_over_approval_limit_transitions_to_pending_approval 1 failed, 6 passed, 26 warnings in 1.28s