Skip to content

Conversation

@yugesh-ganipudi
Copy link
Contributor

@yugesh-ganipudi yugesh-ganipudi commented Nov 19, 2025

  • We implemented new endpoint /call/abort which updates the status to FINISHED and outcome to ABORT whenever gets triggered
  • It requires lead_id in request

Summary by CodeRabbit

  • New Features
    • Added ability to abort a lead's call via a new API endpoint, with response including lead ID, customer name, and order ID.
    • Extended analytics to track call abortions for better visibility into order and lead-level metrics.

@coderabbitai
Copy link

coderabbitai bot commented Nov 19, 2025

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The PR introduces call abortion functionality to the BreezeBuddy API by adding a new POST /call/abort endpoint, corresponding database queries and handlers, database constraint updates to support the ABORT outcome type, and analytics tracking for aborted calls.

Changes

Cohort / File(s) Summary
API Endpoint
app/api/routers/breeze_buddy.py
New POST /call/abort endpoint accepts CallAbortRequest, calls handle_call_abort(), returns success payload with lead_id, customer_name, and order_id, or 404 if no pending call exists; expands analytics to track ABORT outcome.
Database Query Layer
app/database/queries/breeze_buddy/lead_call_tracker.py
New abort_call_by_lead_id_query() generator creates parameterized UPDATE to mark call as FINISHED with ABORT outcome; adds aborted_calls aggregation column to per-order analytics query.
Database Accessor Layer
app/database/accessor/breeze_buddy/lead_call_tracker.py
New async handle_call_abort() function executes abort query, logs call details (customer_name, order_id), returns decoded LeadCallTracker or None.
Accessor Exports
app/database/accessor/__init__.py
Imports and exports handle_call_abort in public API surface.
Schema & Models
app/schemas.py
Adds ABORT member to LeadCallOutcome enum; introduces new CallAbortRequest BaseModel with lead_id field.
Database Schema
scripts/create_tables.py
Extends CHECK constraint on lead_call_tracker outcome column to include 'ABORT'.

Sequence Diagram

sequenceDiagram
    actor Client
    participant Router as POST /call/abort
    participant Handler as handle_call_abort
    participant QueryGen as abort_call_by_lead_id_query
    participant Database as DB
    
    Client->>Router: CallAbortRequest(lead_id)
    activate Router
    
    Router->>Handler: handle_call_abort(lead_id)
    activate Handler
    
    Handler->>QueryGen: abort_call_by_lead_id_query(lead_id)
    activate QueryGen
    QueryGen-->>Handler: (UPDATE query, params)
    deactivate QueryGen
    
    Handler->>Database: Execute parameterized UPDATE
    activate Database
    Database-->>Handler: Result row or None
    deactivate Database
    
    alt Row found
        Handler->>Handler: Decode LeadCallTracker<br/>Log success with customer_name, order_id
        Handler-->>Router: LeadCallTracker
        Router-->>Client: 200 {lead_id, customer_name, order_id}
    else No pending call
        Handler-->>Router: None
        Router-->>Client: 404 Not Found
    else Error
        Handler->>Handler: Log exception
        Handler-->>Router: None
        Router-->>Client: 500 Server Error
    end
    
    deactivate Handler
    deactivate Router
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

  • Database query logic: Verify UPDATE statement constraints (status BACKLOG/RETRY, outcome NULL/empty) and JSON metadata merge correctness
  • Async handler implementation: Confirm error handling and logging of customer_name/order_id extraction from payload
  • API endpoint error handling: Validate success/not-found/error response formats and HTTP status codes
  • Analytics consistency: Ensure ABORT outcome is properly tracked across all analytics aggregations

Possibly related PRs

Suggested reviewers

  • badri-singhal
  • swaroopvarma1

Poem

🐰 Hops with glee
A call to abort, a lead set free!
Through queries swift and handlers true,
The BreezeBuddy hops—ABORT on cue! 🎉
Analytics track each whispered goodbye,
As canceled calls drift through the sky. ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The PR title 'Shopify Order Cancellation lead management' is vague and generic, using broad terms that don't clearly describe the specific change being implemented. Consider a more specific title like 'Add /call/abort endpoint for aborting lead calls' to clearly communicate the primary technical change.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
app/database/accessor/breeze_buddy/lead_call_tracker.py (1)

404-426: Consider more specific exception handling.

While catching broad Exception with logging is acceptable, consider catching more specific exceptions (e.g., database-related exceptions) to distinguish between expected error conditions and unexpected bugs. However, this pattern is consistent with other functions in this file.

app/schemas.py (1)

146-149: Consider adding field validation.

The CallAbortRequest model is functional, but could benefit from validation on lead_id to ensure it's non-empty and follows expected format patterns.

Example enhancement:

from pydantic import Field

class CallAbortRequest(BaseModel):
    """Request model for aborting a call by lead ID"""
    
    lead_id: str = Field(..., min_length=1, description="The unique identifier of the lead call to abort")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between abff427 and a59dd89.

📒 Files selected for processing (6)
  • app/api/routers/breeze_buddy.py (4 hunks)
  • app/database/accessor/__init__.py (2 hunks)
  • app/database/accessor/breeze_buddy/lead_call_tracker.py (1 hunks)
  • app/database/queries/breeze_buddy/lead_call_tracker.py (2 hunks)
  • app/schemas.py (2 hunks)
  • scripts/create_tables.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
app/database/accessor/breeze_buddy/lead_call_tracker.py (5)
app/schemas.py (1)
  • LeadCallTracker (47-66)
app/database/queries/breeze_buddy/lead_call_tracker.py (1)
  • abort_call_by_lead_id_query (354-381)
app/database/queries/__init__.py (1)
  • run_parameterized_query (14-30)
app/database/accessor/breeze_buddy/call_execution_config.py (1)
  • get_row_count (24-28)
app/database/decoder/breeze_buddy/lead_call_tracker.py (1)
  • decode_lead_call_tracker (19-46)
app/database/queries/breeze_buddy/lead_call_tracker.py (1)
app/schemas.py (2)
  • LeadCallStatus (30-34)
  • LeadCallOutcome (37-44)
app/database/accessor/__init__.py (1)
app/database/accessor/breeze_buddy/lead_call_tracker.py (1)
  • handle_call_abort (397-426)
app/api/routers/breeze_buddy.py (2)
app/database/accessor/breeze_buddy/lead_call_tracker.py (1)
  • handle_call_abort (397-426)
app/schemas.py (1)
  • CallAbortRequest (146-149)
🪛 Ruff (0.14.5)
app/database/accessor/breeze_buddy/lead_call_tracker.py

424-424: Do not catch blind exception: Exception

(BLE001)


425-425: Use explicit conversion flag

Replace with conversion flag

(RUF010)

app/database/queries/breeze_buddy/lead_call_tracker.py

359-372: Possible SQL injection vector through string-based query construction

(S608)

app/api/routers/breeze_buddy.py

305-305: Do not catch blind exception: Exception

(BLE001)


307-307: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


307-307: Use explicit conversion flag

Replace with conversion flag

(RUF010)

🔇 Additional comments (6)
scripts/create_tables.py (1)

36-36: LGTM! Database constraint updated correctly.

The addition of 'ABORT' to the outcome CHECK constraint properly extends the schema to support the new abort functionality.

app/database/accessor/__init__.py (1)

20-20: LGTM! Public API surface extended appropriately.

The new handle_call_abort function is properly exported following the existing module patterns.

Also applies to: 61-61

app/database/queries/breeze_buddy/lead_call_tracker.py (2)

343-343: LGTM! Analytics properly extended for ABORT outcome.

The addition of aborted_calls counter maintains consistency with other outcome types in the analytics query.


354-381: LGTM! Query correctly implements abort logic.

The query properly:

  • Uses parameterized values to prevent SQL injection
  • Restricts abort to pending calls (BACKLOG/RETRY status, no existing outcome)
  • Updates all relevant fields (status, outcome, timestamps, metadata)
  • Returns the updated row for confirmation
app/schemas.py (1)

44-44: LGTM! Enum value added correctly.

The ABORT outcome is properly added to the LeadCallOutcome enum, maintaining consistency with the database schema changes.

app/api/routers/breeze_buddy.py (1)

620-622: LGTM! Analytics correctly track aborted calls.

Both call-based and lead-based analytics properly account for the new ABORT outcome, maintaining consistency with how other outcomes are tracked.

Also applies to: 652-654

Comment on lines 273 to 321
@router.post("/call/abort")
async def abort_call(
abort_request: CallAbortRequest,
):
"""
Abort a call by lead ID.
Sets status to FINISHED and outcome to CANCEL.
"""
try:
aborted_lead = await handle_call_abort(abort_request.lead_id)

if aborted_lead:
# Extract customer info for response
customer_name = aborted_lead.payload.get("customer_name") if aborted_lead.payload else None
order_id = aborted_lead.payload.get("order_id") if aborted_lead.payload else None

return {
"status": "success",
"message": f"Call aborted successfully for lead {abort_request.lead_id}",
"lead_id": abort_request.lead_id,
"customer_name": customer_name,
"order_id": order_id,
"updated_status": "FINISHED",
"updated_outcome": "ABORT"
}
else:
return {
"status": "not_found",
"message": f"No pending call found for lead {abort_request.lead_id}",
"lead_id": abort_request.lead_id
}

except Exception as e:
logger.error(f"Error aborting call for lead {abort_request.lead_id}: {e}")
raise HTTPException(status_code=500, detail=f"Failed to abort call: {str(e)}")

Copy link

@coderabbitai coderabbitai bot Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Missing authentication on abort endpoint.

Unlike all other POST endpoints in this router (e.g., trigger_order_confirmation at line 310, add_outbound_number at line 182, add_call_execution_config at line 438), the /call/abort endpoint lacks authentication via Depends(get_current_user). This allows unauthenticated users to abort any call by providing a lead_id, which is a significant security vulnerability.

Additionally, the docstring at line 279 incorrectly states "outcome to CANCEL" when it should say "outcome to ABORT".

Apply this diff to add authentication and fix the docstring:

 @router.post("/call/abort")
 async def abort_call(
     abort_request: CallAbortRequest,
+    current_user: TokenData = Depends(get_current_user),
 ):
     """
     Abort a call by lead ID.
-    Sets status to FINISHED and outcome to CANCEL.
+    Sets status to FINISHED and outcome to ABORT.
+    Requires JWT authentication.
     """
     try:
+        logger.info(
+            f"Authenticated user {current_user.user_id} aborting call for lead {abort_request.lead_id}"
+        )
         aborted_lead = await handle_call_abort(abort_request.lead_id)
🧰 Tools
🪛 Ruff (0.14.5)

305-305: Do not catch blind exception: Exception

(BLE001)


307-307: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


307-307: Use explicit conversion flag

Replace with conversion flag

(RUF010)

🤖 Prompt for AI Agents
In app/api/routers/breeze_buddy.py around lines 273 to 308, the POST /call/abort
endpoint is missing authentication and has an incorrect docstring outcome;
update the function signature to require authentication by adding the dependency
(e.g., user: User = Depends(get_current_user)) consistent with other POST
endpoints in this router, ensure any required imports (Depends,
get_current_user, User type) are present at the top of the file, and change the
docstring line to state that the endpoint sets the outcome to "ABORT" instead of
"CANCEL".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines 397 to 402
async def handle_call_abort(lead_id: str) -> Optional[LeadCallTracker]:
"""
Abort a call by lead ID.
Sets status to FINISHED and outcome to CANCEL.
"""
Copy link

@coderabbitai coderabbitai bot Nov 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix incorrect docstring.

The docstring states "outcome to CANCEL" but the implementation sets outcome to ABORT. This documentation inconsistency could mislead future maintainers.

Apply this diff to correct the docstring:

 async def handle_call_abort(lead_id: str) -> Optional[LeadCallTracker]:
     """
     Abort a call by lead ID.
-    Sets status to FINISHED and outcome to CANCEL.
+    Sets status to FINISHED and outcome to ABORT.
     """
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async def handle_call_abort(lead_id: str) -> Optional[LeadCallTracker]:
"""
Abort a call by lead ID.
Sets status to FINISHED and outcome to CANCEL.
"""
async def handle_call_abort(lead_id: str) -> Optional[LeadCallTracker]:
"""
Abort a call by lead ID.
Sets status to FINISHED and outcome to ABORT.
"""
🤖 Prompt for AI Agents
In app/database/accessor/breeze_buddy/lead_call_tracker.py around lines 397 to
401, the docstring for handle_call_abort incorrectly states that the outcome is
set to CANCEL while the implementation sets outcome to ABORT; update the
docstring to state that the outcome is set to ABORT (or otherwise match the
actual return value), keeping the rest of the docstring intact and consistent
with the function behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!


@router.post("/call/abort")
async def abort_call(
abort_request: CallAbortRequest,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authentication?

@yugesh-ganipudi yugesh-ganipudi force-pushed the BZ-46487-shopify-order-cancellation-lead-management branch from a59dd89 to 043db78 Compare November 20, 2025 06:10
Abort a call by lead ID.
Sets status to FINISHED and outcome to ABORT.
"""
logger.info(f"🚀 Call abort started for lead {lead_id}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove emoji

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

logger.info(f"🚀 Call abort started for lead {lead_id}")

try:
from app.database.queries.breeze_buddy.lead_call_tracker import abort_call_by_lead_id_query
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to top

"status" = $1,
"outcome" = $2,
"updated_at" = NOW(),
"call_end_time" = NOW(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we updating the call_end_time

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

raise HTTPException(status_code=400, detail=str(e))


@router.post("/call/abort")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of post can we use delete endpoint with id in params?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

@yugesh-ganipudi yugesh-ganipudi force-pushed the BZ-46487-shopify-order-cancellation-lead-management branch 2 times, most recently from 5ac31c2 to 194897e Compare November 20, 2025 09:47
app/schemas.py Outdated
scopes: list[str] = Field(default_factory=list)


class CallAbortRequest(BaseModel):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is this being used?

@yugesh-ganipudi yugesh-ganipudi force-pushed the BZ-46487-shopify-order-cancellation-lead-management branch 2 times, most recently from eb6c88f to 8841cd0 Compare November 24, 2025 06:04
…o FINISHED and outcome to ABORT whenever gets triggered

 - It requires lead_id in request
@yugesh-ganipudi yugesh-ganipudi force-pushed the BZ-46487-shopify-order-cancellation-lead-management branch from 8841cd0 to 3fda196 Compare November 26, 2025 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants