From d3aa8d54532a976e4018b363edead3b2bc311379 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 04:21:45 +0000 Subject: [PATCH 1/7] Initial plan From 769833826b89453775f06ef044a81536063da494 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 04:29:29 +0000 Subject: [PATCH 2/7] Implement create partner request endpoint and make publish/cancel idempotent Co-authored-by: xiaoland <37663413+xiaoland@users.noreply.github.com> --- main/managers/partner_request/trip/commute.py | 66 ++++++- .../partner_request/trip/ride_hailing.py | 64 +++++- main/routes.py | 72 ++++--- main/schemas/partner_request/trip/create.py | 32 +++ tests/test_pr/test_create_pr.py | 184 ++++++++++++++++++ 5 files changed, 376 insertions(+), 42 deletions(-) create mode 100644 main/schemas/partner_request/trip/create.py create mode 100644 tests/test_pr/test_create_pr.py diff --git a/main/managers/partner_request/trip/commute.py b/main/managers/partner_request/trip/commute.py index a69ec9a..d3c3a0f 100644 --- a/main/managers/partner_request/trip/commute.py +++ b/main/managers/partner_request/trip/commute.py @@ -7,9 +7,15 @@ __all__ = ["CommutePRManager"] import structlog +import sqlmodel +from typing import Optional as Opt from .base import TripPRManager -from ....schemas.partner_request import PartnerRequestRef +from ....schemas.partner_request import PartnerRequestRef, PartnerRequest, PartnerRequestL2Type +from ....schemas.partner_request.trip.commute import CommutePRContent +from ....schemas.partner_request.trip.create import CommutePRCreate +from core.engine import SessionLocal +from account.schemas import AccountRef logger = structlog.get_logger(__name__) @@ -30,11 +36,59 @@ def get(cls, pr_id: PartnerRequestRef): pass @classmethod - def create(cls, *args, **kwargs): - """Create a commute partner request.""" - # TODO: Implement when commute schema is refactored - logger.info("Create commute PR") - raise NotImplementedError("Commute PR creation pending schema refactor") + def create( + cls, + account_id: AccountRef, + data: CommutePRCreate, + db: Opt[sqlmodel.Session] = None, + ) -> PartnerRequestRef: + """Create a commute partner request. + + Creates both base PartnerRequest and CommutePRContent records. + + :param account_id: Account ID of the creator + :param data: Create request data + :param db: Optional database session + :return: Created partner request ID + """ + logger.info("Create commute PR", account_id=account_id) + + should_close_session = db is None + if db is None: + db = SessionLocal() + + try: + # Create base partner request + pr = PartnerRequest( + type=PartnerRequestL2Type.COMMUTE.value, + created_by=account_id, + title=data.title, + introduction=data.introduction, + ) + db.add(pr) + db.flush() # Get the ID without committing + + # Create commute specific content + content = CommutePRContent( + id=pr.id, + route=data.route, + trip_preference=data.trip_preference, + on_at=data.on_at, + off_at=data.off_at, + workdays=data.workdays if data.workdays else None, + ) + db.add(content) + db.commit() + + logger.info("Created commute PR", pr_id=pr.id) + return pr.id + except Exception as e: + db.rollback() + logger.error("Failed to create commute PR", error=str(e)) + raise + finally: + if should_close_session: + db.close() @classmethod def update(cls, *args, **kwargs): diff --git a/main/managers/partner_request/trip/ride_hailing.py b/main/managers/partner_request/trip/ride_hailing.py index e5418f8..39171f9 100644 --- a/main/managers/partner_request/trip/ride_hailing.py +++ b/main/managers/partner_request/trip/ride_hailing.py @@ -7,9 +7,15 @@ __all__ = ["RideHailingPRManager"] import structlog +import sqlmodel +from typing import Optional as Opt from .base import TripPRManager -from ....schemas.partner_request import PartnerRequestRef +from ....schemas.partner_request import PartnerRequestRef, PartnerRequest, PartnerRequestL2Type +from ....schemas.partner_request.trip.ride_hailing import RideHailingPRContent +from ....schemas.partner_request.trip.create import RideHailingPRCreate +from core.engine import SessionLocal +from account.schemas import AccountRef logger = structlog.get_logger(__name__) @@ -30,11 +36,57 @@ def get(cls, pr_id: PartnerRequestRef): pass @classmethod - def create(cls, *args, **kwargs): - """Create a ride-hailing partner request.""" - # TODO: Implement when ride-hailing schema is refactored - logger.info("Create ride-hailing PR") - raise NotImplementedError("Ride-hailing PR creation pending schema refactor") + def create( + cls, + account_id: AccountRef, + data: RideHailingPRCreate, + db: Opt[sqlmodel.Session] = None, + ) -> PartnerRequestRef: + """Create a ride-hailing partner request. + + Creates both base PartnerRequest and RideHailingPRContent records. + + :param account_id: Account ID of the creator + :param data: Create request data + :param db: Optional database session + :return: Created partner request ID + """ + logger.info("Create ride-hailing PR", account_id=account_id) + + should_close_session = db is None + if db is None: + db = SessionLocal() + + try: + # Create base partner request + pr = PartnerRequest( + type=PartnerRequestL2Type.RIDE_HAILING.value, + created_by=account_id, + title=data.title, + introduction=data.introduction, + ) + db.add(pr) + db.flush() # Get the ID without committing + + # Create ride-hailing specific content + content = RideHailingPRContent( + id=pr.id, + route=data.route, + trip_preference=data.trip_preference, + ride_hailing_preference=data.ride_hailing_preference, + ) + db.add(content) + db.commit() + + logger.info("Created ride-hailing PR", pr_id=pr.id) + return pr.id + except Exception as e: + db.rollback() + logger.error("Failed to create ride-hailing PR", error=str(e)) + raise + finally: + if should_close_session: + db.close() @classmethod def update(cls, *args, **kwargs): diff --git a/main/routes.py b/main/routes.py index 5baf698..a8f4841 100644 --- a/main/routes.py +++ b/main/routes.py @@ -17,7 +17,11 @@ PartnerRequestRef, PartnerRequestStatus, PartnerRequestListType, + PartnerRequestL2Type, ) +from .schemas.partner_request.trip.create import RideHailingPRCreate, CommutePRCreate +from .managers.partner_request.trip.ride_hailing import RideHailingPRManager +from .managers.partner_request.trip.commute import CommutePRManager router = fastapi.APIRouter() @@ -62,6 +66,34 @@ def get_partner_request_list( return result +@router.post("/partner_request/{pr_type}") +def create_partner_request( + pr_type: PartnerRequestL2Type, + data: RideHailingPRCreate | CommutePRCreate, + auth: AuthInfo = Depends(require_auth), + db: sqlmodel.Session = Depends(get_db_session), +) -> PartnerRequestRef: + """Create a partner request. + + Creates both base PartnerRequest and type-specific content records. + The type of partner request is determined by the pr_type path parameter. + """ + account_id = auth.user_id + + if pr_type == PartnerRequestL2Type.RIDE_HAILING: + if not isinstance(data, RideHailingPRCreate): + raise HTTPException(status_code=400, detail="Invalid data for ride_hailing type") + pr_id = RideHailingPRManager.create(account_id, data, db) + elif pr_type == PartnerRequestL2Type.COMMUTE: + if not isinstance(data, CommutePRCreate): + raise HTTPException(status_code=400, detail="Invalid data for commute type") + pr_id = CommutePRManager.create(account_id, data, db) + else: + raise HTTPException(status_code=400, detail=f"Unsupported partner request type: {pr_type}") + + return pr_id + + @router.put("/partner_request/{pr_id}/publish") def publish_partner_request( pr_id: PartnerRequestRef, @@ -72,6 +104,7 @@ def publish_partner_request( Changes status from DRAFT to JOINABLE. Only the admin (creator) can publish. + Idempotent: if already JOINABLE, returns the request without error. """ pr = db.get(PartnerRequest, pr_id) if not pr: @@ -80,6 +113,10 @@ def publish_partner_request( if not pr.is_admin(auth.user_id): raise HTTPException(status_code=403, detail="Must be admin") + # Idempotent: if already published, just return + if pr.status == PartnerRequestStatus.JOINABLE.value: + return pr + if pr.status != PartnerRequestStatus.DRAFT.value: raise HTTPException(status_code=409, detail="Can only publish draft") @@ -101,6 +138,7 @@ def cancel_partner_request( Changes status to CANCELLED. Only the admin (creator) can cancel. Can only cancel if status is JOINABLE or READY. + Idempotent: if already CANCELLED, returns the request without error. """ pr = db.get(PartnerRequest, pr_id) if not pr: @@ -109,6 +147,10 @@ def cancel_partner_request( if not pr.is_admin(auth.user_id): raise HTTPException(status_code=403, detail="Must be admin") + # Idempotent: if already cancelled, just return + if pr.status == PartnerRequestStatus.CANCELLED.value: + return pr + if pr.status not in [PartnerRequestStatus.JOINABLE.value, PartnerRequestStatus.READY.value]: raise HTTPException(status_code=409, detail="Cannot cancel") @@ -117,33 +159,3 @@ def cancel_partner_request( db.commit() db.refresh(pr) return pr - - -@router.put("/partner_request/{pr_id}/status/next") -def next_status( - pr_id: PartnerRequestRef, - auth: AuthInfo = Depends(require_auth), - db: sqlmodel.Session = Depends(get_db_session), -) -> PartnerRequest: - """Move partner request to next status. - - Status progression: DRAFT -> JOINABLE -> READY -> PERFORMING -> SETTLING -> CLOSED - Only the admin (creator) can change status. - """ - pr = db.get(PartnerRequest, pr_id) - if not pr: - raise HTTPException(status_code=404, detail="Partner request not found") - - if not pr.is_admin(auth.user_id): - raise HTTPException(status_code=403, detail="Must be admin") - - current_status = PartnerRequestStatus(pr.status) - try: - next_status = current_status.next() - pr.status = next_status.value - db.add(pr) - db.commit() - db.refresh(pr) - return pr - except ValueError: - raise HTTPException(status_code=409, detail="No next status available") diff --git a/main/schemas/partner_request/trip/create.py b/main/schemas/partner_request/trip/create.py new file mode 100644 index 0000000..01600b6 --- /dev/null +++ b/main/schemas/partner_request/trip/create.py @@ -0,0 +1,32 @@ +"""Create request schemas for trip partner requests""" + +from typing import Optional as Opt, List +from pydantic import BaseModel + +from .base import TripPreference +from .ride_hailing import RideHailingPreference +from ...base.route import RouteItem +from ...base import Weekday +import datetime + + +class RideHailingPRCreate(BaseModel): + """网约车搭子请求创建请求""" + + title: Opt[str] = None + introduction: Opt[str] = None + route: List[RouteItem] = [] + trip_preference: Opt[TripPreference] = None + ride_hailing_preference: Opt[RideHailingPreference] = None + + +class CommutePRCreate(BaseModel): + """通勤搭子请求创建请求""" + + title: Opt[str] = None + introduction: Opt[str] = None + route: List[RouteItem] = [] + trip_preference: Opt[TripPreference] = None + on_at: Opt[datetime.time] = None + off_at: Opt[datetime.time] = None + workdays: Opt[List[Weekday]] = None diff --git a/tests/test_pr/test_create_pr.py b/tests/test_pr/test_create_pr.py new file mode 100644 index 0000000..495b90d --- /dev/null +++ b/tests/test_pr/test_create_pr.py @@ -0,0 +1,184 @@ +"""Tests for creating partner requests""" + +import pytest +from fastapi.testclient import TestClient +from unittest.mock import Mock, patch, MagicMock +import datetime + +from run import app +from main.schemas.partner_request import PartnerRequestL2Type +from main.schemas.base.route import RouteItem, RouteItemDatetime + + +@pytest.fixture +def client(): + """Create test client""" + return TestClient(app) + + +@pytest.fixture +def mock_auth(): + """Mock authentication""" + return Mock(user_id="test-user-123") + + +@pytest.fixture +def mock_db_session(): + """Mock database session""" + session = MagicMock() + return session + + +class TestCreatePartnerRequest: + """Test suite for creating partner requests""" + + def test_create_ride_hailing_pr(self, client, mock_auth, mock_db_session): + """Test creating a ride-hailing partner request""" + with patch("main.routes.require_auth", return_value=mock_auth): + with patch("main.routes.get_db_session", return_value=mock_db_session): + with patch("main.managers.partner_request.trip.ride_hailing.RideHailingPRManager.create") as mock_create: + mock_create.return_value = 123 + + response = client.post( + "/partner_request/ride_hailing", + json={ + "title": "Test Ride Hailing", + "introduction": "Test intro", + "route": [ + { + "location": "loc1", + "datetime": { + "datetime": datetime.datetime.now().isoformat(), + "bring_ahead": 5, + "put_off": 10 + } + }, + { + "location": "loc2", + "datetime": {} + } + ], + "ride_hailing_preference": { + "ride_types": [] + } + } + ) + + assert response.status_code == 200 + assert response.json() == 123 + mock_create.assert_called_once() + + def test_create_commute_pr(self, client, mock_auth, mock_db_session): + """Test creating a commute partner request""" + with patch("main.routes.require_auth", return_value=mock_auth): + with patch("main.routes.get_db_session", return_value=mock_db_session): + with patch("main.managers.partner_request.trip.commute.CommutePRManager.create") as mock_create: + mock_create.return_value = 456 + + response = client.post( + "/partner_request/commute", + json={ + "title": "Test Commute", + "introduction": "Test intro", + "route": [ + { + "location": "loc1", + "datetime": { + "datetime": datetime.datetime.now().isoformat(), + "bring_ahead": 5, + "put_off": 10 + } + }, + { + "location": "loc2", + "datetime": {} + } + ], + "on_at": "08:00:00", + "off_at": "18:00:00", + "workdays": ["monday", "tuesday", "wednesday", "thursday", "friday"] + } + ) + + assert response.status_code == 200 + assert response.json() == 456 + mock_create.assert_called_once() + + def test_create_unsupported_type(self, client, mock_auth, mock_db_session): + """Test creating partner request with unsupported type""" + with patch("main.routes.require_auth", return_value=mock_auth): + with patch("main.routes.get_db_session", return_value=mock_db_session): + response = client.post( + "/partner_request/travel", + json={ + "title": "Test Travel", + "introduction": "Test intro" + } + ) + + # Should fail because travel type is not implemented in create endpoint + assert response.status_code == 400 + assert "Unsupported partner request type" in response.json()["detail"] + + +class TestPublishIdempotent: + """Test suite for idempotent publish operation""" + + def test_publish_already_joinable(self, client, mock_auth, mock_db_session): + """Test publishing a partner request that is already JOINABLE""" + from main.schemas.partner_request import PartnerRequest, PartnerRequestStatus + + # Mock a PR that's already JOINABLE + mock_pr = Mock(spec=PartnerRequest) + mock_pr.id = 1 + mock_pr.status = PartnerRequestStatus.JOINABLE.value + mock_pr.is_admin.return_value = True + + mock_db_session.get.return_value = mock_pr + + with patch("main.routes.require_auth", return_value=mock_auth): + with patch("main.routes.get_db_session", return_value=mock_db_session): + response = client.put("/partner_request/1/publish") + + assert response.status_code == 200 + # Should not call db.add or db.commit since already in target state + mock_db_session.add.assert_not_called() + mock_db_session.commit.assert_not_called() + + +class TestCancelIdempotent: + """Test suite for idempotent cancel operation""" + + def test_cancel_already_cancelled(self, client, mock_auth, mock_db_session): + """Test canceling a partner request that is already CANCELLED""" + from main.schemas.partner_request import PartnerRequest, PartnerRequestStatus + + # Mock a PR that's already CANCELLED + mock_pr = Mock(spec=PartnerRequest) + mock_pr.id = 1 + mock_pr.status = PartnerRequestStatus.CANCELLED.value + mock_pr.is_admin.return_value = True + + mock_db_session.get.return_value = mock_pr + + with patch("main.routes.require_auth", return_value=mock_auth): + with patch("main.routes.get_db_session", return_value=mock_db_session): + response = client.put("/partner_request/1/cancel") + + assert response.status_code == 200 + # Should not call db.add or db.commit since already in target state + mock_db_session.add.assert_not_called() + mock_db_session.commit.assert_not_called() + + +class TestNextStatusRemoved: + """Test that next_status endpoint has been removed""" + + def test_next_status_endpoint_removed(self, client, mock_auth, mock_db_session): + """Test that the next_status endpoint no longer exists""" + with patch("main.routes.require_auth", return_value=mock_auth): + with patch("main.routes.get_db_session", return_value=mock_db_session): + response = client.put("/partner_request/1/status/next") + + # Should return 404 since the endpoint is removed + assert response.status_code == 404 From fd20d491e69f1e815a97f63547502c728a9be42d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 04:31:09 +0000 Subject: [PATCH 3/7] Use discriminated union for PartnerRequestCreate to support different types Co-authored-by: xiaoland <37663413+xiaoland@users.noreply.github.com> --- main/routes.py | 8 ++++++-- main/schemas/partner_request/trip/create.py | 13 +++++++++++-- tests/test_pr/test_create_pr.py | 2 ++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/main/routes.py b/main/routes.py index a8f4841..c382dd4 100644 --- a/main/routes.py +++ b/main/routes.py @@ -19,7 +19,11 @@ PartnerRequestListType, PartnerRequestL2Type, ) -from .schemas.partner_request.trip.create import RideHailingPRCreate, CommutePRCreate +from .schemas.partner_request.trip.create import ( + PartnerRequestCreate, + RideHailingPRCreate, + CommutePRCreate, +) from .managers.partner_request.trip.ride_hailing import RideHailingPRManager from .managers.partner_request.trip.commute import CommutePRManager @@ -69,7 +73,7 @@ def get_partner_request_list( @router.post("/partner_request/{pr_type}") def create_partner_request( pr_type: PartnerRequestL2Type, - data: RideHailingPRCreate | CommutePRCreate, + data: PartnerRequestCreate, auth: AuthInfo = Depends(require_auth), db: sqlmodel.Session = Depends(get_db_session), ) -> PartnerRequestRef: diff --git a/main/schemas/partner_request/trip/create.py b/main/schemas/partner_request/trip/create.py index 01600b6..35273d2 100644 --- a/main/schemas/partner_request/trip/create.py +++ b/main/schemas/partner_request/trip/create.py @@ -1,7 +1,7 @@ """Create request schemas for trip partner requests""" -from typing import Optional as Opt, List -from pydantic import BaseModel +from typing import Optional as Opt, List, Literal, Annotated +from pydantic import BaseModel, Field from .base import TripPreference from .ride_hailing import RideHailingPreference @@ -13,6 +13,7 @@ class RideHailingPRCreate(BaseModel): """网约车搭子请求创建请求""" + type: Literal["ride_hailing"] = "ride_hailing" title: Opt[str] = None introduction: Opt[str] = None route: List[RouteItem] = [] @@ -23,6 +24,7 @@ class RideHailingPRCreate(BaseModel): class CommutePRCreate(BaseModel): """通勤搭子请求创建请求""" + type: Literal["commute"] = "commute" title: Opt[str] = None introduction: Opt[str] = None route: List[RouteItem] = [] @@ -30,3 +32,10 @@ class CommutePRCreate(BaseModel): on_at: Opt[datetime.time] = None off_at: Opt[datetime.time] = None workdays: Opt[List[Weekday]] = None + + +PartnerRequestCreate = Annotated[ + RideHailingPRCreate | CommutePRCreate, + Field(discriminator="type") +] + diff --git a/tests/test_pr/test_create_pr.py b/tests/test_pr/test_create_pr.py index 495b90d..90ebd0c 100644 --- a/tests/test_pr/test_create_pr.py +++ b/tests/test_pr/test_create_pr.py @@ -42,6 +42,7 @@ def test_create_ride_hailing_pr(self, client, mock_auth, mock_db_session): response = client.post( "/partner_request/ride_hailing", json={ + "type": "ride_hailing", "title": "Test Ride Hailing", "introduction": "Test intro", "route": [ @@ -78,6 +79,7 @@ def test_create_commute_pr(self, client, mock_auth, mock_db_session): response = client.post( "/partner_request/commute", json={ + "type": "commute", "title": "Test Commute", "introduction": "Test intro", "route": [ From e0338554139036dae707b31bea888d50465312b0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 04:31:59 +0000 Subject: [PATCH 4/7] Make manager publish/cancel methods idempotent as well Co-authored-by: xiaoland <37663413+xiaoland@users.noreply.github.com> --- main/managers/partner_request/base.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/main/managers/partner_request/base.py b/main/managers/partner_request/base.py index aee8061..6cda9f0 100644 --- a/main/managers/partner_request/base.py +++ b/main/managers/partner_request/base.py @@ -108,6 +108,10 @@ def publish(cls, pr_id: PartnerRequestRef, account_id: AccountRef) -> Opt[Partne if not pr.is_admin(account_id): raise ValueError("Must be admin") + # Idempotent: if already published, just return + if pr.status == PartnerRequestStatus.JOINABLE.value: + return pr + if pr.status != PartnerRequestStatus.DRAFT.value: raise ValueError("Can only publish draft") @@ -140,6 +144,10 @@ def cancel(cls, pr_id: PartnerRequestRef, account_id: AccountRef) -> Opt[Partner if not pr.is_admin(account_id): raise ValueError("Must be admin") + # Idempotent: if already cancelled, just return + if pr.status == PartnerRequestStatus.CANCELLED.value: + return pr + if pr.status not in [ PartnerRequestStatus.JOINABLE.value, PartnerRequestStatus.READY.value, From 11f0929d92714994ed24b21479d94ceb567a292a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 04:34:29 +0000 Subject: [PATCH 5/7] Address code review feedback: remove redundant checks and fix defaults Co-authored-by: xiaoland <37663413+xiaoland@users.noreply.github.com> --- main/managers/partner_request/trip/commute.py | 2 +- main/routes.py | 4 ---- main/schemas/partner_request/trip/create.py | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/main/managers/partner_request/trip/commute.py b/main/managers/partner_request/trip/commute.py index d3c3a0f..349b823 100644 --- a/main/managers/partner_request/trip/commute.py +++ b/main/managers/partner_request/trip/commute.py @@ -75,7 +75,7 @@ def create( trip_preference=data.trip_preference, on_at=data.on_at, off_at=data.off_at, - workdays=data.workdays if data.workdays else None, + workdays=data.workdays, ) db.add(content) db.commit() diff --git a/main/routes.py b/main/routes.py index c382dd4..77ad3fb 100644 --- a/main/routes.py +++ b/main/routes.py @@ -85,12 +85,8 @@ def create_partner_request( account_id = auth.user_id if pr_type == PartnerRequestL2Type.RIDE_HAILING: - if not isinstance(data, RideHailingPRCreate): - raise HTTPException(status_code=400, detail="Invalid data for ride_hailing type") pr_id = RideHailingPRManager.create(account_id, data, db) elif pr_type == PartnerRequestL2Type.COMMUTE: - if not isinstance(data, CommutePRCreate): - raise HTTPException(status_code=400, detail="Invalid data for commute type") pr_id = CommutePRManager.create(account_id, data, db) else: raise HTTPException(status_code=400, detail=f"Unsupported partner request type: {pr_type}") diff --git a/main/schemas/partner_request/trip/create.py b/main/schemas/partner_request/trip/create.py index 35273d2..1331f9e 100644 --- a/main/schemas/partner_request/trip/create.py +++ b/main/schemas/partner_request/trip/create.py @@ -18,7 +18,7 @@ class RideHailingPRCreate(BaseModel): introduction: Opt[str] = None route: List[RouteItem] = [] trip_preference: Opt[TripPreference] = None - ride_hailing_preference: Opt[RideHailingPreference] = None + ride_hailing_preference: RideHailingPreference = RideHailingPreference() class CommutePRCreate(BaseModel): From cc06e2afcf27cbb01aa05e8cb465bab2717a58ef Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 04:36:11 +0000 Subject: [PATCH 6/7] Final code review improvements: organize imports and improve error messages Co-authored-by: xiaoland <37663413+xiaoland@users.noreply.github.com> --- main/managers/partner_request/trip/commute.py | 4 +++- main/managers/partner_request/trip/ride_hailing.py | 4 +++- main/routes.py | 6 +++++- main/schemas/partner_request/trip/create.py | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/main/managers/partner_request/trip/commute.py b/main/managers/partner_request/trip/commute.py index 349b823..64e558f 100644 --- a/main/managers/partner_request/trip/commute.py +++ b/main/managers/partner_request/trip/commute.py @@ -53,9 +53,11 @@ def create( """ logger.info("Create commute PR", account_id=account_id) - should_close_session = db is None if db is None: db = SessionLocal() + should_close_session = True + else: + should_close_session = False try: # Create base partner request diff --git a/main/managers/partner_request/trip/ride_hailing.py b/main/managers/partner_request/trip/ride_hailing.py index 39171f9..4df52b0 100644 --- a/main/managers/partner_request/trip/ride_hailing.py +++ b/main/managers/partner_request/trip/ride_hailing.py @@ -53,9 +53,11 @@ def create( """ logger.info("Create ride-hailing PR", account_id=account_id) - should_close_session = db is None if db is None: db = SessionLocal() + should_close_session = True + else: + should_close_session = False try: # Create base partner request diff --git a/main/routes.py b/main/routes.py index 77ad3fb..839edaa 100644 --- a/main/routes.py +++ b/main/routes.py @@ -89,7 +89,11 @@ def create_partner_request( elif pr_type == PartnerRequestL2Type.COMMUTE: pr_id = CommutePRManager.create(account_id, data, db) else: - raise HTTPException(status_code=400, detail=f"Unsupported partner request type: {pr_type}") + supported_types = ", ".join([t.value for t in [PartnerRequestL2Type.RIDE_HAILING, PartnerRequestL2Type.COMMUTE]]) + raise HTTPException( + status_code=400, + detail=f"Unsupported partner request type: {pr_type}. Supported types: {supported_types}" + ) return pr_id diff --git a/main/schemas/partner_request/trip/create.py b/main/schemas/partner_request/trip/create.py index 1331f9e..c7d03b3 100644 --- a/main/schemas/partner_request/trip/create.py +++ b/main/schemas/partner_request/trip/create.py @@ -1,5 +1,6 @@ """Create request schemas for trip partner requests""" +import datetime from typing import Optional as Opt, List, Literal, Annotated from pydantic import BaseModel, Field @@ -7,7 +8,6 @@ from .ride_hailing import RideHailingPreference from ...base.route import RouteItem from ...base import Weekday -import datetime class RideHailingPRCreate(BaseModel): From 13234e7e0fce01217e3a0f27e3bdb63049b80402 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 04:37:30 +0000 Subject: [PATCH 7/7] Use constant for supported create types to avoid maintenance burden Co-authored-by: xiaoland <37663413+xiaoland@users.noreply.github.com> --- main/routes.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/main/routes.py b/main/routes.py index 839edaa..dee9caa 100644 --- a/main/routes.py +++ b/main/routes.py @@ -29,6 +29,9 @@ router = fastapi.APIRouter() +# Supported partner request types for creation +SUPPORTED_CREATE_TYPES = [PartnerRequestL2Type.RIDE_HAILING, PartnerRequestL2Type.COMMUTE] + @router.get("/partner_request/list/{list_type}") def get_partner_request_list( @@ -89,10 +92,10 @@ def create_partner_request( elif pr_type == PartnerRequestL2Type.COMMUTE: pr_id = CommutePRManager.create(account_id, data, db) else: - supported_types = ", ".join([t.value for t in [PartnerRequestL2Type.RIDE_HAILING, PartnerRequestL2Type.COMMUTE]]) + supported = ", ".join([t.value for t in SUPPORTED_CREATE_TYPES]) raise HTTPException( status_code=400, - detail=f"Unsupported partner request type: {pr_type}. Supported types: {supported_types}" + detail=f"Unsupported partner request type: {pr_type}. Supported types: {supported}" ) return pr_id