diff --git a/api/services/telephony/providers/cloudonix/provider.py b/api/services/telephony/providers/cloudonix/provider.py index 950cd050..31b84fb6 100644 --- a/api/services/telephony/providers/cloudonix/provider.py +++ b/api/services/telephony/providers/cloudonix/provider.py @@ -388,13 +388,16 @@ class CloudonixProvider(TelephonyProvider): disposition = data.get("disposition") or "" session = data.get("session") + billsec = data.get("billsec") return { "call_id": session.get("token") if isinstance(session, dict) else "", "status": disposition_map.get(disposition.upper(), disposition.lower()), "from_number": data.get("from"), "to_number": data.get("to"), - "duration": str(data.get("billsec") or data.get("duration") or 0), + "duration": str( + billsec if billsec is not None else (data.get("duration") or 0) + ), "extra": data, } diff --git a/api/tests/telephony/cloudonix/test_routes.py b/api/tests/telephony/cloudonix/test_routes.py index a9b288b1..31cf220a 100644 --- a/api/tests/telephony/cloudonix/test_routes.py +++ b/api/tests/telephony/cloudonix/test_routes.py @@ -118,3 +118,17 @@ def test_parse_cloudonix_cdr_maps_disposition_and_session_token(): assert req["call_id"] == "abc123" assert req["status"] == TelephonyCallStatus.BUSY assert req["duration"] == "12" + + +def test_parse_cloudonix_cdr_preserves_zero_billsec(): + """A zero billed duration must not fall back to total call duration.""" + req = CloudonixProvider.parse_cdr_status_callback( + { + "session": {"token": "abc123"}, + "disposition": "ANSWER", + "billsec": 0, + "duration": 42, + } + ) + + assert req["duration"] == "0" diff --git a/api/tests/test_pipecat_engine_end_call.py b/api/tests/test_pipecat_engine_end_call.py index 6f1f7c31..b927369b 100644 --- a/api/tests/test_pipecat_engine_end_call.py +++ b/api/tests/test_pipecat_engine_end_call.py @@ -834,9 +834,7 @@ class TestEndCallRaceConditions: EndTaskReason.USER_HANGUP.value, abort_immediately=True ) - await asyncio.gather( - run_pipeline(), initialize_and_race_disconnect() - ) + await asyncio.gather(run_pipeline(), initialize_and_race_disconnect()) # Verify disconnect was attempted assert disconnect_called, "Disconnect should have been called" diff --git a/sdk/python/src/dograh_sdk/_generated_models.py b/sdk/python/src/dograh_sdk/_generated_models.py index cd56b905..090eee70 100644 --- a/sdk/python/src/dograh_sdk/_generated_models.py +++ b/sdk/python/src/dograh_sdk/_generated_models.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: -# filename: dograh-openapi-XXXXXX.json.rRr9IUrKFk -# timestamp: 2026-06-23T13:02:10+00:00 +# filename: dograh-openapi-XXXXXX.json.YWer7ilGLp +# timestamp: 2026-06-24T16:36:26+00:00 from __future__ import annotations