Aryan Jain commited on
Commit
1f780d7
·
1 Parent(s): 6c377a5

update rfp and proposal apis

Browse files
src/controllers/__init__.py CHANGED
@@ -8,9 +8,9 @@ from ._evaluation_controller import EvaluationController
8
 
9
  api_router = APIRouter()
10
 
11
- api_router.include_router(RFPController().router, prefix="/rfps", tags=["RFPs"])
12
  api_router.include_router(
13
- ProposalController().router, prefix="/proposals", tags=["Proposals"]
14
  )
15
  api_router.include_router(
16
  ProposalAIController().router,
 
8
 
9
  api_router = APIRouter()
10
 
11
+ api_router.include_router(RFPController().router)
12
  api_router.include_router(
13
+ ProposalController().router
14
  )
15
  api_router.include_router(
16
  ProposalAIController().router,
src/controllers/_proposal_controller.py CHANGED
@@ -1,4 +1,4 @@
1
- from fastapi import APIRouter, HTTPException, Query
2
  from pydantic import BaseModel
3
  from typing import List, Optional
4
  from uuid import UUID
@@ -29,7 +29,6 @@ class ProposalRequest(BaseModel):
29
 
30
 
31
  class ProposalUpdateRequest(BaseModel):
32
- id: UUID
33
  rfp_id: Optional[UUID] = None
34
  name: Optional[str] = None
35
  tep: Optional[str] = None
@@ -51,41 +50,124 @@ class ProposalController:
51
  self.__proposal_service = ProposalService
52
  self.router = APIRouter()
53
  self.router.add_api_route(
54
- "/proposal",
55
  self.get_proposals,
56
  methods=["GET"],
57
  response_model=ResponseProposal,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  )
59
  self.router.add_api_route(
60
- "/proposal",
61
  self.create_proposal,
62
  methods=["POST"],
63
  response_model=ResponseProposal,
 
64
  )
65
  self.router.add_api_route(
66
- "/proposal",
67
  self.update_proposal,
68
  methods=["PUT"],
69
  response_model=ResponseProposal,
 
70
  )
71
  self.router.add_api_route(
72
- "/proposal",
73
  self.delete_proposal,
74
  methods=["DELETE"],
75
  response_model=ProposalDeleteResponse,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  )
77
 
78
  async def get_proposals(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  self,
80
- proposal_id: str = Query(None),
81
- rfp_id: str = Query(None),
82
- status: ProposalStatus = Query(None),
83
  ):
84
  async with self.__proposal_service() as service:
85
  try:
86
- proposals = await service.get_proposals(
87
- proposal_id=proposal_id, rfp_id=rfp_id, status=status
 
 
 
 
 
 
88
  )
 
 
 
 
 
 
 
 
 
89
  return ResponseProposal(
90
  status="success", data=[Proposal(**p) for p in proposals]
91
  )
@@ -110,11 +192,12 @@ class ProposalController:
110
  status_code=500, detail="Failed to create proposal."
111
  )
112
 
113
- async def update_proposal(self, proposal: ProposalUpdateRequest):
114
  async with self.__proposal_service() as service:
115
  try:
116
  updated_proposal = await service.update_proposal(
117
- proposal.model_dump(exclude_unset=True)
 
118
  )
119
  return ResponseProposal(
120
  status="success", data=[Proposal(**updated_proposal)]
@@ -126,16 +209,12 @@ class ProposalController:
126
  )
127
 
128
  async def delete_proposal(
129
- self, proposal_id: str = Query(None), rfp_id: str = Query(None)
130
  ):
131
  async with self.__proposal_service() as service:
132
  try:
133
- if not proposal_id and not rfp_id:
134
- raise HTTPException(
135
- status_code=400, detail="Proposal ID or RFP ID is required."
136
- )
137
  status = await service.delete_proposal(
138
- proposal_id=proposal_id, rfp_id=rfp_id
139
  )
140
  if not status:
141
  raise HTTPException(status_code=404, detail="Proposal not found.")
@@ -145,3 +224,37 @@ class ProposalController:
145
  raise HTTPException(
146
  status_code=500, detail="Failed to delete proposal."
147
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, HTTPException, Query, Path
2
  from pydantic import BaseModel
3
  from typing import List, Optional
4
  from uuid import UUID
 
29
 
30
 
31
  class ProposalUpdateRequest(BaseModel):
 
32
  rfp_id: Optional[UUID] = None
33
  name: Optional[str] = None
34
  tep: Optional[str] = None
 
50
  self.__proposal_service = ProposalService
51
  self.router = APIRouter()
52
  self.router.add_api_route(
53
+ "/proposals",
54
  self.get_proposals,
55
  methods=["GET"],
56
  response_model=ResponseProposal,
57
+ tags=["Proposals"],
58
+ )
59
+ self.router.add_api_route(
60
+ "/proposals/{proposal_id}",
61
+ self.get_proposals_by_id,
62
+ methods=["GET"],
63
+ response_model=ResponseProposal,
64
+ tags=["Proposals by ID"],
65
+ )
66
+ self.router.add_api_route(
67
+ "/rfps/{rfp_id}/proposals",
68
+ self.get_proposals_by_rfp_id,
69
+ methods=["GET"],
70
+ response_model=ResponseProposal,
71
+ tags=["Proposals by RFP ID"],
72
+ )
73
+ self.router.add_api_route(
74
+ "/rfps/{rfp_id}/proposals/{proposal_id}",
75
+ self.get_proposals_by_proposal_and_rfp_id,
76
+ methods=["GET"],
77
+ response_model=ResponseProposal,
78
+ tags=["Proposals by Proposal and RFP ID"],
79
  )
80
  self.router.add_api_route(
81
+ "/proposals",
82
  self.create_proposal,
83
  methods=["POST"],
84
  response_model=ResponseProposal,
85
+ tags=["Proposals"],
86
  )
87
  self.router.add_api_route(
88
+ "/proposals/{proposal_id}",
89
  self.update_proposal,
90
  methods=["PUT"],
91
  response_model=ResponseProposal,
92
+ tags=["Proposals by ID"],
93
  )
94
  self.router.add_api_route(
95
+ "/proposals/{proposal_id}",
96
  self.delete_proposal,
97
  methods=["DELETE"],
98
  response_model=ProposalDeleteResponse,
99
+ tags=["Proposals by ID"],
100
+ )
101
+ self.router.add_api_route(
102
+ "/rfps/{rfp_id}/proposals",
103
+ self.delete_proposals_by_rfp_id,
104
+ methods=["DeLETE"],
105
+ response_model=ProposalDeleteResponse,
106
+ tags=["Proposals by RFP ID"],
107
+ )
108
+ self.router.add_api_route(
109
+ "/rfps/{rfp_id}/proposals/{proposal_id}",
110
+ self.delete_proposals_by_proposal_and_rfp_id,
111
+ methods=["DeLETE"],
112
+ response_model=ProposalDeleteResponse,
113
+ tags=["Proposals by Proposal and RFP ID"],
114
  )
115
 
116
  async def get_proposals(
117
+ self
118
+ ):
119
+ async with self.__proposal_service() as service:
120
+ try:
121
+ proposals = await service.get_proposals()
122
+ return ResponseProposal(
123
+ status="success", data=[Proposal(**p) for p in proposals]
124
+ )
125
+ except Exception as e:
126
+ logger.exception(e)
127
+ raise HTTPException(
128
+ status_code=500, detail="Failed to retrieve proposals."
129
+ )
130
+
131
+ async def get_proposals_by_id(
132
+ self,
133
+ proposal_id: str = Path(...),
134
+ ):
135
+ async with self.__proposal_service() as service:
136
+ try:
137
+ proposals = await service.get_proposals(proposal_id=proposal_id)
138
+ return ResponseProposal(
139
+ status="success", data=[Proposal(**p) for p in proposals]
140
+ )
141
+ except Exception as e:
142
+ logger.exception(e)
143
+ raise HTTPException(
144
+ status_code=500, detail="Failed to retrieve proposals."
145
+ )
146
+
147
+ async def get_proposals_by_rfp_id(
148
  self,
149
+ rfp_id: str = Path(...),
 
 
150
  ):
151
  async with self.__proposal_service() as service:
152
  try:
153
+ proposals = await service.get_proposals(rfp_id=rfp_id)
154
+ return ResponseProposal(
155
+ status="success", data=[Proposal(**p) for p in proposals]
156
+ )
157
+ except Exception as e:
158
+ logger.exception(e)
159
+ raise HTTPException(
160
+ status_code=500, detail="Failed to retrieve proposals."
161
  )
162
+
163
+ async def get_proposals_by_proposal_and_rfp_id(
164
+ self,
165
+ rfp_id: str = Path(...),
166
+ proposal_id: str = Path(...),
167
+ ):
168
+ async with self.__proposal_service() as service:
169
+ try:
170
+ proposals = await service.get_proposals(rfp_id=rfp_id, proposal_id=proposal_id)
171
  return ResponseProposal(
172
  status="success", data=[Proposal(**p) for p in proposals]
173
  )
 
192
  status_code=500, detail="Failed to create proposal."
193
  )
194
 
195
+ async def update_proposal(self, proposal: ProposalUpdateRequest, proposal_id: str = Path(...)):
196
  async with self.__proposal_service() as service:
197
  try:
198
  updated_proposal = await service.update_proposal(
199
+ proposal_id=proposal_id,
200
+ proposal=proposal.model_dump(exclude_unset=True)
201
  )
202
  return ResponseProposal(
203
  status="success", data=[Proposal(**updated_proposal)]
 
209
  )
210
 
211
  async def delete_proposal(
212
+ self, proposal_id: str = Path(...)
213
  ):
214
  async with self.__proposal_service() as service:
215
  try:
 
 
 
 
216
  status = await service.delete_proposal(
217
+ proposal_id=proposal_id
218
  )
219
  if not status:
220
  raise HTTPException(status_code=404, detail="Proposal not found.")
 
224
  raise HTTPException(
225
  status_code=500, detail="Failed to delete proposal."
226
  )
227
+
228
+ async def delete_proposals_by_rfp_id(
229
+ self, rfp_id: str = Path(...)
230
+ ):
231
+ async with self.__proposal_service() as service:
232
+ try:
233
+ status = await service.delete_proposal(
234
+ rfp_id=rfp_id
235
+ )
236
+ if not status:
237
+ raise HTTPException(status_code=404, detail="Proposal not found.")
238
+ return ProposalDeleteResponse(status="success")
239
+ except Exception as e:
240
+ logger.exception(e)
241
+ raise HTTPException(
242
+ status_code=500, detail="Failed to delete proposal."
243
+ )
244
+
245
+ async def delete_proposals_by_proposal_and_rfp_id(
246
+ self, rfp_id: str = Path(...), proposal_id: str = Path(...)
247
+ ):
248
+ async with self.__proposal_service() as service:
249
+ try:
250
+ status = await service.delete_proposal(
251
+ rfp_id=rfp_id, proposal_id=proposal_id
252
+ )
253
+ if not status:
254
+ raise HTTPException(status_code=404, detail="Proposal not found.")
255
+ return ProposalDeleteResponse(status="success")
256
+ except Exception as e:
257
+ logger.exception(e)
258
+ raise HTTPException(
259
+ status_code=500, detail="Failed to delete proposal."
260
+ )
src/controllers/_rfp_controller.py CHANGED
@@ -1,3 +1,4 @@
 
1
  from fastapi import APIRouter, HTTPException, Query
2
  from pydantic import BaseModel, Field
3
  from typing import List, Optional
@@ -33,7 +34,6 @@ class RFPRequest(BaseModel):
33
 
34
 
35
  class RFPUpdateRequest(BaseModel):
36
- id: str
37
  rfp_number: Optional[str] = None
38
  name: Optional[str] = None
39
  received_proposals: Optional[int] = None
@@ -50,22 +50,38 @@ class RFPController:
50
  self.__rfp_service = RFPService
51
  self.router = APIRouter()
52
  self.router.add_api_route(
53
- "/rfp", self.get_rfps, methods=["GET"], response_model=ResponseRFP
54
  )
55
  self.router.add_api_route(
56
- "/rfp", self.create_rfp, methods=["POST"], response_model=ResponseRFP
57
  )
58
  self.router.add_api_route(
59
- "/rfp", self.update_rfp, methods=["PUT"], response_model=ResponseRFP
60
  )
61
  self.router.add_api_route(
62
- "/rfp",
 
 
 
63
  self.delete_rfp,
64
  methods=["DELETE"],
65
  response_model=RFPDeleteResponse,
 
66
  )
67
 
68
- async def get_rfps(self, rfp_id: str = Query(None)):
 
 
 
 
 
 
 
 
 
 
 
 
69
  async with self.__rfp_service() as service:
70
  try:
71
  rfps = await service.get_rfps(rfp_id=rfp_id)
@@ -89,10 +105,10 @@ class RFPController:
89
  logger.exception(e)
90
  raise HTTPException(status_code=500, detail="Failed to create RFP.")
91
 
92
- async def update_rfp(self, rfp: RFPUpdateRequest):
93
  async with self.__rfp_service() as service:
94
  try:
95
- rfp = await service.update_rfp(rfp.model_dump(exclude_unset=True))
96
  return ResponseRFP(status="success", data=[RFP(**rfp)])
97
  except HTTPException as e:
98
  logger.warning(e)
@@ -101,7 +117,7 @@ class RFPController:
101
  logger.exception(e)
102
  raise HTTPException(status_code=500, detail="Failed to update RFP.")
103
 
104
- async def delete_rfp(self, rfp_id: str = Query(...)):
105
  async with self.__rfp_service() as service:
106
  try:
107
  status = await service.delete_rfp(rfp_id)
 
1
+ from fastapi import Path
2
  from fastapi import APIRouter, HTTPException, Query
3
  from pydantic import BaseModel, Field
4
  from typing import List, Optional
 
34
 
35
 
36
  class RFPUpdateRequest(BaseModel):
 
37
  rfp_number: Optional[str] = None
38
  name: Optional[str] = None
39
  received_proposals: Optional[int] = None
 
50
  self.__rfp_service = RFPService
51
  self.router = APIRouter()
52
  self.router.add_api_route(
53
+ "/rfps", self.get_rfps, methods=["GET"], response_model=ResponseRFP, tags=["RFPs"]
54
  )
55
  self.router.add_api_route(
56
+ "/rfps/{rfp_id}", self.get_rfps_by_id, methods=["GET"], response_model=ResponseRFP, tags=["RFPs by ID"]
57
  )
58
  self.router.add_api_route(
59
+ "/rfps", self.create_rfp, methods=["POST"], response_model=ResponseRFP, tags=["RFPs"]
60
  )
61
  self.router.add_api_route(
62
+ "/rfps/{rfp_id}", self.update_rfp, methods=["PUT"], response_model=ResponseRFP, tags=["RFPs by ID"]
63
+ )
64
+ self.router.add_api_route(
65
+ "/rfps/{rfp_id}",
66
  self.delete_rfp,
67
  methods=["DELETE"],
68
  response_model=RFPDeleteResponse,
69
+ tags=["RFPs by ID"],
70
  )
71
 
72
+ async def get_rfps(self):
73
+ async with self.__rfp_service() as service:
74
+ try:
75
+ rfps = await service.get_rfps()
76
+ return ResponseRFP(status="success", data=[RFP(**rfp) for rfp in rfps])
77
+ except HTTPException as e:
78
+ logger.warning(e)
79
+ raise e
80
+ except Exception as e:
81
+ logger.exception(e)
82
+ raise HTTPException(status_code=500, detail="Failed to retrieve RFPs.")
83
+
84
+ async def get_rfps_by_id(self, rfp_id: str = Path(...)):
85
  async with self.__rfp_service() as service:
86
  try:
87
  rfps = await service.get_rfps(rfp_id=rfp_id)
 
105
  logger.exception(e)
106
  raise HTTPException(status_code=500, detail="Failed to create RFP.")
107
 
108
+ async def update_rfp(self, rfp: RFPUpdateRequest, rfp_id: str = Path(...)):
109
  async with self.__rfp_service() as service:
110
  try:
111
+ rfp = await service.update_rfp(rfp_id=rfp_id, rfp=rfp.model_dump(exclude_unset=True))
112
  return ResponseRFP(status="success", data=[RFP(**rfp)])
113
  except HTTPException as e:
114
  logger.warning(e)
 
117
  logger.exception(e)
118
  raise HTTPException(status_code=500, detail="Failed to update RFP.")
119
 
120
+ async def delete_rfp(self, rfp_id: str = Path(...)):
121
  async with self.__rfp_service() as service:
122
  try:
123
  status = await service.delete_rfp(rfp_id)
src/repositories/_proposal_repository.py CHANGED
@@ -46,9 +46,9 @@ class ProposalRepository(BaseRepository):
46
  await session.refresh(instance)
47
  return {k: v for k, v in instance.__dict__.items() if not k.startswith("_")}
48
 
49
- async def update_proposal(self, proposal: dict):
50
  async with self.get_session() as session:
51
- instance = await session.get(Proposal, proposal["id"])
52
  if not instance:
53
  return None
54
  for key, value in proposal.items():
 
46
  await session.refresh(instance)
47
  return {k: v for k, v in instance.__dict__.items() if not k.startswith("_")}
48
 
49
+ async def update_proposal(self, proposal_id: str, proposal: dict):
50
  async with self.get_session() as session:
51
+ instance = await session.get(Proposal, proposal_id)
52
  if not instance:
53
  return None
54
  for key, value in proposal.items():
src/repositories/_rfp_repository.py CHANGED
@@ -45,9 +45,9 @@ class RFPRepository(BaseRepository):
45
  }
46
  return rsult_dict
47
 
48
- async def update_rfp(self, rfp: dict):
49
  async with self.get_session() as session:
50
- instance = await session.get(RFP, rfp["id"])
51
  for key, value in rfp.items():
52
  setattr(instance, key, value)
53
  await session.commit()
 
45
  }
46
  return rsult_dict
47
 
48
+ async def update_rfp(self, rfp_id: str, rfp: dict):
49
  async with self.get_session() as session:
50
+ instance = await session.get(RFP, rfp_id)
51
  for key, value in rfp.items():
52
  setattr(instance, key, value)
53
  await session.commit()
src/services/_proposal_service.py CHANGED
@@ -28,9 +28,9 @@ class ProposalService:
28
  async with self.proposal_repository() as repository:
29
  return await repository.create_proposal(proposal)
30
 
31
- async def update_proposal(self, proposal: dict):
32
  async with self.proposal_repository() as repository:
33
- return await repository.update_proposal(proposal)
34
 
35
  async def delete_proposal(self, proposal_id: str = None, rfp_id: str = None):
36
  async with self.proposal_repository() as repository:
 
28
  async with self.proposal_repository() as repository:
29
  return await repository.create_proposal(proposal)
30
 
31
+ async def update_proposal(self, proposal_id: str, proposal: dict):
32
  async with self.proposal_repository() as repository:
33
+ return await repository.update_proposal(proposal_id=proposal_id, proposal=proposal)
34
 
35
  async def delete_proposal(self, proposal_id: str = None, rfp_id: str = None):
36
  async with self.proposal_repository() as repository:
src/services/_rfp_service.py CHANGED
@@ -20,9 +20,9 @@ class RFPService:
20
  async with self.rfp_repository() as repository:
21
  return await repository.create_rfp(rfp)
22
 
23
- async def update_rfp(self, rfp: dict):
24
  async with self.rfp_repository() as repository:
25
- return await repository.update_rfp(rfp)
26
 
27
  async def delete_rfp(self, rfp_id: str):
28
  async with self.rfp_repository() as repository:
 
20
  async with self.rfp_repository() as repository:
21
  return await repository.create_rfp(rfp)
22
 
23
+ async def update_rfp(self, rfp_id: str, rfp: dict):
24
  async with self.rfp_repository() as repository:
25
+ return await repository.update_rfp(rfp_id=rfp_id, rfp=rfp)
26
 
27
  async def delete_rfp(self, rfp_id: str):
28
  async with self.rfp_repository() as repository: