Aryan Jain commited on
Commit
fd23386
·
1 Parent(s): 1eb956a

update APIs

Browse files
src/controllers/__init__.py CHANGED
@@ -9,25 +9,11 @@ from ._evaluation_controller import EvaluationController
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,
17
- prefix="/proposal_ai_analysis",
18
- tags=["Proposal AI Analysis"],
19
- )
20
- api_router.include_router(
21
- ProposalDetailedController().router,
22
- prefix="/proposal_detailed_analysis",
23
- tags=["Proposal Detailed Analysis"],
24
- )
25
- api_router.include_router(
26
- LetterController().router
27
- )
28
- api_router.include_router(
29
- EvaluationController().router
30
- )
31
 
32
  __all__ = ["api_router"]
33
  __version__ = "0.1.0"
 
9
  api_router = APIRouter()
10
 
11
  api_router.include_router(RFPController().router)
12
+ api_router.include_router(ProposalController().router)
13
+ api_router.include_router(ProposalAIController().router)
14
+ api_router.include_router(ProposalDetailedController().router)
15
+ api_router.include_router(LetterController().router)
16
+ api_router.include_router(EvaluationController().router)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  __all__ = ["api_router"]
19
  __version__ = "0.1.0"
src/controllers/_evaluation_controller.py CHANGED
@@ -29,12 +29,22 @@ class EvaluationRequest(BaseModel):
29
  evaluation_criteria_type: EvaluationCriteriaType
30
 
31
 
 
 
 
 
 
32
  class UpdateEvaluationRequest(BaseModel):
33
  rfp_id: Optional[UUID] = None
34
  evaluation_criteria: Optional[str] = None
35
  evaluation_criteria_type: Optional[EvaluationCriteriaType] = None
36
 
37
 
 
 
 
 
 
38
  class DeleteResponse(BaseModel):
39
  status: str
40
 
@@ -58,14 +68,14 @@ class EvaluationController:
58
  tags=["Evaluation Criteria by ID"],
59
  )
60
  self.router.add_api_route(
61
- "/rpfs/{rfp_id}/evaluation_criteria",
62
  self.get_criteria_by_rfp_id,
63
  methods=["GET"],
64
  response_model=EvaluationResponse,
65
  tags=["Evaluation Criteria by RFP ID"],
66
  )
67
  self.router.add_api_route(
68
- "/rpfs/{rfp_id}/evaluation_criteria/{id}",
69
  self.get_criteria_by_proposal_and_rfp_id,
70
  methods=["GET"],
71
  response_model=EvaluationResponse,
@@ -78,6 +88,13 @@ class EvaluationController:
78
  response_model=EvaluationResponse,
79
  tags=["Evaluation Criteria"],
80
  )
 
 
 
 
 
 
 
81
  self.router.add_api_route(
82
  "/evaluation_criteria/{id}",
83
  self.update_criteria,
@@ -85,6 +102,13 @@ class EvaluationController:
85
  response_model=EvaluationResponse,
86
  tags=["Evaluation Criteria by ID"],
87
  )
 
 
 
 
 
 
 
88
  self.router.add_api_route(
89
  "/evaluation_criteria/{id}",
90
  self.delete_criteria,
@@ -93,23 +117,21 @@ class EvaluationController:
93
  tags=["Evaluation Criteria by ID"],
94
  )
95
  self.router.add_api_route(
96
- "/rpfs/{rfp_id}/evaluation_criteria",
97
  self.delete_criteria_by_rfp_id,
98
  methods=["DELETE"],
99
  response_model=DeleteResponse,
100
  tags=["Evaluation Criteria by RFP ID"],
101
  )
102
  self.router.add_api_route(
103
- "/rpfs/{rfp_id}/evaluation_criteria/{id}",
104
  self.delete_criteria_by_proposal_and_rfp_id,
105
  methods=["DELETE"],
106
  response_model=DeleteResponse,
107
  tags=["Evaluation Criteria by Proposal and RFP ID"],
108
  )
109
 
110
- async def get_criteria(
111
- self
112
- ):
113
  try:
114
  async with self.evaluation_service() as service:
115
  result = await service.get_criteria()
@@ -121,7 +143,7 @@ class EvaluationController:
121
  raise HTTPException(
122
  status_code=500, detail="Error fetching evaluation criteria"
123
  )
124
-
125
  async def get_criteria_by_id(self, id: str = Path(...)):
126
  try:
127
  async with self.evaluation_service() as service:
@@ -134,11 +156,17 @@ class EvaluationController:
134
  raise HTTPException(
135
  status_code=500, detail="Error fetching evaluation criteria"
136
  )
137
-
138
- async def get_criteria_by_rfp_id(self, rfp_id: str = Path(...)):
 
 
 
 
139
  try:
140
  async with self.evaluation_service() as service:
141
- result = await service.get_criteria(rfp_id=rfp_id)
 
 
142
  return EvaluationResponse(
143
  status="success", data=[EvaluationCriteria(**r) for r in result]
144
  )
@@ -147,8 +175,10 @@ class EvaluationController:
147
  raise HTTPException(
148
  status_code=500, detail="Error fetching evaluation criteria"
149
  )
150
-
151
- async def get_criteria_by_proposal_and_rfp_id(self, rfp_id: str = Path(...), id: str = Path(...)):
 
 
152
  try:
153
  async with self.evaluation_service() as service:
154
  result = await service.get_criteria(rfp_id=rfp_id, id=id)
@@ -176,11 +206,33 @@ class EvaluationController:
176
  status_code=500, detail="Error creating evaluation criteria"
177
  )
178
 
179
- async def update_criteria(self, criteria: UpdateEvaluationRequest, id: str = Path(...)):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  try:
181
  async with self.evaluation_service() as service:
182
  result = await service.update_criteria(
183
- id=id, evaluation_criteria=criteria.model_dump(exclude_unset=True, mode="json")
 
 
 
184
  )
185
  return EvaluationResponse(
186
  status="success", data=[EvaluationCriteria(**r) for r in result]
@@ -191,9 +243,27 @@ class EvaluationController:
191
  status_code=500, detail="Error updating evaluation criteria"
192
  )
193
 
194
- async def delete_criteria(
195
- self, id: str = Path(...)
 
 
 
196
  ):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  try:
198
  async with self.evaluation_service() as service:
199
  await service.delete_criteria(id=id)
@@ -203,7 +273,7 @@ class EvaluationController:
203
  raise HTTPException(
204
  status_code=500, detail="Error deleting evaluation criteria"
205
  )
206
-
207
  async def delete_criteria_by_rfp_id(self, rfp_id: str = Path(...)):
208
  try:
209
  async with self.evaluation_service() as service:
@@ -214,8 +284,10 @@ class EvaluationController:
214
  raise HTTPException(
215
  status_code=500, detail="Error deleting evaluation criteria"
216
  )
217
-
218
- async def delete_criteria_by_proposal_and_rfp_id(self, rfp_id: str = Path(...), id: str = Path(...)):
 
 
219
  try:
220
  async with self.evaluation_service() as service:
221
  await service.delete_criteria(rfp_id=rfp_id, id=id)
 
29
  evaluation_criteria_type: EvaluationCriteriaType
30
 
31
 
32
+ class CreateEvaluationRequest(BaseModel):
33
+ evaluation_criteria: str
34
+ evaluation_criteria_type: EvaluationCriteriaType
35
+
36
+
37
  class UpdateEvaluationRequest(BaseModel):
38
  rfp_id: Optional[UUID] = None
39
  evaluation_criteria: Optional[str] = None
40
  evaluation_criteria_type: Optional[EvaluationCriteriaType] = None
41
 
42
 
43
+ class UpdateEvaluationCriteriaByRFPRequest(BaseModel):
44
+ evaluation_criteria: Optional[str] = None
45
+ evaluation_criteria_type: Optional[EvaluationCriteriaType] = None
46
+
47
+
48
  class DeleteResponse(BaseModel):
49
  status: str
50
 
 
68
  tags=["Evaluation Criteria by ID"],
69
  )
70
  self.router.add_api_route(
71
+ "/rfps/{rfp_id}/evaluation_criteria",
72
  self.get_criteria_by_rfp_id,
73
  methods=["GET"],
74
  response_model=EvaluationResponse,
75
  tags=["Evaluation Criteria by RFP ID"],
76
  )
77
  self.router.add_api_route(
78
+ "/rfps/{rfp_id}/evaluation_criteria/{id}",
79
  self.get_criteria_by_proposal_and_rfp_id,
80
  methods=["GET"],
81
  response_model=EvaluationResponse,
 
88
  response_model=EvaluationResponse,
89
  tags=["Evaluation Criteria"],
90
  )
91
+ self.router.add_api_route(
92
+ "/rfps/{rfp_id}/evaluation_criteria",
93
+ self.create_criteria_by_rfp_id,
94
+ methods=["POST"],
95
+ response_model=EvaluationResponse,
96
+ tags=["Evaluation Criteria by RFP ID"],
97
+ )
98
  self.router.add_api_route(
99
  "/evaluation_criteria/{id}",
100
  self.update_criteria,
 
102
  response_model=EvaluationResponse,
103
  tags=["Evaluation Criteria by ID"],
104
  )
105
+ self.router.add_api_route(
106
+ "/rfps/{rfp_id}/evaluation_criteria/{id}",
107
+ self.update_criteria_by_proposal_and_rfp_id,
108
+ methods=["PUT"],
109
+ response_model=EvaluationResponse,
110
+ tags=["Evaluation Criteria by Proposal and RFP ID"],
111
+ )
112
  self.router.add_api_route(
113
  "/evaluation_criteria/{id}",
114
  self.delete_criteria,
 
117
  tags=["Evaluation Criteria by ID"],
118
  )
119
  self.router.add_api_route(
120
+ "/rfps/{rfp_id}/evaluation_criteria",
121
  self.delete_criteria_by_rfp_id,
122
  methods=["DELETE"],
123
  response_model=DeleteResponse,
124
  tags=["Evaluation Criteria by RFP ID"],
125
  )
126
  self.router.add_api_route(
127
+ "/rfps/{rfp_id}/evaluation_criteria/{id}",
128
  self.delete_criteria_by_proposal_and_rfp_id,
129
  methods=["DELETE"],
130
  response_model=DeleteResponse,
131
  tags=["Evaluation Criteria by Proposal and RFP ID"],
132
  )
133
 
134
+ async def get_criteria(self):
 
 
135
  try:
136
  async with self.evaluation_service() as service:
137
  result = await service.get_criteria()
 
143
  raise HTTPException(
144
  status_code=500, detail="Error fetching evaluation criteria"
145
  )
146
+
147
  async def get_criteria_by_id(self, id: str = Path(...)):
148
  try:
149
  async with self.evaluation_service() as service:
 
156
  raise HTTPException(
157
  status_code=500, detail="Error fetching evaluation criteria"
158
  )
159
+
160
+ async def get_criteria_by_rfp_id(
161
+ self,
162
+ rfp_id: str = Path(...),
163
+ criteria_type: Optional[EvaluationCriteriaType] = Query(None),
164
+ ):
165
  try:
166
  async with self.evaluation_service() as service:
167
+ result = await service.get_criteria(
168
+ rfp_id=rfp_id, evaluation_criteria_type=criteria_type
169
+ )
170
  return EvaluationResponse(
171
  status="success", data=[EvaluationCriteria(**r) for r in result]
172
  )
 
175
  raise HTTPException(
176
  status_code=500, detail="Error fetching evaluation criteria"
177
  )
178
+
179
+ async def get_criteria_by_proposal_and_rfp_id(
180
+ self, rfp_id: str = Path(...), id: str = Path(...)
181
+ ):
182
  try:
183
  async with self.evaluation_service() as service:
184
  result = await service.get_criteria(rfp_id=rfp_id, id=id)
 
206
  status_code=500, detail="Error creating evaluation criteria"
207
  )
208
 
209
+ async def create_criteria_by_rfp_id(
210
+ self, criteria: CreateEvaluationRequest, rfp_id: str = Path(...)
211
+ ):
212
+ try:
213
+ async with self.evaluation_service() as service:
214
+ data = criteria.model_dump(exclude_unset=True, mode="json")
215
+ data["rfp_id"] = rfp_id
216
+ result = await service.create_criteria(evaluation_criteria=data)
217
+ return EvaluationResponse(
218
+ status="success", data=[EvaluationCriteria(**r) for r in result]
219
+ )
220
+ except Exception as e:
221
+ logger.error(e)
222
+ raise HTTPException(
223
+ status_code=500, detail="Error creating evaluation criteria"
224
+ )
225
+
226
+ async def update_criteria(
227
+ self, criteria: UpdateEvaluationRequest, id: str = Path(...)
228
+ ):
229
  try:
230
  async with self.evaluation_service() as service:
231
  result = await service.update_criteria(
232
+ id=id,
233
+ evaluation_criteria=criteria.model_dump(
234
+ exclude_unset=True, mode="json"
235
+ ),
236
  )
237
  return EvaluationResponse(
238
  status="success", data=[EvaluationCriteria(**r) for r in result]
 
243
  status_code=500, detail="Error updating evaluation criteria"
244
  )
245
 
246
+ async def update_criteria_by_proposal_and_rfp_id(
247
+ self,
248
+ criteria: UpdateEvaluationCriteriaByRFPRequest,
249
+ rfp_id: str = Path(...),
250
+ id: str = Path(...),
251
  ):
252
+ try:
253
+ async with self.evaluation_service() as service:
254
+ data = criteria.model_dump(exclude_unset=True, mode="json")
255
+ data["rfp_id"] = rfp_id
256
+ result = await service.update_criteria(id=id, evaluation_criteria=data)
257
+ return EvaluationResponse(
258
+ status="success", data=[EvaluationCriteria(**r) for r in result]
259
+ )
260
+ except Exception as e:
261
+ logger.error(e)
262
+ raise HTTPException(
263
+ status_code=500, detail="Error updating evaluation criteria"
264
+ )
265
+
266
+ async def delete_criteria(self, id: str = Path(...)):
267
  try:
268
  async with self.evaluation_service() as service:
269
  await service.delete_criteria(id=id)
 
273
  raise HTTPException(
274
  status_code=500, detail="Error deleting evaluation criteria"
275
  )
276
+
277
  async def delete_criteria_by_rfp_id(self, rfp_id: str = Path(...)):
278
  try:
279
  async with self.evaluation_service() as service:
 
284
  raise HTTPException(
285
  status_code=500, detail="Error deleting evaluation criteria"
286
  )
287
+
288
+ async def delete_criteria_by_proposal_and_rfp_id(
289
+ self, rfp_id: str = Path(...), id: str = Path(...)
290
+ ):
291
  try:
292
  async with self.evaluation_service() as service:
293
  await service.delete_criteria(rfp_id=rfp_id, id=id)
src/controllers/_letter_controller.py CHANGED
@@ -29,12 +29,22 @@ class LetterRequest(BaseModel):
29
  letter_type: LetterType
30
 
31
 
 
 
 
 
 
32
  class UpdateLetterRequest(BaseModel):
33
  proposal_id: Optional[UUID] = None
34
  letter: Optional[str] = None
35
  letter_type: Optional[LetterType] = None
36
 
37
 
 
 
 
 
 
38
  class DeleteResponse(BaseModel):
39
  status: str
40
 
@@ -44,7 +54,11 @@ class LetterController:
44
  self.letter_service = LetterService
45
  self.router = APIRouter()
46
  self.router.add_api_route(
47
- "/letters", self.get_letters, methods=["GET"], response_model=Response, tags=["Letters"]
 
 
 
 
48
  )
49
  self.router.add_api_route(
50
  "/letters/{id}",
@@ -54,24 +68,46 @@ class LetterController:
54
  tags=["Letters by ID"],
55
  )
56
  self.router.add_api_route(
57
- "proposals/{proposal_id}/letters",
58
  self.get_letters_by_proposal_id,
59
  methods=["GET"],
60
  response_model=Response,
61
  tags=["Letters by Proposal ID"],
62
  )
63
  self.router.add_api_route(
64
- "proposals/{proposal_id}/letters/{id}",
65
  self.get_letters_by_proposal_and_id,
66
  methods=["GET"],
67
  response_model=Response,
68
  tags=["Letters by Proposal and ID"],
69
  )
70
  self.router.add_api_route(
71
- "/letters", self.create_letter, methods=["POST"], response_model=Response, tags=["Letters"]
 
 
 
 
 
 
 
 
 
 
 
72
  )
73
  self.router.add_api_route(
74
- "/letters/{id}", self.update_letter, methods=["PUT"], response_model=Response, tags=["Letters by ID"]
 
 
 
 
 
 
 
 
 
 
 
75
  )
76
  self.router.add_api_route(
77
  "/letters/{id}",
@@ -95,9 +131,7 @@ class LetterController:
95
  tags=["Letters by Proposal and ID"],
96
  )
97
 
98
- async def get_letters(
99
- self
100
- ):
101
  try:
102
  async with self.letter_service() as service:
103
  result = await service.get_letters()
@@ -105,7 +139,7 @@ class LetterController:
105
  except Exception as e:
106
  logger.error(e)
107
  raise HTTPException(status_code=500, detail="Error fetching letters")
108
-
109
  async def get_letters_by_id(self, id: str = Path(...)):
110
  try:
111
  async with self.letter_service() as service:
@@ -114,17 +148,23 @@ class LetterController:
114
  except Exception as e:
115
  logger.error(e)
116
  raise HTTPException(status_code=500, detail="Error fetching letter")
117
-
118
- async def get_letters_by_proposal_id(self, proposal_id: str = Path(...)):
 
 
119
  try:
120
  async with self.letter_service() as service:
121
- result = await service.get_letters(proposal_id=proposal_id)
 
 
122
  return Response(status="success", data=[Letter(**r) for r in result])
123
  except Exception as e:
124
  logger.error(e)
125
  raise HTTPException(status_code=500, detail="Error fetching letter")
126
-
127
- async def get_letters_by_proposal_and_id(self, proposal_id: str = Path(...), id: str = Path(...)):
 
 
128
  try:
129
  async with self.letter_service() as service:
130
  result = await service.get_letters(proposal_id=proposal_id, id=id)
@@ -144,6 +184,19 @@ class LetterController:
144
  logger.error(e)
145
  raise HTTPException(status_code=500, detail="Error creating letter")
146
 
 
 
 
 
 
 
 
 
 
 
 
 
 
147
  async def update_letter(self, letter: UpdateLetterRequest, id: str = Path(...)):
148
  try:
149
  async with self.letter_service() as service:
@@ -155,9 +208,23 @@ class LetterController:
155
  logger.error(e)
156
  raise HTTPException(status_code=500, detail="Error updating letter")
157
 
158
- async def delete_letter(
159
- self, id: str = Path(...)
 
 
 
160
  ):
 
 
 
 
 
 
 
 
 
 
 
161
  try:
162
  async with self.letter_service() as service:
163
  result = await service.delete_letter(id=id)
@@ -165,7 +232,7 @@ class LetterController:
165
  except Exception as e:
166
  logger.error(e)
167
  raise HTTPException(status_code=500, detail="Error deleting letter")
168
-
169
  async def delete_letters_by_proposal_id(self, proposal_id: str = Path(...)):
170
  try:
171
  async with self.letter_service() as service:
@@ -174,8 +241,10 @@ class LetterController:
174
  except Exception as e:
175
  logger.error(e)
176
  raise HTTPException(status_code=500, detail="Error deleting letter")
177
-
178
- async def delete_letters_by_proposal_and_id(self, proposal_id: str = Path(...), id: str = Path(...)):
 
 
179
  try:
180
  async with self.letter_service() as service:
181
  result = await service.delete_letter(proposal_id=proposal_id, id=id)
 
29
  letter_type: LetterType
30
 
31
 
32
+ class CreateLetterRequest(BaseModel):
33
+ letter: str
34
+ letter_type: LetterType
35
+
36
+
37
  class UpdateLetterRequest(BaseModel):
38
  proposal_id: Optional[UUID] = None
39
  letter: Optional[str] = None
40
  letter_type: Optional[LetterType] = None
41
 
42
 
43
+ class UpdateLetterRequestByProposalAndId(BaseModel):
44
+ letter: Optional[str] = None
45
+ letter_type: Optional[LetterType] = None
46
+
47
+
48
  class DeleteResponse(BaseModel):
49
  status: str
50
 
 
54
  self.letter_service = LetterService
55
  self.router = APIRouter()
56
  self.router.add_api_route(
57
+ "/letters",
58
+ self.get_letters,
59
+ methods=["GET"],
60
+ response_model=Response,
61
+ tags=["Letters"],
62
  )
63
  self.router.add_api_route(
64
  "/letters/{id}",
 
68
  tags=["Letters by ID"],
69
  )
70
  self.router.add_api_route(
71
+ "/proposals/{proposal_id}/letters",
72
  self.get_letters_by_proposal_id,
73
  methods=["GET"],
74
  response_model=Response,
75
  tags=["Letters by Proposal ID"],
76
  )
77
  self.router.add_api_route(
78
+ "/proposals/{proposal_id}/letters/{id}",
79
  self.get_letters_by_proposal_and_id,
80
  methods=["GET"],
81
  response_model=Response,
82
  tags=["Letters by Proposal and ID"],
83
  )
84
  self.router.add_api_route(
85
+ "/letters",
86
+ self.create_letter,
87
+ methods=["POST"],
88
+ response_model=Response,
89
+ tags=["Letters"],
90
+ )
91
+ self.router.add_api_route(
92
+ "/proposals/{proposal_id}/letters",
93
+ self.create_letters_by_proposal_id,
94
+ methods=["POST"],
95
+ response_model=Response,
96
+ tags=["Letters by Proposal ID"],
97
  )
98
  self.router.add_api_route(
99
+ "/letters/{id}",
100
+ self.update_letter,
101
+ methods=["PUT"],
102
+ response_model=Response,
103
+ tags=["Letters by ID"],
104
+ )
105
+ self.router.add_api_route(
106
+ "/proposals/{proposal_id}/letters/{id}",
107
+ self.update_letters_by_proposal_and_id,
108
+ methods=["PUT"],
109
+ response_model=Response,
110
+ tags=["Letters by Proposal and ID"],
111
  )
112
  self.router.add_api_route(
113
  "/letters/{id}",
 
131
  tags=["Letters by Proposal and ID"],
132
  )
133
 
134
+ async def get_letters(self):
 
 
135
  try:
136
  async with self.letter_service() as service:
137
  result = await service.get_letters()
 
139
  except Exception as e:
140
  logger.error(e)
141
  raise HTTPException(status_code=500, detail="Error fetching letters")
142
+
143
  async def get_letters_by_id(self, id: str = Path(...)):
144
  try:
145
  async with self.letter_service() as service:
 
148
  except Exception as e:
149
  logger.error(e)
150
  raise HTTPException(status_code=500, detail="Error fetching letter")
151
+
152
+ async def get_letters_by_proposal_id(
153
+ self, proposal_id: str = Path(...), letter_type: LetterType = Query(None)
154
+ ):
155
  try:
156
  async with self.letter_service() as service:
157
+ result = await service.get_letters(
158
+ proposal_id=proposal_id, letter_type=letter_type
159
+ )
160
  return Response(status="success", data=[Letter(**r) for r in result])
161
  except Exception as e:
162
  logger.error(e)
163
  raise HTTPException(status_code=500, detail="Error fetching letter")
164
+
165
+ async def get_letters_by_proposal_and_id(
166
+ self, proposal_id: str = Path(...), id: str = Path(...)
167
+ ):
168
  try:
169
  async with self.letter_service() as service:
170
  result = await service.get_letters(proposal_id=proposal_id, id=id)
 
184
  logger.error(e)
185
  raise HTTPException(status_code=500, detail="Error creating letter")
186
 
187
+ async def create_letters_by_proposal_id(
188
+ self, letter: CreateLetterRequest, proposal_id: str = Path(...)
189
+ ):
190
+ try:
191
+ async with self.letter_service() as service:
192
+ data = letter.model_dump(exclude_unset=True, mode="json")
193
+ data["proposal_id"] = proposal_id
194
+ result = await service.create_letter(letter=data)
195
+ return Response(status="success", data=[Letter(**r) for r in result])
196
+ except Exception as e:
197
+ logger.error(e)
198
+ raise HTTPException(status_code=500, detail="Error creating letter")
199
+
200
  async def update_letter(self, letter: UpdateLetterRequest, id: str = Path(...)):
201
  try:
202
  async with self.letter_service() as service:
 
208
  logger.error(e)
209
  raise HTTPException(status_code=500, detail="Error updating letter")
210
 
211
+ async def update_letters_by_proposal_and_id(
212
+ self,
213
+ letter: UpdateLetterRequestByProposalAndId,
214
+ proposal_id: str = Path(...),
215
+ id: str = Path(...),
216
  ):
217
+ try:
218
+ async with self.letter_service() as service:
219
+ data = letter.model_dump(exclude_unset=True, mode="json")
220
+ data["proposal_id"] = proposal_id
221
+ result = await service.update_letter(id=id, letter=data)
222
+ return Response(status="success", data=[Letter(**r) for r in result])
223
+ except Exception as e:
224
+ logger.error(e)
225
+ raise HTTPException(status_code=500, detail="Error updating letter")
226
+
227
+ async def delete_letter(self, id: str = Path(...)):
228
  try:
229
  async with self.letter_service() as service:
230
  result = await service.delete_letter(id=id)
 
232
  except Exception as e:
233
  logger.error(e)
234
  raise HTTPException(status_code=500, detail="Error deleting letter")
235
+
236
  async def delete_letters_by_proposal_id(self, proposal_id: str = Path(...)):
237
  try:
238
  async with self.letter_service() as service:
 
241
  except Exception as e:
242
  logger.error(e)
243
  raise HTTPException(status_code=500, detail="Error deleting letter")
244
+
245
+ async def delete_letters_by_proposal_and_id(
246
+ self, proposal_id: str = Path(...), id: str = Path(...)
247
+ ):
248
  try:
249
  async with self.letter_service() as service:
250
  result = await service.delete_letter(proposal_id=proposal_id, id=id)
src/controllers/_proposal_ai_analysis_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
@@ -119,7 +119,6 @@ class ProposalStrengthRequest(BaseModel):
119
 
120
 
121
  class UpdateProposalStrengthRequest(BaseModel):
122
- id: UUID
123
  proposal_id: Optional[UUID] = None
124
  strength_point: Optional[str] = None
125
 
@@ -130,7 +129,6 @@ class ProposalWeaknessRequest(BaseModel):
130
 
131
 
132
  class UpdateProposalWeaknessRequest(BaseModel):
133
- id: UUID
134
  proposal_id: Optional[UUID] = None
135
  weakness_point: Optional[str] = None
136
 
@@ -141,7 +139,6 @@ class ProposalRejectionReasonRequest(BaseModel):
141
 
142
 
143
  class UpdateProposalRejectionReasonRequest(BaseModel):
144
- id: UUID
145
  proposal_id: Optional[UUID] = None
146
  reason: Optional[str] = None
147
 
@@ -152,7 +149,6 @@ class ProposalImprovementRequest(BaseModel):
152
 
153
 
154
  class UpdateProposalImprovementRequest(BaseModel):
155
- id: UUID
156
  proposal_id: Optional[UUID] = None
157
  improvement_point: Optional[str] = None
158
 
@@ -161,35 +157,33 @@ class CreateAiAnalysisRequest(BaseModel):
161
  proposal_id: UUID
162
  ai_score: float
163
 
 
 
164
 
165
  class UpdateAiAnalysisRequest(BaseModel):
166
- id: Optional[UUID] = None
167
  proposal_id: Optional[UUID] = None
168
  ai_score: Optional[float] = None
169
 
 
 
170
 
171
  class CreateAllProposalStrengthsRequest(BaseModel):
172
- proposal_id: UUID
173
  strength_point: List[str]
174
 
175
 
176
  class CreateAllProposalWeaknessRequest(BaseModel):
177
- proposal_id: UUID
178
  weakness_point: List[str]
179
 
180
 
181
  class CreateAllProposalRejectionReasonsRequest(BaseModel):
182
- proposal_id: UUID
183
  reason: List[str]
184
 
185
 
186
  class CreateAllProposalImprovementsRequest(BaseModel):
187
- proposal_id: UUID
188
  improvement_point: List[str]
189
 
190
 
191
  class CreateAllProposalAnalysisRequest(BaseModel):
192
- proposal_id: UUID
193
  ai_score: float
194
  strengths: Optional[List[str]] = None
195
  weaknesses: Optional[List[str]] = None
@@ -198,7 +192,6 @@ class CreateAllProposalAnalysisRequest(BaseModel):
198
 
199
 
200
  class UpdateAllProposalAnalysisRequest(BaseModel):
201
- proposal_id: UUID
202
  ai_score: Optional[float] = None
203
  strengths: Optional[List[str]] = None
204
  weaknesses: Optional[List[str]] = None
@@ -218,6 +211,27 @@ class ProposalAIController:
218
  tags=["Proposal Strengths"],
219
  response_model=ProposalStrengthResponse,
220
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  self.router.add_api_route(
222
  "/proposal_strengths",
223
  self.create_proposal_strengths,
@@ -226,31 +240,45 @@ class ProposalAIController:
226
  response_model=ProposalStrengthResponse,
227
  )
228
  self.router.add_api_route(
229
- "/proposal_strengths/all",
230
  self.create_all_proposal_strengths,
231
  methods=["POST"],
232
- tags=["Proposal All Strengths"],
233
- response_model=ProposalStrengthResponse,
234
  )
235
  self.router.add_api_route(
236
- "/proposal_strengths",
237
  self.update_proposal_strengths,
238
  methods=["PUT"],
239
- tags=["Proposal Strengths"],
240
  response_model=ProposalStrengthResponse,
241
  )
242
  self.router.add_api_route(
243
- "/proposal_strengths/all",
244
  self.update_all_proposal_strengths,
245
  methods=["PUT"],
246
- tags=["Proposal All Strengths"],
247
- response_model=ProposalStrengthResponse,
248
  )
249
  self.router.add_api_route(
250
- "/proposal_strengths",
251
  self.delete_proposal_strength,
252
  methods=["DELETE"],
253
- tags=["Proposal Strengths"],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  response_model=DeleteResponse,
255
  )
256
 
@@ -261,6 +289,27 @@ class ProposalAIController:
261
  tags=["Proposal Weakness"],
262
  response_model=ProposalWeaknessResponse,
263
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  self.router.add_api_route(
265
  "/proposal_weakness",
266
  self.create_proposal_weakness,
@@ -269,31 +318,45 @@ class ProposalAIController:
269
  response_model=ProposalWeaknessResponse,
270
  )
271
  self.router.add_api_route(
272
- "/proposal_weakness/all",
273
  self.create_all_proposal_weakness,
274
  methods=["POST"],
275
- tags=["Proposal All Weakness"],
276
- response_model=ProposalWeaknessResponse,
277
  )
278
  self.router.add_api_route(
279
- "/proposal_weakness",
280
  self.update_proposal_weakness,
281
  methods=["PUT"],
282
- tags=["Proposal Weakness"],
283
  response_model=ProposalWeaknessResponse,
284
  )
285
  self.router.add_api_route(
286
- "/proposal_weakness/all",
287
  self.update_all_proposal_weakness,
288
  methods=["PUT"],
289
- tags=["Proposal All Weakness"],
290
- response_model=ProposalWeaknessResponse,
291
  )
292
  self.router.add_api_route(
293
- "/proposal_weakness",
294
  self.delete_proposal_weakness,
295
  methods=["DELETE"],
296
- tags=["Proposal Weakness"],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  response_model=DeleteResponse,
298
  )
299
 
@@ -304,6 +367,27 @@ class ProposalAIController:
304
  tags=["Proposal Rejections"],
305
  response_model=ProposalRejectionReasonResponse,
306
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  self.router.add_api_route(
308
  "/proposal_rejections",
309
  self.create_proposal_rejections,
@@ -312,31 +396,45 @@ class ProposalAIController:
312
  response_model=ProposalRejectionReasonResponse,
313
  )
314
  self.router.add_api_route(
315
- "/proposal_rejections/all",
316
  self.create_all_proposal_rejections,
317
  methods=["POST"],
318
- tags=["Proposal All Rejections"],
319
- response_model=ProposalRejectionReasonResponse,
320
  )
321
  self.router.add_api_route(
322
- "/proposal_rejections",
323
  self.update_proposal_rejections,
324
  methods=["PUT"],
325
- tags=["Proposal Rejections"],
326
  response_model=ProposalRejectionReasonResponse,
327
  )
328
  self.router.add_api_route(
329
- "/proposal_rejections/all",
330
  self.update_all_proposal_rejections,
331
  methods=["PUT"],
332
- tags=["Proposal All Rejections"],
333
- response_model=ProposalRejectionReasonResponse,
334
  )
335
  self.router.add_api_route(
336
- "/proposal_rejections",
337
  self.delete_proposal_rejections,
338
  methods=["DELETE"],
339
- tags=["Proposal Rejections"],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
340
  response_model=DeleteResponse,
341
  )
342
 
@@ -347,6 +445,27 @@ class ProposalAIController:
347
  tags=["Proposal Improvements"],
348
  response_model=ProposalImprovementResponse,
349
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  self.router.add_api_route(
351
  "/proposal_improvements",
352
  self.create_proposal_improvements,
@@ -355,31 +474,45 @@ class ProposalAIController:
355
  response_model=ProposalImprovementResponse,
356
  )
357
  self.router.add_api_route(
358
- "/proposal_improvements/all",
359
  self.create_all_proposal_improvements,
360
  methods=["POST"],
361
- tags=["Proposal All Improvements"],
362
- response_model=ProposalImprovementResponse,
363
  )
364
  self.router.add_api_route(
365
- "/proposal_improvements",
366
  self.update_proposal_improvements,
367
  methods=["PUT"],
368
- tags=["Proposal Improvements"],
369
  response_model=ProposalImprovementResponse,
370
  )
371
  self.router.add_api_route(
372
- "/proposal_improvements/all",
373
  self.update_all_proposal_improvements,
374
  methods=["PUT"],
375
- tags=["Proposal All Improvements"],
376
- response_model=ProposalImprovementResponse,
377
  )
378
  self.router.add_api_route(
379
- "/proposal_improvements",
380
  self.delete_proposal_improvements,
381
  methods=["DELETE"],
382
- tags=["Proposal Improvements"],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
  response_model=DeleteResponse,
384
  )
385
 
@@ -390,6 +523,27 @@ class ProposalAIController:
390
  tags=["Proposal AI Score"],
391
  response_model=ProposalAIAnalysisResponse,
392
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  self.router.add_api_route(
394
  "/proposal_ai_score",
395
  self.create_proposal_ai_score,
@@ -398,43 +552,71 @@ class ProposalAIController:
398
  response_model=ProposalAIAnalysisResponse,
399
  )
400
  self.router.add_api_route(
401
- "/proposal_ai_score",
 
 
 
 
 
 
 
402
  self.update_proposal_ai_score,
403
  methods=["PUT"],
404
- tags=["Proposal AI Score"],
405
  response_model=ProposalAIAnalysisResponse,
406
  )
407
  self.router.add_api_route(
408
- "/proposal_ai_score",
 
 
 
 
 
 
 
409
  self.delete_proposal_ai_score,
410
  methods=["DELETE"],
411
- tags=["Proposal AI Score"],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
  response_model=DeleteResponse,
413
  )
414
 
415
  self.router.add_api_route(
416
- "/proposal_analysis",
417
  self.get_all_proposal_analysis,
418
  methods=["GET"],
419
  tags=["Proposal Complete Analysis"],
420
  response_model=ProposalCompleteAnalysisResponse,
421
  )
422
  self.router.add_api_route(
423
- "/proposal_analysis",
424
  self.create_proposal_analysis,
425
  methods=["POST"],
426
  tags=["Proposal Complete Analysis"],
427
  response_model=ProposalCompleteAnalysisResponse,
428
  )
429
  self.router.add_api_route(
430
- "/proposal_analysis",
431
  self.update_proposal_analysis,
432
  methods=["PUT"],
433
  tags=["Proposal Complete Analysis"],
434
  response_model=ProposalCompleteAnalysisResponse,
435
  )
436
  self.router.add_api_route(
437
- "/proposal_analysis",
438
  self.delete_proposal_analysis,
439
  methods=["DELETE"],
440
  tags=["Proposal Complete Analysis"],
@@ -442,14 +624,12 @@ class ProposalAIController:
442
  )
443
 
444
  async def get_proposal_strengths(
445
- self, proposal_strength_id: str = Query(None), proposal_id: UUID = Query(None)
446
  ):
447
  async with self.__service() as service:
448
  try:
449
  strengths = await service.get_all_data(
450
- query_type=QueryType.STRENGTHS,
451
- id=proposal_strength_id,
452
- proposal_id=proposal_id,
453
  )
454
  return ProposalStrengthResponse(
455
  status="success", data=[ProposalStrength(**s) for s in strengths]
@@ -459,6 +639,51 @@ class ProposalAIController:
459
  raise HTTPException(
460
  status_code=500, detail="Failed to retrieve strengths."
461
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
 
463
  async def create_proposal_strengths(self, strength: ProposalStrengthRequest):
464
  async with self.__service() as service:
@@ -478,17 +703,19 @@ class ProposalAIController:
478
  )
479
 
480
  async def create_all_proposal_strengths(
481
- self, strengths: CreateAllProposalStrengthsRequest
482
  ):
483
  async with self.__service() as service:
484
  try:
 
 
485
  created = await service.create_data(
486
  query_type=QueryType.STRENGTHS,
487
  create_or_update_type=CreateOrUpdateType.ALL,
488
- data=strengths.model_dump(mode="json"),
489
  )
490
- return ProposalStrengthResponse(
491
- status="success", data=[ProposalStrength(**s) for s in created]
492
  )
493
  except Exception as e:
494
  logger.exception(e)
@@ -496,13 +723,15 @@ class ProposalAIController:
496
  status_code=500, detail="Failed to create strengths."
497
  )
498
 
499
- async def update_proposal_strengths(self, strength: UpdateProposalStrengthRequest):
500
  async with self.__service() as service:
501
  try:
 
 
502
  updated = await service.update_data(
503
  query_type=QueryType.STRENGTHS,
504
  create_or_update_type=CreateOrUpdateType.ID,
505
- data=strength.model_dump(mode="json", exclude_unset=True),
506
  )
507
  return ProposalStrengthResponse(
508
  status="success", data=[ProposalStrength(**s) for s in updated]
@@ -514,17 +743,19 @@ class ProposalAIController:
514
  )
515
 
516
  async def update_all_proposal_strengths(
517
- self, strengths: CreateAllProposalStrengthsRequest
518
  ):
519
  async with self.__service() as service:
520
  try:
 
 
521
  updated = await service.update_data(
522
  query_type=QueryType.STRENGTHS,
523
  create_or_update_type=CreateOrUpdateType.ALL,
524
- data=strengths.model_dump(mode="json", exclude_unset=True),
525
  )
526
- return ProposalStrengthResponse(
527
- status="success", data=[ProposalStrength(**s) for s in updated]
528
  )
529
  except Exception as e:
530
  logger.exception(e)
@@ -533,17 +764,38 @@ class ProposalAIController:
533
  )
534
 
535
  async def delete_proposal_strength(
536
- self, id: UUID = Query(None), proposal_id: UUID = Query(None)
537
  ):
538
  async with self.__service() as service:
539
  try:
540
- if not id and not proposal_id:
541
- raise HTTPException(
542
- status_code=400,
543
- detail="Either id or proposal_id must be provided.",
544
- )
545
  result = await service.delete_data(
546
- query_type=QueryType.STRENGTHS, id=id, proposal_id=proposal_id
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
  )
548
  return DeleteResponse(status="success")
549
  except Exception as e:
@@ -553,14 +805,12 @@ class ProposalAIController:
553
  )
554
 
555
  async def get_proposal_weakness(
556
- self, proposal_weakness_id: str = Query(None), proposal_id: UUID = Query(None)
557
  ):
558
  async with self.__service() as service:
559
  try:
560
  weaknesses = await service.get_all_data(
561
- query_type=QueryType.WEAKNESSES,
562
- id=proposal_weakness_id,
563
- proposal_id=proposal_id,
564
  )
565
  return ProposalWeaknessResponse(
566
  status="success", data=[ProposalWeakness(**w) for w in weaknesses]
@@ -570,6 +820,51 @@ class ProposalAIController:
570
  raise HTTPException(
571
  status_code=500, detail="Failed to retrieve weaknesses."
572
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
573
 
574
  async def create_proposal_weakness(self, weakness: ProposalWeaknessRequest):
575
  async with self.__service() as service:
@@ -589,17 +884,19 @@ class ProposalAIController:
589
  )
590
 
591
  async def create_all_proposal_weakness(
592
- self, weaknesses: CreateAllProposalWeaknessRequest
593
  ):
594
  async with self.__service() as service:
595
  try:
 
 
596
  created = await service.create_data(
597
  query_type=QueryType.WEAKNESSES,
598
  create_or_update_type=CreateOrUpdateType.ALL,
599
- data=weaknesses.model_dump(mode="json"),
600
  )
601
- return ProposalWeaknessResponse(
602
- status="success", data=[ProposalWeakness(**w) for w in created]
603
  )
604
  except Exception as e:
605
  logger.exception(e)
@@ -607,13 +904,15 @@ class ProposalAIController:
607
  status_code=500, detail="Failed to create weaknesses."
608
  )
609
 
610
- async def update_proposal_weakness(self, weakness: UpdateProposalWeaknessRequest):
611
  async with self.__service() as service:
612
  try:
 
 
613
  updated = await service.update_data(
614
  query_type=QueryType.WEAKNESSES,
615
  create_or_update_type=CreateOrUpdateType.ID,
616
- data=weakness.model_dump(mode="json", exclude_unset=True),
617
  )
618
  return ProposalWeaknessResponse(
619
  status="success", data=[ProposalWeakness(**w) for w in updated]
@@ -625,17 +924,19 @@ class ProposalAIController:
625
  )
626
 
627
  async def update_all_proposal_weakness(
628
- self, weaknesses: CreateAllProposalWeaknessRequest
629
  ):
630
  async with self.__service() as service:
631
  try:
 
 
632
  updated = await service.update_data(
633
  query_type=QueryType.WEAKNESSES,
634
  create_or_update_type=CreateOrUpdateType.ALL,
635
- data=weaknesses.model_dump(mode="json", exclude_unset=True),
636
  )
637
- return ProposalWeaknessResponse(
638
- status="success", data=[ProposalWeakness(**w) for w in updated]
639
  )
640
  except Exception as e:
641
  logger.exception(e)
@@ -644,12 +945,40 @@ class ProposalAIController:
644
  )
645
 
646
  async def delete_proposal_weakness(
647
- self, id: UUID = Query(None), proposal_id: UUID = Query(None)
648
  ):
649
  async with self.__service() as service:
650
  try:
651
  result = await service.delete_data(
652
- query_type=QueryType.WEAKNESSES, id=id, proposal_id=proposal_id
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
653
  )
654
  return DeleteResponse(status="success")
655
  except Exception as e:
@@ -659,14 +988,12 @@ class ProposalAIController:
659
  )
660
 
661
  async def get_proposal_rejections(
662
- self, id: UUID = Query(None), proposal_id: UUID = Query(None)
663
  ):
664
  async with self.__service() as service:
665
  try:
666
  rejection_reasons = await service.get_all_data(
667
- query_type=QueryType.REJECTION_REASONS,
668
- id=id,
669
- proposal_id=proposal_id,
670
  )
671
  return ProposalRejectionReasonResponse(
672
  status="success",
@@ -677,6 +1004,51 @@ class ProposalAIController:
677
  raise HTTPException(
678
  status_code=500, detail="Failed to retrieve rejection reasons."
679
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
680
 
681
  async def create_proposal_rejections(
682
  self, rejection_reason: ProposalRejectionReasonRequest
@@ -699,18 +1071,20 @@ class ProposalAIController:
699
  )
700
 
701
  async def create_all_proposal_rejections(
702
- self, rejection_reasons: CreateAllProposalRejectionReasonsRequest
703
  ):
704
  async with self.__service() as service:
705
  try:
 
 
706
  created = await service.create_data(
707
  query_type=QueryType.REJECTION_REASONS,
708
  create_or_update_type=CreateOrUpdateType.ALL,
709
- data=rejection_reasons.model_dump(mode="json"),
710
  )
711
- return ProposalRejectionReasonResponse(
712
  status="success",
713
- data=[ProposalRejectionReason(**r) for r in created],
714
  )
715
  except Exception as e:
716
  logger.exception(e)
@@ -719,14 +1093,16 @@ class ProposalAIController:
719
  )
720
 
721
  async def update_proposal_rejections(
722
- self, rejection_reason: UpdateProposalRejectionReasonRequest
723
  ):
724
  async with self.__service() as service:
725
  try:
 
 
726
  updated = await service.update_data(
727
  query_type=QueryType.REJECTION_REASONS,
728
  create_or_update_type=CreateOrUpdateType.ID,
729
- data=rejection_reason.model_dump(mode="json", exclude_unset=True),
730
  )
731
  return ProposalRejectionReasonResponse(
732
  status="success",
@@ -739,18 +1115,20 @@ class ProposalAIController:
739
  )
740
 
741
  async def update_all_proposal_rejections(
742
- self, rejection_reasons: CreateAllProposalRejectionReasonsRequest
743
  ):
744
  async with self.__service() as service:
745
  try:
 
 
746
  updated = await service.update_data(
747
  query_type=QueryType.REJECTION_REASONS,
748
  create_or_update_type=CreateOrUpdateType.ALL,
749
- data=rejection_reasons.model_dump(mode="json", exclude_unset=True),
750
  )
751
- return ProposalRejectionReasonResponse(
752
  status="success",
753
- data=[ProposalRejectionReason(**r) for r in updated],
754
  )
755
  except Exception as e:
756
  logger.exception(e)
@@ -759,19 +1137,46 @@ class ProposalAIController:
759
  )
760
 
761
  async def delete_proposal_rejections(
762
- self, id: UUID = Query(None), proposal_id: UUID = Query(None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
763
  ):
764
  async with self.__service() as service:
765
  try:
766
- if not id and not proposal_id:
767
- raise HTTPException(
768
- status_code=400,
769
- detail="Either id or proposal_id must be provided.",
770
- )
771
  result = await service.delete_data(
772
  query_type=QueryType.REJECTION_REASONS,
773
  id=id,
774
- proposal_id=proposal_id,
775
  )
776
  return DeleteResponse(status="success")
777
  except Exception as e:
@@ -781,12 +1186,70 @@ class ProposalAIController:
781
  )
782
 
783
  async def get_proposal_improvements(
784
- self, id: UUID = Query(None), proposal_id: UUID = Query(None)
785
  ):
786
  async with self.__service() as service:
787
  try:
788
  improvements = await service.get_all_data(
789
- query_type=QueryType.IMPROVEMENTS, id=id, proposal_id=proposal_id
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
790
  )
791
  return ProposalImprovementResponse(
792
  status="success",
@@ -818,17 +1281,19 @@ class ProposalAIController:
818
  )
819
 
820
  async def create_all_proposal_improvements(
821
- self, improvements: CreateAllProposalImprovementsRequest
822
  ):
823
  async with self.__service() as service:
824
  try:
 
 
825
  created = await service.create_data(
826
  query_type=QueryType.IMPROVEMENTS,
827
  create_or_update_type=CreateOrUpdateType.ALL,
828
- data=improvements.model_dump(mode="json"),
829
  )
830
- return ProposalImprovementResponse(
831
- status="success", data=[ProposalImprovement(**r) for r in created]
832
  )
833
  except Exception as e:
834
  logger.exception(e)
@@ -837,14 +1302,16 @@ class ProposalAIController:
837
  )
838
 
839
  async def update_proposal_improvements(
840
- self, improvement: UpdateProposalImprovementRequest
841
  ):
842
  async with self.__service() as service:
843
  try:
 
 
844
  updated = await service.update_data(
845
  query_type=QueryType.IMPROVEMENTS,
846
  create_or_update_type=CreateOrUpdateType.ID,
847
- data=improvement.model_dump(mode="json", exclude_unset=True),
848
  )
849
  return ProposalImprovementResponse(
850
  status="success", data=[ProposalImprovement(**r) for r in updated]
@@ -856,17 +1323,19 @@ class ProposalAIController:
856
  )
857
 
858
  async def update_all_proposal_improvements(
859
- self, improvements: CreateAllProposalImprovementsRequest
860
  ):
861
  async with self.__service() as service:
862
  try:
 
 
863
  updated = await service.update_data(
864
  query_type=QueryType.IMPROVEMENTS,
865
  create_or_update_type=CreateOrUpdateType.ALL,
866
- data=improvements.model_dump(mode="json", exclude_unset=True),
867
  )
868
- return ProposalImprovementResponse(
869
- status="success", data=[ProposalImprovement(**r) for r in updated]
870
  )
871
  except Exception as e:
872
  logger.exception(e)
@@ -875,15 +1344,40 @@ class ProposalAIController:
875
  )
876
 
877
  async def delete_proposal_improvements(
878
- self, id: UUID = Query(None), proposal_id: UUID = Query(None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
879
  ):
880
  async with self.__service() as service:
881
  try:
882
- if not id and not proposal_id:
883
- raise HTTPException(
884
- status_code=400,
885
- detail="Either id or proposal_id must be provided.",
886
- )
887
  result = await service.delete_data(
888
  query_type=QueryType.IMPROVEMENTS, id=id, proposal_id=proposal_id
889
  )
@@ -895,7 +1389,58 @@ class ProposalAIController:
895
  )
896
 
897
  async def get_proposal_ai_score(
898
- self, id: UUID = Query(None), proposal_id: UUID = Query(None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
899
  ):
900
  async with self.__service() as service:
901
  try:
@@ -927,25 +1472,36 @@ class ProposalAIController:
927
  raise HTTPException(
928
  status_code=500, detail="Failed to create AI score."
929
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
930
 
931
- async def update_proposal_ai_score(self, score: UpdateAiAnalysisRequest):
932
- if not score.id and not score.proposal_id:
933
- raise HTTPException(
934
- status_code=400, detail="Either 'id' or 'proposal_id' must be provided."
935
- )
936
  async with self.__service() as service:
937
  try:
938
- if score.id:
 
 
939
  updated = await service.update_data(
940
  query_type=QueryType.AI_SCORE,
941
  create_or_update_type=CreateOrUpdateType.ID,
942
- data=score.model_dump(mode="json", exclude_unset=True),
943
- )
944
- elif score.proposal_id:
945
- updated = await service.update_data(
946
- query_type=QueryType.AI_SCORE,
947
- create_or_update_type=CreateOrUpdateType.ALL,
948
- data=score.model_dump(mode="json", exclude_unset=True),
949
  )
950
  return ProposalAIAnalysisResponse(
951
  status="success", data=[ProposalAIAnalysis(**r) for r in updated]
@@ -955,17 +1511,61 @@ class ProposalAIController:
955
  raise HTTPException(
956
  status_code=500, detail="Failed to update AI score."
957
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
958
 
959
  async def delete_proposal_ai_score(
960
- self, id: UUID = Query(None), proposal_id: UUID = Query(None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
961
  ):
962
  async with self.__service() as service:
963
  try:
964
- if not id and not proposal_id:
965
- raise HTTPException(
966
- status_code=400,
967
- detail="Either id or proposal_id must be provided.",
968
- )
969
  result = await service.delete_data(
970
  query_type=QueryType.AI_SCORE, id=id, proposal_id=proposal_id
971
  )
@@ -976,7 +1576,7 @@ class ProposalAIController:
976
  status_code=500, detail="Failed to delete AI score."
977
  )
978
 
979
- async def get_all_proposal_analysis(self, proposal_id: UUID = Query(...)):
980
  async with self.__service() as service:
981
  try:
982
  analysis = await service.get_all_data(
@@ -993,14 +1593,16 @@ class ProposalAIController:
993
  )
994
 
995
  async def create_proposal_analysis(
996
- self, analysis: CreateAllProposalAnalysisRequest
997
  ):
998
  async with self.__service() as service:
999
  try:
 
 
1000
  created = await service.create_data(
1001
  query_type=QueryType.ALL,
1002
  create_or_update_type=CreateOrUpdateType.ALL,
1003
- data=analysis.model_dump(mode="json", exclude_unset=True),
1004
  )
1005
  return ProposalCompleteAnalysisResponse(
1006
  status="success",
@@ -1013,14 +1615,16 @@ class ProposalAIController:
1013
  )
1014
 
1015
  async def update_proposal_analysis(
1016
- self, analysis: UpdateAllProposalAnalysisRequest
1017
  ):
1018
  async with self.__service() as service:
1019
  try:
 
 
1020
  updated = await service.update_data(
1021
  query_type=QueryType.ALL,
1022
  create_or_update_type=CreateOrUpdateType.ALL,
1023
- data=analysis.model_dump(mode="json", exclude_unset=True),
1024
  )
1025
  return ProposalCompleteAnalysisResponse(
1026
  status="success",
@@ -1032,11 +1636,11 @@ class ProposalAIController:
1032
  status_code=500, detail="Failed to update analysis."
1033
  )
1034
 
1035
- async def delete_proposal_analysis(self, id: UUID = Query(...)):
1036
  async with self.__service() as service:
1037
  try:
1038
  result = await service.delete_data(
1039
- query_type=QueryType.ALL, proposal_id=id
1040
  )
1041
  return DeleteResponse(status="success")
1042
  except Exception as e:
 
1
+ from fastapi import APIRouter, HTTPException, Query, Path
2
  from pydantic import BaseModel
3
  from typing import List, Optional
4
  from uuid import UUID
 
119
 
120
 
121
  class UpdateProposalStrengthRequest(BaseModel):
 
122
  proposal_id: Optional[UUID] = None
123
  strength_point: Optional[str] = None
124
 
 
129
 
130
 
131
  class UpdateProposalWeaknessRequest(BaseModel):
 
132
  proposal_id: Optional[UUID] = None
133
  weakness_point: Optional[str] = None
134
 
 
139
 
140
 
141
  class UpdateProposalRejectionReasonRequest(BaseModel):
 
142
  proposal_id: Optional[UUID] = None
143
  reason: Optional[str] = None
144
 
 
149
 
150
 
151
  class UpdateProposalImprovementRequest(BaseModel):
 
152
  proposal_id: Optional[UUID] = None
153
  improvement_point: Optional[str] = None
154
 
 
157
  proposal_id: UUID
158
  ai_score: float
159
 
160
+ class CreateAIAnalysisRequestByProposalId(BaseModel):
161
+ ai_score: float
162
 
163
  class UpdateAiAnalysisRequest(BaseModel):
 
164
  proposal_id: Optional[UUID] = None
165
  ai_score: Optional[float] = None
166
 
167
+ class UpdateAIAnalysisRequestByProposalId(BaseModel):
168
+ ai_score: Optional[float] = None
169
 
170
  class CreateAllProposalStrengthsRequest(BaseModel):
 
171
  strength_point: List[str]
172
 
173
 
174
  class CreateAllProposalWeaknessRequest(BaseModel):
 
175
  weakness_point: List[str]
176
 
177
 
178
  class CreateAllProposalRejectionReasonsRequest(BaseModel):
 
179
  reason: List[str]
180
 
181
 
182
  class CreateAllProposalImprovementsRequest(BaseModel):
 
183
  improvement_point: List[str]
184
 
185
 
186
  class CreateAllProposalAnalysisRequest(BaseModel):
 
187
  ai_score: float
188
  strengths: Optional[List[str]] = None
189
  weaknesses: Optional[List[str]] = None
 
192
 
193
 
194
  class UpdateAllProposalAnalysisRequest(BaseModel):
 
195
  ai_score: Optional[float] = None
196
  strengths: Optional[List[str]] = None
197
  weaknesses: Optional[List[str]] = None
 
211
  tags=["Proposal Strengths"],
212
  response_model=ProposalStrengthResponse,
213
  )
214
+ self.router.add_api_route(
215
+ "/proposal_strengths/{id}",
216
+ self.get_proposal_strengths_by_id,
217
+ methods=["GET"],
218
+ tags=["Proposal Strengths by ID"],
219
+ response_model=ProposalStrengthResponse,
220
+ )
221
+ self.router.add_api_route(
222
+ "/proposals/{proposal_id}/proposal_strengths",
223
+ self.get_proposal_strengths_by_proposal_id,
224
+ methods=["GET"],
225
+ tags=["Proposal Strengths by Proposal ID"],
226
+ response_model=ProposalAllStrengthsResponse,
227
+ )
228
+ self.router.add_api_route(
229
+ "/proposals/{proposal_id}/proposal_strengths/{id}",
230
+ self.get_proposal_strengths_by_proposal_and_id,
231
+ methods=["GET"],
232
+ tags=["Proposal Strengths by Proposal and ID"],
233
+ response_model=ProposalStrengthResponse,
234
+ )
235
  self.router.add_api_route(
236
  "/proposal_strengths",
237
  self.create_proposal_strengths,
 
240
  response_model=ProposalStrengthResponse,
241
  )
242
  self.router.add_api_route(
243
+ "/proposals/{proposal_id}/proposal_strengths",
244
  self.create_all_proposal_strengths,
245
  methods=["POST"],
246
+ tags=["Proposal Strengths by Proposal ID"],
247
+ response_model=ProposalAllStrengthsResponse,
248
  )
249
  self.router.add_api_route(
250
+ "/proposal_strengths/{id}",
251
  self.update_proposal_strengths,
252
  methods=["PUT"],
253
+ tags=["Proposal Strengths by ID"],
254
  response_model=ProposalStrengthResponse,
255
  )
256
  self.router.add_api_route(
257
+ "/proposals/{proposal_id}/proposal_strengths",
258
  self.update_all_proposal_strengths,
259
  methods=["PUT"],
260
+ tags=["Proposal Strengths by Proposal ID"],
261
+ response_model=ProposalAllStrengthsResponse,
262
  )
263
  self.router.add_api_route(
264
+ "/proposal_strengths/{id}",
265
  self.delete_proposal_strength,
266
  methods=["DELETE"],
267
+ tags=["Proposal Strengths by ID"],
268
+ response_model=DeleteResponse,
269
+ )
270
+ self.router.add_api_route(
271
+ "/proposals/{proposal_id}/proposal_strengths",
272
+ self.delete_all_proposal_strengths,
273
+ methods=["DELETE"],
274
+ tags=["Proposal Strengths by Proposal ID"],
275
+ response_model=DeleteResponse,
276
+ )
277
+ self.router.add_api_route(
278
+ "/proposals/{proposal_id}/proposal_strengths/{id}",
279
+ self.delete_proposal_strengths_by_proposal_and_id,
280
+ methods=["DELETE"],
281
+ tags=["Proposal Strengths by Proposal and ID"],
282
  response_model=DeleteResponse,
283
  )
284
 
 
289
  tags=["Proposal Weakness"],
290
  response_model=ProposalWeaknessResponse,
291
  )
292
+ self.router.add_api_route(
293
+ "/proposal_weakness/{id}",
294
+ self.get_proposal_weakness_by_id,
295
+ methods=["GET"],
296
+ tags=["Proposal Weakness by ID"],
297
+ response_model=ProposalWeaknessResponse,
298
+ )
299
+ self.router.add_api_route(
300
+ "/proposals/{proposal_id}/proposal_weakness",
301
+ self.get_proposal_weakness_by_proposal_id,
302
+ methods=["GET"],
303
+ tags=["Proposal Weakness by Proposal ID"],
304
+ response_model=ProposalAllWeaknessesResponse,
305
+ )
306
+ self.router.add_api_route(
307
+ "/proposals/{proposal_id}/proposal_weakness/{id}",
308
+ self.get_proposal_weakness_by_proposal_and_id,
309
+ methods=["GET"],
310
+ tags=["Proposal Weakness by Proposal and ID"],
311
+ response_model=ProposalWeaknessResponse,
312
+ )
313
  self.router.add_api_route(
314
  "/proposal_weakness",
315
  self.create_proposal_weakness,
 
318
  response_model=ProposalWeaknessResponse,
319
  )
320
  self.router.add_api_route(
321
+ "/proposals/{proposal_id}/proposal_weakness",
322
  self.create_all_proposal_weakness,
323
  methods=["POST"],
324
+ tags=["Proposal Weakness by Proposal ID"],
325
+ response_model=ProposalAllWeaknessesResponse,
326
  )
327
  self.router.add_api_route(
328
+ "/proposal_weakness/{id}",
329
  self.update_proposal_weakness,
330
  methods=["PUT"],
331
+ tags=["Proposal Weakness by ID"],
332
  response_model=ProposalWeaknessResponse,
333
  )
334
  self.router.add_api_route(
335
+ "/proposals/{proposal_id}/proposal_weakness",
336
  self.update_all_proposal_weakness,
337
  methods=["PUT"],
338
+ tags=["Proposal Weakness by Proposal ID"],
339
+ response_model=ProposalAllWeaknessesResponse,
340
  )
341
  self.router.add_api_route(
342
+ "/proposal_weakness/{id}",
343
  self.delete_proposal_weakness,
344
  methods=["DELETE"],
345
+ tags=["Proposal Weakness by ID"],
346
+ response_model=DeleteResponse,
347
+ )
348
+ self.router.add_api_route(
349
+ "/proposals/{proposal_id}/proposal_weakness",
350
+ self.delete_all_proposal_weakness,
351
+ methods=["DELETE"],
352
+ tags=["Proposal Weakness by Proposal ID"],
353
+ response_model=DeleteResponse,
354
+ )
355
+ self.router.add_api_route(
356
+ "/proposals/{proposal_id}/proposal_weakness/{id}",
357
+ self.delete_proposal_weakness_by_proposal_and_id,
358
+ methods=["DELETE"],
359
+ tags=["Proposal Weakness by Proposal and ID"],
360
  response_model=DeleteResponse,
361
  )
362
 
 
367
  tags=["Proposal Rejections"],
368
  response_model=ProposalRejectionReasonResponse,
369
  )
370
+ self.router.add_api_route(
371
+ "/proposal_rejections/{id}",
372
+ self.get_proposal_rejections_by_id,
373
+ methods=["GET"],
374
+ tags=["Proposal Rejections by ID"],
375
+ response_model=ProposalRejectionReasonResponse,
376
+ )
377
+ self.router.add_api_route(
378
+ "/proposals/{proposal_id}/proposal_rejections",
379
+ self.get_proposal_rejections_by_proposal_id,
380
+ methods=["GET"],
381
+ tags=["Proposal Rejections by Proposal ID"],
382
+ response_model=ProposalAllRejectionReasonsResponse,
383
+ )
384
+ self.router.add_api_route(
385
+ "/proposals/{proposal_id}/proposal_rejections/{id}",
386
+ self.get_proposal_rejections_by_proposal_and_id,
387
+ methods=["GET"],
388
+ tags=["Proposal Rejections by Proposal and ID"],
389
+ response_model=ProposalRejectionReasonResponse,
390
+ )
391
  self.router.add_api_route(
392
  "/proposal_rejections",
393
  self.create_proposal_rejections,
 
396
  response_model=ProposalRejectionReasonResponse,
397
  )
398
  self.router.add_api_route(
399
+ "/proposals/{proposal_id}/proposal_rejections",
400
  self.create_all_proposal_rejections,
401
  methods=["POST"],
402
+ tags=["Proposal Rejections by Proposal ID"],
403
+ response_model=ProposalAllRejectionReasonsResponse,
404
  )
405
  self.router.add_api_route(
406
+ "/proposal_rejections/{id}",
407
  self.update_proposal_rejections,
408
  methods=["PUT"],
409
+ tags=["Proposal Rejections by ID"],
410
  response_model=ProposalRejectionReasonResponse,
411
  )
412
  self.router.add_api_route(
413
+ "/proposals/{proposal_id}/proposal_rejections",
414
  self.update_all_proposal_rejections,
415
  methods=["PUT"],
416
+ tags=["Proposal Rejections by Proposal ID"],
417
+ response_model=ProposalAllRejectionReasonsResponse,
418
  )
419
  self.router.add_api_route(
420
+ "/proposal_rejections/{id}",
421
  self.delete_proposal_rejections,
422
  methods=["DELETE"],
423
+ tags=["Proposal Rejections by ID"],
424
+ response_model=DeleteResponse,
425
+ )
426
+ self.router.add_api_route(
427
+ "/proposals/{proposal_id}/proposal_rejections",
428
+ self.delete_all_proposal_rejections,
429
+ methods=["DELETE"],
430
+ tags=["Proposal Rejections by Proposal ID"],
431
+ response_model=DeleteResponse,
432
+ )
433
+ self.router.add_api_route(
434
+ "/proposals/{proposal_id}/proposal_rejections/{id}",
435
+ self.delete_proposal_rejections_by_proposal_and_id,
436
+ methods=["DELETE"],
437
+ tags=["Proposal Rejections by Proposal and ID"],
438
  response_model=DeleteResponse,
439
  )
440
 
 
445
  tags=["Proposal Improvements"],
446
  response_model=ProposalImprovementResponse,
447
  )
448
+ self.router.add_api_route(
449
+ "/proposal_improvements/{id}",
450
+ self.get_proposal_improvements_by_id,
451
+ methods=["GET"],
452
+ tags=["Proposal Improvements by ID"],
453
+ response_model=ProposalImprovementResponse,
454
+ )
455
+ self.router.add_api_route(
456
+ "/proposals/{proposal_id}/proposal_improvements",
457
+ self.get_proposal_improvements_by_proposal_id,
458
+ methods=["GET"],
459
+ tags=["Proposal Improvements by Proposal ID"],
460
+ response_model=ProposalAllImprovementsResponse,
461
+ )
462
+ self.router.add_api_route(
463
+ "/proposals/{proposal_id}/proposal_improvements/{id}",
464
+ self.get_proposal_improvements_by_proposal_and_id,
465
+ methods=["GET"],
466
+ tags=["Proposal Improvements by Proposal and ID"],
467
+ response_model=ProposalImprovementResponse,
468
+ )
469
  self.router.add_api_route(
470
  "/proposal_improvements",
471
  self.create_proposal_improvements,
 
474
  response_model=ProposalImprovementResponse,
475
  )
476
  self.router.add_api_route(
477
+ "/proposals/{proposal_id}/proposal_improvements",
478
  self.create_all_proposal_improvements,
479
  methods=["POST"],
480
+ tags=["Proposal Improvements by Proposal ID"],
481
+ response_model=ProposalAllImprovementsResponse,
482
  )
483
  self.router.add_api_route(
484
+ "/proposal_improvements/{id}",
485
  self.update_proposal_improvements,
486
  methods=["PUT"],
487
+ tags=["Proposal Improvements by ID"],
488
  response_model=ProposalImprovementResponse,
489
  )
490
  self.router.add_api_route(
491
+ "/proposals/{proposal_id}/proposal_improvements",
492
  self.update_all_proposal_improvements,
493
  methods=["PUT"],
494
+ tags=["Proposal Improvements by Proposal ID"],
495
+ response_model=ProposalAllImprovementsResponse,
496
  )
497
  self.router.add_api_route(
498
+ "/proposal_improvements/{id}",
499
  self.delete_proposal_improvements,
500
  methods=["DELETE"],
501
+ tags=["Proposal Improvements by ID"],
502
+ response_model=DeleteResponse,
503
+ )
504
+ self.router.add_api_route(
505
+ "/proposals/{proposal_id}/proposal_improvements",
506
+ self.delete_all_proposal_improvements,
507
+ methods=["DELETE"],
508
+ tags=["Proposal Improvements by Proposal ID"],
509
+ response_model=DeleteResponse,
510
+ )
511
+ self.router.add_api_route(
512
+ "/proposals/{proposal_id}/proposal_improvements/{id}",
513
+ self.delete_proposal_improvements_by_proposal_and_id,
514
+ methods=["DELETE"],
515
+ tags=["Proposal Improvements by Proposal and ID"],
516
  response_model=DeleteResponse,
517
  )
518
 
 
523
  tags=["Proposal AI Score"],
524
  response_model=ProposalAIAnalysisResponse,
525
  )
526
+ self.router.add_api_route(
527
+ "/proposal_ai_score/{id}",
528
+ self.get_proposal_ai_score_by_id,
529
+ methods=["GET"],
530
+ tags=["Proposal AI Score by ID"],
531
+ response_model=ProposalAIAnalysisResponse,
532
+ )
533
+ self.router.add_api_route(
534
+ "/proposals/{proposal_id}/proposal_ai_score",
535
+ self.get_proposal_ai_score_by_proposal_id,
536
+ methods=["GET"],
537
+ tags=["Proposal AI Score by Proposal ID"],
538
+ response_model=ProposalAIAnalysisResponse,
539
+ )
540
+ self.router.add_api_route(
541
+ "/proposals/{proposal_id}/proposal_ai_score/{id}",
542
+ self.get_proposal_ai_score_by_proposal_and_id,
543
+ methods=["GET"],
544
+ tags=["Proposal AI Score by Proposal and ID"],
545
+ response_model=ProposalAIAnalysisResponse,
546
+ )
547
  self.router.add_api_route(
548
  "/proposal_ai_score",
549
  self.create_proposal_ai_score,
 
552
  response_model=ProposalAIAnalysisResponse,
553
  )
554
  self.router.add_api_route(
555
+ "/proposals/{proposal_id}/proposal_ai_score",
556
+ self.create_proposal_ai_score_by_proposal_id,
557
+ methods=["POST"],
558
+ tags=["Proposal AI Score by Proposal ID"],
559
+ response_model=ProposalAIAnalysisResponse,
560
+ )
561
+ self.router.add_api_route(
562
+ "/proposal_ai_score/{id}",
563
  self.update_proposal_ai_score,
564
  methods=["PUT"],
565
+ tags=["Proposal AI Score by ID"],
566
  response_model=ProposalAIAnalysisResponse,
567
  )
568
  self.router.add_api_route(
569
+ "/proposals/{proposal_id}/proposal_ai_score",
570
+ self.update_proposal_ai_score_by_proposal_id,
571
+ methods=["PUT"],
572
+ tags=["Proposal AI Score by Proposal ID"],
573
+ response_model=ProposalAIAnalysisResponse,
574
+ )
575
+ self.router.add_api_route(
576
+ "/proposal_ai_score/{id}",
577
  self.delete_proposal_ai_score,
578
  methods=["DELETE"],
579
+ tags=["Proposal AI Score by ID"],
580
+ response_model=DeleteResponse,
581
+ )
582
+ self.router.add_api_route(
583
+ "/proposals/{proposal_id}/proposal_ai_score",
584
+ self.delete_proposal_ai_score_by_proposal_id,
585
+ methods=["DELETE"],
586
+ tags=["Proposal AI Score by Proposal ID"],
587
+ response_model=DeleteResponse,
588
+ )
589
+ self.router.add_api_route(
590
+ "/proposals/{proposal_id}/proposal_ai_score/{id}",
591
+ self.delete_proposal_ai_score_by_proposal_and_id,
592
+ methods=["DELETE"],
593
+ tags=["Proposal AI Score by Proposal and ID"],
594
  response_model=DeleteResponse,
595
  )
596
 
597
  self.router.add_api_route(
598
+ "/proposals/{proposal_id}/proposal_analysis",
599
  self.get_all_proposal_analysis,
600
  methods=["GET"],
601
  tags=["Proposal Complete Analysis"],
602
  response_model=ProposalCompleteAnalysisResponse,
603
  )
604
  self.router.add_api_route(
605
+ "/proposals/{proposal_id}/proposal_analysis",
606
  self.create_proposal_analysis,
607
  methods=["POST"],
608
  tags=["Proposal Complete Analysis"],
609
  response_model=ProposalCompleteAnalysisResponse,
610
  )
611
  self.router.add_api_route(
612
+ "/proposals/{proposal_id}/proposal_analysis",
613
  self.update_proposal_analysis,
614
  methods=["PUT"],
615
  tags=["Proposal Complete Analysis"],
616
  response_model=ProposalCompleteAnalysisResponse,
617
  )
618
  self.router.add_api_route(
619
+ "/proposals/{proposal_id}/proposal_analysis",
620
  self.delete_proposal_analysis,
621
  methods=["DELETE"],
622
  tags=["Proposal Complete Analysis"],
 
624
  )
625
 
626
  async def get_proposal_strengths(
627
+ self
628
  ):
629
  async with self.__service() as service:
630
  try:
631
  strengths = await service.get_all_data(
632
+ query_type=QueryType.STRENGTHS
 
 
633
  )
634
  return ProposalStrengthResponse(
635
  status="success", data=[ProposalStrength(**s) for s in strengths]
 
639
  raise HTTPException(
640
  status_code=500, detail="Failed to retrieve strengths."
641
  )
642
+
643
+ async def get_proposal_strengths_by_id(self, id: UUID = Path(...)):
644
+ async with self.__service() as service:
645
+ try:
646
+ strength = await service.get_all_data(
647
+ query_type=QueryType.STRENGTHS, id=id
648
+ )
649
+ return ProposalStrengthResponse(
650
+ status="success", data=[ProposalStrength(**s) for s in strength]
651
+ )
652
+ except Exception as e:
653
+ logger.exception(e)
654
+ raise HTTPException(
655
+ status_code=500, detail="Failed to retrieve strength."
656
+ )
657
+
658
+ async def get_proposal_strengths_by_proposal_id(self, proposal_id: UUID = Path(...)):
659
+ async with self.__service() as service:
660
+ try:
661
+ strength = await service.get_all_data(
662
+ query_type=QueryType.STRENGTHS, proposal_id=proposal_id
663
+ )
664
+ return ProposalAllStrengthsResponse(
665
+ status="success", data=[s["strength_point"] for s in strength]
666
+ )
667
+ except Exception as e:
668
+ logger.exception(e)
669
+ raise HTTPException(
670
+ status_code=500, detail="Failed to retrieve strength."
671
+ )
672
+
673
+ async def get_proposal_strengths_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...)):
674
+ async with self.__service() as service:
675
+ try:
676
+ strength = await service.get_all_data(
677
+ query_type=QueryType.STRENGTHS, proposal_id=proposal_id, id=id
678
+ )
679
+ return ProposalStrengthResponse(
680
+ status="success", data=[ProposalStrength(**s) for s in strength]
681
+ )
682
+ except Exception as e:
683
+ logger.exception(e)
684
+ raise HTTPException(
685
+ status_code=500, detail="Failed to retrieve strength."
686
+ )
687
 
688
  async def create_proposal_strengths(self, strength: ProposalStrengthRequest):
689
  async with self.__service() as service:
 
703
  )
704
 
705
  async def create_all_proposal_strengths(
706
+ self, strengths: CreateAllProposalStrengthsRequest, proposal_id: UUID = Path(...)
707
  ):
708
  async with self.__service() as service:
709
  try:
710
+ strengths_request = strengths.model_dump(mode="json", exclude_unset=True)
711
+ strengths_request["proposal_id"] = proposal_id
712
  created = await service.create_data(
713
  query_type=QueryType.STRENGTHS,
714
  create_or_update_type=CreateOrUpdateType.ALL,
715
+ data=strengths_request,
716
  )
717
+ return ProposalAllStrengthsResponse(
718
+ status="success", data=[s["strength_point"] for s in created]
719
  )
720
  except Exception as e:
721
  logger.exception(e)
 
723
  status_code=500, detail="Failed to create strengths."
724
  )
725
 
726
+ async def update_proposal_strengths(self, strength: UpdateProposalStrengthRequest, id: UUID = Path(...)):
727
  async with self.__service() as service:
728
  try:
729
+ strength_request = strength.model_dump(mode="json", exclude_unset=True)
730
+ strength_request["id"] = id
731
  updated = await service.update_data(
732
  query_type=QueryType.STRENGTHS,
733
  create_or_update_type=CreateOrUpdateType.ID,
734
+ data=strength_request,
735
  )
736
  return ProposalStrengthResponse(
737
  status="success", data=[ProposalStrength(**s) for s in updated]
 
743
  )
744
 
745
  async def update_all_proposal_strengths(
746
+ self, strengths: CreateAllProposalStrengthsRequest, proposal_id: UUID = Path(...)
747
  ):
748
  async with self.__service() as service:
749
  try:
750
+ strengths_request = strengths.model_dump(mode="json", exclude_unset=True)
751
+ strengths_request["proposal_id"] = proposal_id
752
  updated = await service.update_data(
753
  query_type=QueryType.STRENGTHS,
754
  create_or_update_type=CreateOrUpdateType.ALL,
755
+ data=strengths_request,
756
  )
757
+ return ProposalAllStrengthsResponse(
758
+ status="success", data=[s["strength_point"] for s in updated]
759
  )
760
  except Exception as e:
761
  logger.exception(e)
 
764
  )
765
 
766
  async def delete_proposal_strength(
767
+ self, id: UUID = Path(...)
768
  ):
769
  async with self.__service() as service:
770
  try:
 
 
 
 
 
771
  result = await service.delete_data(
772
+ query_type=QueryType.STRENGTHS, id=id
773
+ )
774
+ return DeleteResponse(status="success")
775
+ except Exception as e:
776
+ logger.exception(e)
777
+ raise HTTPException(
778
+ status_code=500, detail="Failed to delete strength."
779
+ )
780
+
781
+ async def delete_all_proposal_strengths(self, proposal_id: UUID = Path(...)):
782
+ async with self.__service() as service:
783
+ try:
784
+ result = await service.delete_data(
785
+ query_type=QueryType.STRENGTHS, proposal_id=proposal_id
786
+ )
787
+ return DeleteResponse(status="success")
788
+ except Exception as e:
789
+ logger.exception(e)
790
+ raise HTTPException(
791
+ status_code=500, detail="Failed to delete strengths."
792
+ )
793
+
794
+ async def delete_proposal_strengths_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...)):
795
+ async with self.__service() as service:
796
+ try:
797
+ result = await service.delete_data(
798
+ query_type=QueryType.STRENGTHS, proposal_id=proposal_id, id=id
799
  )
800
  return DeleteResponse(status="success")
801
  except Exception as e:
 
805
  )
806
 
807
  async def get_proposal_weakness(
808
+ self
809
  ):
810
  async with self.__service() as service:
811
  try:
812
  weaknesses = await service.get_all_data(
813
+ query_type=QueryType.WEAKNESSES
 
 
814
  )
815
  return ProposalWeaknessResponse(
816
  status="success", data=[ProposalWeakness(**w) for w in weaknesses]
 
820
  raise HTTPException(
821
  status_code=500, detail="Failed to retrieve weaknesses."
822
  )
823
+
824
+ async def get_proposal_weakness_by_id(self, id: UUID = Path(...)):
825
+ async with self.__service() as service:
826
+ try:
827
+ weakness = await service.get_all_data(
828
+ query_type=QueryType.WEAKNESSES, id=id
829
+ )
830
+ return ProposalWeaknessResponse(
831
+ status="success", data=[ProposalWeakness(**w) for w in weakness]
832
+ )
833
+ except Exception as e:
834
+ logger.exception(e)
835
+ raise HTTPException(
836
+ status_code=500, detail="Failed to retrieve weakness."
837
+ )
838
+
839
+ async def get_proposal_weakness_by_proposal_id(self, proposal_id: UUID = Path(...)):
840
+ async with self.__service() as service:
841
+ try:
842
+ weakness = await service.get_all_data(
843
+ query_type=QueryType.WEAKNESSES, proposal_id=proposal_id
844
+ )
845
+ return ProposalAllWeaknessesResponse(
846
+ status="success", data=[w["weakness_point"] for w in weakness]
847
+ )
848
+ except Exception as e:
849
+ logger.exception(e)
850
+ raise HTTPException(
851
+ status_code=500, detail="Failed to retrieve weakness."
852
+ )
853
+
854
+ async def get_proposal_weakness_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...)):
855
+ async with self.__service() as service:
856
+ try:
857
+ weakness = await service.get_all_data(
858
+ query_type=QueryType.WEAKNESSES, proposal_id=proposal_id, id=id
859
+ )
860
+ return ProposalWeaknessResponse(
861
+ status="success", data=[ProposalWeakness(**w) for w in weakness]
862
+ )
863
+ except Exception as e:
864
+ logger.exception(e)
865
+ raise HTTPException(
866
+ status_code=500, detail="Failed to retrieve weakness."
867
+ )
868
 
869
  async def create_proposal_weakness(self, weakness: ProposalWeaknessRequest):
870
  async with self.__service() as service:
 
884
  )
885
 
886
  async def create_all_proposal_weakness(
887
+ self, weaknesses: CreateAllProposalWeaknessRequest, proposal_id: UUID
888
  ):
889
  async with self.__service() as service:
890
  try:
891
+ weakness_request = weaknesses.model_dump(mode="json", exclude_unset=True)
892
+ weakness_request["proposal_id"] = proposal_id
893
  created = await service.create_data(
894
  query_type=QueryType.WEAKNESSES,
895
  create_or_update_type=CreateOrUpdateType.ALL,
896
+ data=weakness_request,
897
  )
898
+ return ProposalAllWeaknessesResponse(
899
+ status="success", data=[w["weakness_point"] for w in created]
900
  )
901
  except Exception as e:
902
  logger.exception(e)
 
904
  status_code=500, detail="Failed to create weaknesses."
905
  )
906
 
907
+ async def update_proposal_weakness(self, weakness: UpdateProposalWeaknessRequest, id: UUID = Path(...)):
908
  async with self.__service() as service:
909
  try:
910
+ weakness_request = weakness.model_dump(mode="json", exclude_unset=True)
911
+ weakness_request["id"] = id
912
  updated = await service.update_data(
913
  query_type=QueryType.WEAKNESSES,
914
  create_or_update_type=CreateOrUpdateType.ID,
915
+ data=weakness_request,
916
  )
917
  return ProposalWeaknessResponse(
918
  status="success", data=[ProposalWeakness(**w) for w in updated]
 
924
  )
925
 
926
  async def update_all_proposal_weakness(
927
+ self, weaknesses: CreateAllProposalWeaknessRequest, proposal_id: UUID = Path(...)
928
  ):
929
  async with self.__service() as service:
930
  try:
931
+ weakness_request = weaknesses.model_dump(mode="json", exclude_unset=True)
932
+ weakness_request["proposal_id"] = proposal_id
933
  updated = await service.update_data(
934
  query_type=QueryType.WEAKNESSES,
935
  create_or_update_type=CreateOrUpdateType.ALL,
936
+ data=weakness_request,
937
  )
938
+ return ProposalAllWeaknessesResponse(
939
+ status="success", data=[w["weakness_point"] for w in updated]
940
  )
941
  except Exception as e:
942
  logger.exception(e)
 
945
  )
946
 
947
  async def delete_proposal_weakness(
948
+ self, id: UUID = Path(...)
949
  ):
950
  async with self.__service() as service:
951
  try:
952
  result = await service.delete_data(
953
+ query_type=QueryType.WEAKNESSES, id=id
954
+ )
955
+ return DeleteResponse(status="success")
956
+ except Exception as e:
957
+ logger.exception(e)
958
+ raise HTTPException(
959
+ status_code=500, detail="Failed to delete weakness."
960
+ )
961
+
962
+ async def delete_all_proposal_weakness(
963
+ self, proposal_id: UUID = Path(...)
964
+ ):
965
+ async with self.__service() as service:
966
+ try:
967
+ result = await service.delete_data(
968
+ query_type=QueryType.WEAKNESSES, proposal_id=proposal_id
969
+ )
970
+ return DeleteResponse(status="success")
971
+ except Exception as e:
972
+ logger.exception(e)
973
+ raise HTTPException(
974
+ status_code=500, detail="Failed to delete weaknesses."
975
+ )
976
+
977
+ async def delete_proposal_weakness_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...)):
978
+ async with self.__service() as service:
979
+ try:
980
+ result = await service.delete_data(
981
+ query_type=QueryType.WEAKNESSES, proposal_id=proposal_id, id=id
982
  )
983
  return DeleteResponse(status="success")
984
  except Exception as e:
 
988
  )
989
 
990
  async def get_proposal_rejections(
991
+ self
992
  ):
993
  async with self.__service() as service:
994
  try:
995
  rejection_reasons = await service.get_all_data(
996
+ query_type=QueryType.REJECTION_REASONS
 
 
997
  )
998
  return ProposalRejectionReasonResponse(
999
  status="success",
 
1004
  raise HTTPException(
1005
  status_code=500, detail="Failed to retrieve rejection reasons."
1006
  )
1007
+
1008
+ async def get_proposal_rejections_by_id(self, id: UUID = Path(...)):
1009
+ async with self.__service() as service:
1010
+ try:
1011
+ rejection_reason = await service.get_all_data(
1012
+ query_type=QueryType.REJECTION_REASONS, id=id
1013
+ )
1014
+ return ProposalRejectionReasonResponse(
1015
+ status="success", data=[ProposalRejectionReason(**r) for r in rejection_reason]
1016
+ )
1017
+ except Exception as e:
1018
+ logger.exception(e)
1019
+ raise HTTPException(
1020
+ status_code=500, detail="Failed to retrieve rejection reason."
1021
+ )
1022
+
1023
+ async def get_proposal_rejections_by_proposal_id(self, proposal_id: UUID = Path(...)):
1024
+ async with self.__service() as service:
1025
+ try:
1026
+ rejection_reason = await service.get_all_data(
1027
+ query_type=QueryType.REJECTION_REASONS, proposal_id=proposal_id
1028
+ )
1029
+ return ProposalAllRejectionReasonsResponse(
1030
+ status="success", data=[r["reason"] for r in rejection_reason]
1031
+ )
1032
+ except Exception as e:
1033
+ logger.exception(e)
1034
+ raise HTTPException(
1035
+ status_code=500, detail="Failed to retrieve rejection reason."
1036
+ )
1037
+
1038
+ async def get_proposal_rejections_by_proposal_and_id(self, proposal_id: UUID = Path(...), id: UUID = Path(...)):
1039
+ async with self.__service() as service:
1040
+ try:
1041
+ rejection_reason = await service.get_all_data(
1042
+ query_type=QueryType.REJECTION_REASONS, proposal_id=proposal_id, id=id
1043
+ )
1044
+ return ProposalRejectionReasonResponse(
1045
+ status="success", data=[ProposalRejectionReason(**r) for r in rejection_reason]
1046
+ )
1047
+ except Exception as e:
1048
+ logger.exception(e)
1049
+ raise HTTPException(
1050
+ status_code=500, detail="Failed to retrieve rejection reason."
1051
+ )
1052
 
1053
  async def create_proposal_rejections(
1054
  self, rejection_reason: ProposalRejectionReasonRequest
 
1071
  )
1072
 
1073
  async def create_all_proposal_rejections(
1074
+ self, rejection_reasons: CreateAllProposalRejectionReasonsRequest, proposal_id: UUID = Path(...)
1075
  ):
1076
  async with self.__service() as service:
1077
  try:
1078
+ rejection_reasons_data = rejection_reasons.model_dump(mode="json", exclude_unset=True)
1079
+ rejection_reasons_data["proposal_id"] = proposal_id
1080
  created = await service.create_data(
1081
  query_type=QueryType.REJECTION_REASONS,
1082
  create_or_update_type=CreateOrUpdateType.ALL,
1083
+ data=rejection_reasons_data,
1084
  )
1085
+ return ProposalAllRejectionReasonsResponse(
1086
  status="success",
1087
+ data=[r["reason"] for r in created],
1088
  )
1089
  except Exception as e:
1090
  logger.exception(e)
 
1093
  )
1094
 
1095
  async def update_proposal_rejections(
1096
+ self, rejection_reason: UpdateProposalRejectionReasonRequest, id: UUID = Path(...)
1097
  ):
1098
  async with self.__service() as service:
1099
  try:
1100
+ rejection_reason_data = rejection_reason.model_dump(mode="json", exclude_unset=True)
1101
+ rejection_reason_data["id"] = id
1102
  updated = await service.update_data(
1103
  query_type=QueryType.REJECTION_REASONS,
1104
  create_or_update_type=CreateOrUpdateType.ID,
1105
+ data=rejection_reason_data,
1106
  )
1107
  return ProposalRejectionReasonResponse(
1108
  status="success",
 
1115
  )
1116
 
1117
  async def update_all_proposal_rejections(
1118
+ self, rejection_reasons: CreateAllProposalRejectionReasonsRequest, proposal_id: UUID = Path(...)
1119
  ):
1120
  async with self.__service() as service:
1121
  try:
1122
+ rejection_reasons_data = rejection_reasons.model_dump(mode="json", exclude_unset=True)
1123
+ rejection_reasons_data["proposal_id"] = proposal_id
1124
  updated = await service.update_data(
1125
  query_type=QueryType.REJECTION_REASONS,
1126
  create_or_update_type=CreateOrUpdateType.ALL,
1127
+ data=rejection_reasons_data,
1128
  )
1129
+ return ProposalAllRejectionReasonsResponse(
1130
  status="success",
1131
+ data=[r["reason"] for r in updated],
1132
  )
1133
  except Exception as e:
1134
  logger.exception(e)
 
1137
  )
1138
 
1139
  async def delete_proposal_rejections(
1140
+ self, id: UUID = Path(...)
1141
+ ):
1142
+ async with self.__service() as service:
1143
+ try:
1144
+ result = await service.delete_data(
1145
+ query_type=QueryType.REJECTION_REASONS,
1146
+ id=id
1147
+ )
1148
+ return DeleteResponse(status="success")
1149
+ except Exception as e:
1150
+ logger.exception(e)
1151
+ raise HTTPException(
1152
+ status_code=500, detail="Failed to delete rejection reason."
1153
+ )
1154
+
1155
+ async def delete_all_proposal_rejections(
1156
+ self, proposal_id: UUID = Path(...)
1157
+ ):
1158
+ async with self.__service() as service:
1159
+ try:
1160
+ result = await service.delete_data(
1161
+ query_type=QueryType.REJECTION_REASONS,
1162
+ proposal_id=proposal_id
1163
+ )
1164
+ return DeleteResponse(status="success")
1165
+ except Exception as e:
1166
+ logger.exception(e)
1167
+ raise HTTPException(
1168
+ status_code=500, detail="Failed to delete rejection reasons."
1169
+ )
1170
+
1171
+ async def delete_proposal_rejections_by_proposal_and_id(
1172
+ self, proposal_id: UUID = Path(...), id: UUID = Path(...)
1173
  ):
1174
  async with self.__service() as service:
1175
  try:
 
 
 
 
 
1176
  result = await service.delete_data(
1177
  query_type=QueryType.REJECTION_REASONS,
1178
  id=id,
1179
+ proposal_id=proposal_id
1180
  )
1181
  return DeleteResponse(status="success")
1182
  except Exception as e:
 
1186
  )
1187
 
1188
  async def get_proposal_improvements(
1189
+ self
1190
  ):
1191
  async with self.__service() as service:
1192
  try:
1193
  improvements = await service.get_all_data(
1194
+ query_type=QueryType.IMPROVEMENTS
1195
+ )
1196
+ return ProposalImprovementResponse(
1197
+ status="success",
1198
+ data=[ProposalImprovement(**r) for r in improvements],
1199
+ )
1200
+ except Exception as e:
1201
+ logger.exception(e)
1202
+ raise HTTPException(
1203
+ status_code=500, detail="Failed to retrieve improvements."
1204
+ )
1205
+
1206
+ async def get_proposal_improvements_by_id(
1207
+ self, id: UUID = Path(...)
1208
+ ):
1209
+ async with self.__service() as service:
1210
+ try:
1211
+ improvements = await service.get_all_data(
1212
+ query_type=QueryType.IMPROVEMENTS,
1213
+ id=id
1214
+ )
1215
+ return ProposalImprovementResponse(
1216
+ status="success",
1217
+ data=[ProposalImprovement(**r) for r in improvements],
1218
+ )
1219
+ except Exception as e:
1220
+ logger.exception(e)
1221
+ raise HTTPException(
1222
+ status_code=500, detail="Failed to retrieve improvements."
1223
+ )
1224
+
1225
+ async def get_proposal_improvements_by_proposal_id(
1226
+ self, proposal_id: UUID = Path(...)
1227
+ ):
1228
+ async with self.__service() as service:
1229
+ try:
1230
+ improvements = await service.get_all_data(
1231
+ query_type=QueryType.IMPROVEMENTS,
1232
+ proposal_id=proposal_id
1233
+ )
1234
+ return ProposalAllImprovementsResponse(
1235
+ status="success",
1236
+ data=[r["improvement_point"] for r in improvements],
1237
+ )
1238
+ except Exception as e:
1239
+ logger.exception(e)
1240
+ raise HTTPException(
1241
+ status_code=500, detail="Failed to retrieve improvements."
1242
+ )
1243
+
1244
+ async def get_proposal_improvements_by_proposal_and_id(
1245
+ self, proposal_id: UUID = Path(...), id: UUID = Path(...)
1246
+ ):
1247
+ async with self.__service() as service:
1248
+ try:
1249
+ improvements = await service.get_all_data(
1250
+ query_type=QueryType.IMPROVEMENTS,
1251
+ id=id,
1252
+ proposal_id=proposal_id
1253
  )
1254
  return ProposalImprovementResponse(
1255
  status="success",
 
1281
  )
1282
 
1283
  async def create_all_proposal_improvements(
1284
+ self, improvements: CreateAllProposalImprovementsRequest, proposal_id: UUID = Path(...)
1285
  ):
1286
  async with self.__service() as service:
1287
  try:
1288
+ data = improvements.model_dump(mode="json", exclude_unset=True)
1289
+ data["proposal_id"] = proposal_id
1290
  created = await service.create_data(
1291
  query_type=QueryType.IMPROVEMENTS,
1292
  create_or_update_type=CreateOrUpdateType.ALL,
1293
+ data=data,
1294
  )
1295
+ return ProposalAllImprovementsResponse(
1296
+ status="success", data=[r["improvement_point"] for r in created]
1297
  )
1298
  except Exception as e:
1299
  logger.exception(e)
 
1302
  )
1303
 
1304
  async def update_proposal_improvements(
1305
+ self, improvement: UpdateProposalImprovementRequest, id: UUID = Path(...)
1306
  ):
1307
  async with self.__service() as service:
1308
  try:
1309
+ data = improvement.model_dump(mode="json", exclude_unset=True)
1310
+ data["id"] = id
1311
  updated = await service.update_data(
1312
  query_type=QueryType.IMPROVEMENTS,
1313
  create_or_update_type=CreateOrUpdateType.ID,
1314
+ data=data,
1315
  )
1316
  return ProposalImprovementResponse(
1317
  status="success", data=[ProposalImprovement(**r) for r in updated]
 
1323
  )
1324
 
1325
  async def update_all_proposal_improvements(
1326
+ self, improvements: CreateAllProposalImprovementsRequest, proposal_id: UUID = Path(...)
1327
  ):
1328
  async with self.__service() as service:
1329
  try:
1330
+ data = improvements.model_dump(mode="json", exclude_unset=True)
1331
+ data["proposal_id"] = proposal_id
1332
  updated = await service.update_data(
1333
  query_type=QueryType.IMPROVEMENTS,
1334
  create_or_update_type=CreateOrUpdateType.ALL,
1335
+ data=data,
1336
  )
1337
+ return ProposalAllImprovementsResponse(
1338
+ status="success", data=[r["improvement_point"] for r in updated]
1339
  )
1340
  except Exception as e:
1341
  logger.exception(e)
 
1344
  )
1345
 
1346
  async def delete_proposal_improvements(
1347
+ self, id: UUID = Path(...)
1348
+ ):
1349
+ async with self.__service() as service:
1350
+ try:
1351
+ result = await service.delete_data(
1352
+ query_type=QueryType.IMPROVEMENTS, id=id
1353
+ )
1354
+ return DeleteResponse(status="success")
1355
+ except Exception as e:
1356
+ logger.exception(e)
1357
+ raise HTTPException(
1358
+ status_code=500, detail="Failed to delete improvement."
1359
+ )
1360
+
1361
+ async def delete_all_proposal_improvements(
1362
+ self, proposal_id: UUID = Path(...)
1363
+ ):
1364
+ async with self.__service() as service:
1365
+ try:
1366
+ result = await service.delete_data(
1367
+ query_type=QueryType.IMPROVEMENTS, proposal_id=proposal_id
1368
+ )
1369
+ return DeleteResponse(status="success")
1370
+ except Exception as e:
1371
+ logger.exception(e)
1372
+ raise HTTPException(
1373
+ status_code=500, detail="Failed to delete improvements."
1374
+ )
1375
+
1376
+ async def delete_proposal_improvements_by_proposal_and_id(
1377
+ self, id: UUID = Path(...), proposal_id: UUID = Path(...)
1378
  ):
1379
  async with self.__service() as service:
1380
  try:
 
 
 
 
 
1381
  result = await service.delete_data(
1382
  query_type=QueryType.IMPROVEMENTS, id=id, proposal_id=proposal_id
1383
  )
 
1389
  )
1390
 
1391
  async def get_proposal_ai_score(
1392
+ self
1393
+ ):
1394
+ async with self.__service() as service:
1395
+ try:
1396
+ scores = await service.get_all_data(
1397
+ query_type=QueryType.AI_SCORE
1398
+ )
1399
+ return ProposalAIAnalysisResponse(
1400
+ status="success", data=[ProposalAIAnalysis(**r) for r in scores]
1401
+ )
1402
+ except Exception as e:
1403
+ logger.exception(e)
1404
+ raise HTTPException(
1405
+ status_code=500, detail="Failed to retrieve AI scores."
1406
+ )
1407
+
1408
+ async def get_proposal_ai_score_by_id(
1409
+ self, id: UUID = Path(...)
1410
+ ):
1411
+ async with self.__service() as service:
1412
+ try:
1413
+ scores = await service.get_all_data(
1414
+ query_type=QueryType.AI_SCORE, id=id
1415
+ )
1416
+ return ProposalAIAnalysisResponse(
1417
+ status="success", data=[ProposalAIAnalysis(**r) for r in scores]
1418
+ )
1419
+ except Exception as e:
1420
+ logger.exception(e)
1421
+ raise HTTPException(
1422
+ status_code=500, detail="Failed to retrieve AI scores."
1423
+ )
1424
+
1425
+ async def get_proposal_ai_score_by_proposal_id(
1426
+ self, proposal_id: UUID = Path(...)
1427
+ ):
1428
+ async with self.__service() as service:
1429
+ try:
1430
+ scores = await service.get_all_data(
1431
+ query_type=QueryType.AI_SCORE, proposal_id=proposal_id
1432
+ )
1433
+ return ProposalAIAnalysisResponse(
1434
+ status="success", data=[ProposalAIAnalysis(**r) for r in scores]
1435
+ )
1436
+ except Exception as e:
1437
+ logger.exception(e)
1438
+ raise HTTPException(
1439
+ status_code=500, detail="Failed to retrieve AI scores."
1440
+ )
1441
+
1442
+ async def get_proposal_ai_score_by_proposal_and_id(
1443
+ self, id: UUID = Path(...), proposal_id: UUID = Path(...)
1444
  ):
1445
  async with self.__service() as service:
1446
  try:
 
1472
  raise HTTPException(
1473
  status_code=500, detail="Failed to create AI score."
1474
  )
1475
+
1476
+ async def create_proposal_ai_score_by_proposal_id(self, score: CreateAIAnalysisRequestByProposalId, proposal_id: UUID = Path(...)):
1477
+ async with self.__service() as service:
1478
+ try:
1479
+ data = score.model_dump(mode="json", exclude_unset=True)
1480
+ data["proposal_id"] = proposal_id
1481
+ created = await service.create_data(
1482
+ query_type=QueryType.AI_SCORE,
1483
+ create_or_update_type=CreateOrUpdateType.ID,
1484
+ data=data,
1485
+ )
1486
+ return ProposalAIAnalysisResponse(
1487
+ status="success", data=[ProposalAIAnalysis(**r) for r in created]
1488
+ )
1489
+ except Exception as e:
1490
+ logger.exception(e)
1491
+ raise HTTPException(
1492
+ status_code=500, detail="Failed to create AI score."
1493
+ )
1494
 
1495
+ async def update_proposal_ai_score(self, score: UpdateAiAnalysisRequest, id: UUID = Path(...)):
 
 
 
 
1496
  async with self.__service() as service:
1497
  try:
1498
+ if id:
1499
+ data = score.model_dump(mode="json", exclude_unset=True)
1500
+ data["id"] = id
1501
  updated = await service.update_data(
1502
  query_type=QueryType.AI_SCORE,
1503
  create_or_update_type=CreateOrUpdateType.ID,
1504
+ data=data,
 
 
 
 
 
 
1505
  )
1506
  return ProposalAIAnalysisResponse(
1507
  status="success", data=[ProposalAIAnalysis(**r) for r in updated]
 
1511
  raise HTTPException(
1512
  status_code=500, detail="Failed to update AI score."
1513
  )
1514
+
1515
+ async def update_proposal_ai_score_by_proposal_id(self, score: UpdateAIAnalysisRequestByProposalId, proposal_id: UUID = Path(...)):
1516
+ async with self.__service() as service:
1517
+ try:
1518
+ data = score.model_dump(mode="json", exclude_unset=True)
1519
+ data["proposal_id"] = proposal_id
1520
+ updated = await service.update_data(
1521
+ query_type=QueryType.AI_SCORE,
1522
+ create_or_update_type=CreateOrUpdateType.ALL,
1523
+ data=data,
1524
+ )
1525
+ return ProposalAIAnalysisResponse(
1526
+ status="success", data=[ProposalAIAnalysis(**r) for r in updated]
1527
+ )
1528
+ except Exception as e:
1529
+ logger.exception(e)
1530
+ raise HTTPException(
1531
+ status_code=500, detail="Failed to update AI score."
1532
+ )
1533
 
1534
  async def delete_proposal_ai_score(
1535
+ self, id: UUID = Path(...)
1536
+ ):
1537
+ async with self.__service() as service:
1538
+ try:
1539
+ result = await service.delete_data(
1540
+ query_type=QueryType.AI_SCORE, id=id
1541
+ )
1542
+ return DeleteResponse(status="success")
1543
+ except Exception as e:
1544
+ logger.exception(e)
1545
+ raise HTTPException(
1546
+ status_code=500, detail="Failed to delete AI score."
1547
+ )
1548
+
1549
+ async def delete_proposal_ai_score_by_proposal_id(
1550
+ self, proposal_id: UUID = Path(...)
1551
+ ):
1552
+ async with self.__service() as service:
1553
+ try:
1554
+ result = await service.delete_data(
1555
+ query_type=QueryType.AI_SCORE, proposal_id=proposal_id
1556
+ )
1557
+ return DeleteResponse(status="success")
1558
+ except Exception as e:
1559
+ logger.exception(e)
1560
+ raise HTTPException(
1561
+ status_code=500, detail="Failed to delete AI score."
1562
+ )
1563
+
1564
+ async def delete_proposal_ai_score_by_proposal_and_id(
1565
+ self, id: UUID = Path(...), proposal_id: UUID = Path(...)
1566
  ):
1567
  async with self.__service() as service:
1568
  try:
 
 
 
 
 
1569
  result = await service.delete_data(
1570
  query_type=QueryType.AI_SCORE, id=id, proposal_id=proposal_id
1571
  )
 
1576
  status_code=500, detail="Failed to delete AI score."
1577
  )
1578
 
1579
+ async def get_all_proposal_analysis(self, proposal_id: UUID = Path(...)):
1580
  async with self.__service() as service:
1581
  try:
1582
  analysis = await service.get_all_data(
 
1593
  )
1594
 
1595
  async def create_proposal_analysis(
1596
+ self, analysis: CreateAllProposalAnalysisRequest, proposal_id: UUID = Path(...)
1597
  ):
1598
  async with self.__service() as service:
1599
  try:
1600
+ data = analysis.model_dump(mode="json", exclude_unset=True)
1601
+ data["proposal_id"] = proposal_id
1602
  created = await service.create_data(
1603
  query_type=QueryType.ALL,
1604
  create_or_update_type=CreateOrUpdateType.ALL,
1605
+ data=data,
1606
  )
1607
  return ProposalCompleteAnalysisResponse(
1608
  status="success",
 
1615
  )
1616
 
1617
  async def update_proposal_analysis(
1618
+ self, analysis: UpdateAllProposalAnalysisRequest, proposal_id: UUID = Path(...)
1619
  ):
1620
  async with self.__service() as service:
1621
  try:
1622
+ data = analysis.model_dump(mode="json", exclude_unset=True)
1623
+ data["proposal_id"] = proposal_id
1624
  updated = await service.update_data(
1625
  query_type=QueryType.ALL,
1626
  create_or_update_type=CreateOrUpdateType.ALL,
1627
+ data=data,
1628
  )
1629
  return ProposalCompleteAnalysisResponse(
1630
  status="success",
 
1636
  status_code=500, detail="Failed to update analysis."
1637
  )
1638
 
1639
+ async def delete_proposal_analysis(self, proposal_id: UUID = Path(...)):
1640
  async with self.__service() as service:
1641
  try:
1642
  result = await service.delete_data(
1643
+ query_type=QueryType.ALL, proposal_id=proposal_id
1644
  )
1645
  return DeleteResponse(status="success")
1646
  except Exception as e:
src/controllers/_proposal_controller.py CHANGED
@@ -28,6 +28,13 @@ class ProposalRequest(BaseModel):
28
  status: ProposalStatus
29
 
30
 
 
 
 
 
 
 
 
31
  class ProposalUpdateRequest(BaseModel):
32
  rfp_id: Optional[UUID] = None
33
  name: Optional[str] = None
@@ -36,6 +43,13 @@ class ProposalUpdateRequest(BaseModel):
36
  status: Optional[ProposalStatus] = None
37
 
38
 
 
 
 
 
 
 
 
39
  class ProposalDeleteResponse(BaseModel):
40
  status: str
41
 
@@ -84,6 +98,13 @@ class ProposalController:
84
  response_model=ResponseProposal,
85
  tags=["Proposals"],
86
  )
 
 
 
 
 
 
 
87
  self.router.add_api_route(
88
  "/proposals/{proposal_id}",
89
  self.update_proposal,
@@ -91,6 +112,13 @@ class ProposalController:
91
  response_model=ResponseProposal,
92
  tags=["Proposals by ID"],
93
  )
 
 
 
 
 
 
 
94
  self.router.add_api_route(
95
  "/proposals/{proposal_id}",
96
  self.delete_proposal,
@@ -113,9 +141,7 @@ class ProposalController:
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()
@@ -127,7 +153,7 @@ class ProposalController:
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(...),
@@ -143,7 +169,7 @@ class ProposalController:
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(...),
@@ -159,7 +185,7 @@ class ProposalController:
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(...),
@@ -167,7 +193,9 @@ class ProposalController:
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,12 +220,31 @@ class ProposalController:
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)]
@@ -208,14 +255,33 @@ class ProposalController:
208
  status_code=500, detail="Failed to update 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.")
221
  return ProposalDeleteResponse(status="success")
@@ -224,15 +290,11 @@ class ProposalController:
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")
@@ -241,7 +303,7 @@ class ProposalController:
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
  ):
@@ -257,4 +319,4 @@ class ProposalController:
257
  logger.exception(e)
258
  raise HTTPException(
259
  status_code=500, detail="Failed to delete proposal."
260
- )
 
28
  status: ProposalStatus
29
 
30
 
31
+ class CreateProposalRequest(BaseModel):
32
+ name: str
33
+ tep: str
34
+ gate_criteria: GateCriteria
35
+ status: ProposalStatus
36
+
37
+
38
  class ProposalUpdateRequest(BaseModel):
39
  rfp_id: Optional[UUID] = None
40
  name: Optional[str] = None
 
43
  status: Optional[ProposalStatus] = None
44
 
45
 
46
+ class UpdateProposalRequest(BaseModel):
47
+ name: Optional[str] = None
48
+ tep: Optional[str] = None
49
+ gate_criteria: Optional[GateCriteria] = None
50
+ status: Optional[ProposalStatus] = None
51
+
52
+
53
  class ProposalDeleteResponse(BaseModel):
54
  status: str
55
 
 
98
  response_model=ResponseProposal,
99
  tags=["Proposals"],
100
  )
101
+ self.router.add_api_route(
102
+ "/rfps/{rfp_id}/proposals",
103
+ self.create_proposal_by_rfp_id,
104
+ methods=["POST"],
105
+ response_model=ResponseProposal,
106
+ tags=["Proposals by RFP ID"],
107
+ )
108
  self.router.add_api_route(
109
  "/proposals/{proposal_id}",
110
  self.update_proposal,
 
112
  response_model=ResponseProposal,
113
  tags=["Proposals by ID"],
114
  )
115
+ self.router.add_api_route(
116
+ "/rfps/{rfp_id}/proposals/{proposal_id}",
117
+ self.update_proposal_by_proposal_and_rfp_id,
118
+ methods=["PUT"],
119
+ response_model=ResponseProposal,
120
+ tags=["Proposals by Proposal and RFP ID"],
121
+ )
122
  self.router.add_api_route(
123
  "/proposals/{proposal_id}",
124
  self.delete_proposal,
 
141
  tags=["Proposals by Proposal and RFP ID"],
142
  )
143
 
144
+ async def get_proposals(self):
 
 
145
  async with self.__proposal_service() as service:
146
  try:
147
  proposals = await service.get_proposals()
 
153
  raise HTTPException(
154
  status_code=500, detail="Failed to retrieve proposals."
155
  )
156
+
157
  async def get_proposals_by_id(
158
  self,
159
  proposal_id: str = Path(...),
 
169
  raise HTTPException(
170
  status_code=500, detail="Failed to retrieve proposals."
171
  )
172
+
173
  async def get_proposals_by_rfp_id(
174
  self,
175
  rfp_id: str = Path(...),
 
185
  raise HTTPException(
186
  status_code=500, detail="Failed to retrieve proposals."
187
  )
188
+
189
  async def get_proposals_by_proposal_and_rfp_id(
190
  self,
191
  rfp_id: str = Path(...),
 
193
  ):
194
  async with self.__proposal_service() as service:
195
  try:
196
+ proposals = await service.get_proposals(
197
+ rfp_id=rfp_id, proposal_id=proposal_id
198
+ )
199
  return ResponseProposal(
200
  status="success", data=[Proposal(**p) for p in proposals]
201
  )
 
220
  status_code=500, detail="Failed to create proposal."
221
  )
222
 
223
+ async def create_proposal_by_rfp_id(
224
+ self, proposal: CreateProposalRequest, rfp_id: str = Path(...)
225
+ ):
226
+ async with self.__proposal_service() as service:
227
+ try:
228
+ data = proposal.model_dump(exclude_unset=True, mode="json")
229
+ data["rfp_id"] = rfp_id
230
+ new_proposal = await service.create_proposal(proposal=data)
231
+ return ResponseProposal(
232
+ status="success", data=[Proposal(**new_proposal)]
233
+ )
234
+ except Exception as e:
235
+ logger.exception(e)
236
+ raise HTTPException(
237
+ status_code=500, detail="Failed to create proposal."
238
+ )
239
+
240
+ async def update_proposal(
241
+ self, proposal: ProposalUpdateRequest, proposal_id: str = Path(...)
242
+ ):
243
  async with self.__proposal_service() as service:
244
  try:
245
  updated_proposal = await service.update_proposal(
246
  proposal_id=proposal_id,
247
+ proposal=proposal.model_dump(exclude_unset=True),
248
  )
249
  return ResponseProposal(
250
  status="success", data=[Proposal(**updated_proposal)]
 
255
  status_code=500, detail="Failed to update proposal."
256
  )
257
 
258
+ async def update_proposal_by_proposal_and_rfp_id(
259
+ self,
260
+ proposal: UpdateProposalRequest,
261
+ rfp_id: str = Path(...),
262
+ proposal_id: str = Path(...),
263
  ):
264
  async with self.__proposal_service() as service:
265
  try:
266
+ data = proposal.model_dump(exclude_unset=True, mode="json")
267
+ data["rfp_id"] = rfp_id
268
+ updated_proposal = await service.update_proposal(
269
+ proposal_id=proposal_id,
270
+ proposal=proposal.model_dump(exclude_unset=True),
271
  )
272
+ return ResponseProposal(
273
+ status="success", data=[Proposal(**updated_proposal)]
274
+ )
275
+ except Exception as e:
276
+ logger.exception(e)
277
+ raise HTTPException(
278
+ status_code=500, detail="Failed to update proposal."
279
+ )
280
+
281
+ async def delete_proposal(self, proposal_id: str = Path(...)):
282
+ async with self.__proposal_service() as service:
283
+ try:
284
+ status = await service.delete_proposal(proposal_id=proposal_id)
285
  if not status:
286
  raise HTTPException(status_code=404, detail="Proposal not found.")
287
  return ProposalDeleteResponse(status="success")
 
290
  raise HTTPException(
291
  status_code=500, detail="Failed to delete proposal."
292
  )
293
+
294
+ async def delete_proposals_by_rfp_id(self, rfp_id: str = Path(...)):
 
 
295
  async with self.__proposal_service() as service:
296
  try:
297
+ status = await service.delete_proposal(rfp_id=rfp_id)
 
 
298
  if not status:
299
  raise HTTPException(status_code=404, detail="Proposal not found.")
300
  return ProposalDeleteResponse(status="success")
 
303
  raise HTTPException(
304
  status_code=500, detail="Failed to delete proposal."
305
  )
306
+
307
  async def delete_proposals_by_proposal_and_rfp_id(
308
  self, rfp_id: str = Path(...), proposal_id: str = Path(...)
309
  ):
 
319
  logger.exception(e)
320
  raise HTTPException(
321
  status_code=500, detail="Failed to delete proposal."
322
+ )
src/controllers/_proposal_detailed_analysis_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
@@ -39,7 +39,6 @@ class ProposalCompleteDetailedAnalysis(BaseModel):
39
 
40
 
41
  class CreateProposalDetailedAnalysisRequest(BaseModel):
42
- proposal_id: UUID
43
  data: ProposalCompleteDetailedAnalysis
44
 
45
 
@@ -60,7 +59,6 @@ class CreateDetailedAnalysisRequest(BaseModel):
60
 
61
 
62
  class UpdateDetailedAnalysisRequest(BaseModel):
63
- id: Optional[UUID] = None
64
  proposal_id: Optional[UUID] = None
65
  confidence: Optional[float] = None
66
  ai_assessment_result: Optional[str] = None
@@ -79,10 +77,17 @@ class ProposalDetailedController:
79
  response_model=ProposalDetailedAnalysisResponse,
80
  )
81
  self.router.add_api_route(
82
- "/proposal_detailed_analysis/all",
 
 
 
 
 
 
 
83
  self.get_proposal_analysis_by_proposal_id,
84
  methods=["GET"],
85
- tags=["Proposal Complete Detailed Analysis"],
86
  response_model=CompleteAnalysisResponse,
87
  )
88
  self.router.add_api_route(
@@ -93,37 +98,52 @@ class ProposalDetailedController:
93
  response_model=ProposalDetailedAnalysisResponse,
94
  )
95
  self.router.add_api_route(
96
- "/proposal_detailed_analysis/all",
97
  self.create_complete_proposal_analysis,
98
  methods=["POST"],
99
- tags=["Proposal Complete Detailed Analysis"],
100
  response_model=CompleteAnalysisResponse,
101
  )
102
  self.router.add_api_route(
103
- "/proposal_detailed_analysis",
104
  self.update_proposal_analysis,
105
  methods=["PUT"],
106
- tags=["Proposal Detailed Analysis"],
107
  response_model=ProposalDetailedAnalysisResponse,
108
  )
109
  self.router.add_api_route(
110
- "/proposal_detailed_analysis/all",
111
  self.update_complete_proposal_analysis,
112
  methods=["PUT"],
113
- tags=["Proposal Complete Detailed Analysis"],
114
  response_model=CompleteAnalysisResponse,
115
  )
116
  self.router.add_api_route(
117
- "/proposal_detailed_analysis",
118
  self.delete_proposal_analysis,
119
  methods=["DELETE"],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  response_model=DeleteResponse,
121
  )
122
 
123
- async def get_proposal_analysis(self, id: str = Query(None)):
124
  async with self.service() as service:
125
  try:
126
- result = await service.get_proposal_analysis(id=id)
127
  if not result:
128
  return ProposalDetailedAnalysisResponse(status="success", data=[])
129
  return ProposalDetailedAnalysisResponse(
@@ -136,7 +156,21 @@ class ProposalDetailedController:
136
  status_code=500, detail="Failed to get proposal analysis."
137
  )
138
 
139
- async def get_proposal_analysis_by_proposal_id(self, proposal_id: str = Query(...)):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  async with self.service() as service:
141
  try:
142
  result = await service.get_proposal_analysis_by_proposal_id(
@@ -166,13 +200,15 @@ class ProposalDetailedController:
166
  )
167
 
168
  async def create_complete_proposal_analysis(
169
- self, analysis: CreateProposalDetailedAnalysisRequest
 
 
170
  ):
171
  async with self.service() as service:
172
  try:
173
- result = await service.create_complete_proposal_analysis(
174
- data=analysis.model_dump(mode="json", exclude_unset=True)
175
- )
176
  return CompleteAnalysisResponse(status="success", data=result)
177
  except Exception as e:
178
  logger.exception(e)
@@ -180,12 +216,14 @@ class ProposalDetailedController:
180
  status_code=500, detail="Failed to create proposal analysis."
181
  )
182
 
183
- async def update_proposal_analysis(self, analysis: UpdateDetailedAnalysisRequest):
 
 
184
  async with self.service() as service:
185
  try:
186
- result = await service.update_proposal_analysis(
187
- data=analysis.model_dump(mode="json", exclude_unset=True)
188
- )
189
  return ProposalDetailedAnalysisResponse(
190
  status="success",
191
  data=[ProposalDetailedAnalysis(**r) for r in result],
@@ -197,13 +235,15 @@ class ProposalDetailedController:
197
  )
198
 
199
  async def update_complete_proposal_analysis(
200
- self, analysis: CreateProposalDetailedAnalysisRequest
 
 
201
  ):
202
  async with self.service() as service:
203
  try:
204
- result = await service.update_complete_proposal_analysis(
205
- data=analysis.model_dump(mode="json", exclude_unset=True)
206
- )
207
  return CompleteAnalysisResponse(status="success", data=result)
208
  except Exception as e:
209
  logger.exception(e)
@@ -211,18 +251,37 @@ class ProposalDetailedController:
211
  status_code=500, detail="Failed to update proposal analysis."
212
  )
213
 
214
- async def delete_proposal_analysis(
215
- self, id: str = Query(None), proposal_id: str = Query(None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  ):
217
  async with self.service() as service:
218
  try:
219
- if not id and not proposal_id:
220
- raise HTTPException(
221
- status_code=400,
222
- detail="Either id or proposal_id must be provided.",
223
- )
224
  result = await service.delete_proposal_analysis(
225
- id=id, proposal_id=proposal_id
226
  )
227
  return DeleteResponse(status="success")
228
  except Exception as e:
 
1
+ from fastapi import APIRouter, HTTPException, Query, Path
2
  from pydantic import BaseModel
3
  from typing import List, Optional
4
  from uuid import UUID
 
39
 
40
 
41
  class CreateProposalDetailedAnalysisRequest(BaseModel):
 
42
  data: ProposalCompleteDetailedAnalysis
43
 
44
 
 
59
 
60
 
61
  class UpdateDetailedAnalysisRequest(BaseModel):
 
62
  proposal_id: Optional[UUID] = None
63
  confidence: Optional[float] = None
64
  ai_assessment_result: Optional[str] = None
 
77
  response_model=ProposalDetailedAnalysisResponse,
78
  )
79
  self.router.add_api_route(
80
+ "/proposal_detailed_analysis/{id}",
81
+ self.get_proposal_analysis_by_id,
82
+ methods=["GET"],
83
+ tags=["Proposal Detailed Analysis by ID"],
84
+ response_model=ProposalDetailedAnalysisResponse,
85
+ )
86
+ self.router.add_api_route(
87
+ "/proposals/{proposal_id}/proposal_detailed_analysis",
88
  self.get_proposal_analysis_by_proposal_id,
89
  methods=["GET"],
90
+ tags=["Proposal Detailed Analysis by Proposal ID"],
91
  response_model=CompleteAnalysisResponse,
92
  )
93
  self.router.add_api_route(
 
98
  response_model=ProposalDetailedAnalysisResponse,
99
  )
100
  self.router.add_api_route(
101
+ "/proposals/{proposal_id}/proposal_detailed_analysis",
102
  self.create_complete_proposal_analysis,
103
  methods=["POST"],
104
+ tags=["Proposal Detailed Analysis by Proposal ID"],
105
  response_model=CompleteAnalysisResponse,
106
  )
107
  self.router.add_api_route(
108
+ "/proposal_detailed_analysis/{id}",
109
  self.update_proposal_analysis,
110
  methods=["PUT"],
111
+ tags=["Proposal Detailed Analysis by ID"],
112
  response_model=ProposalDetailedAnalysisResponse,
113
  )
114
  self.router.add_api_route(
115
+ "/proposals/{proposal_id}/proposal_detailed_analysis",
116
  self.update_complete_proposal_analysis,
117
  methods=["PUT"],
118
+ tags=["Proposal Detailed Analysis by Proposal ID"],
119
  response_model=CompleteAnalysisResponse,
120
  )
121
  self.router.add_api_route(
122
+ "/proposal_detailed_analysis/{id}",
123
  self.delete_proposal_analysis,
124
  methods=["DELETE"],
125
+ tags=["Proposal Detailed Analysis by ID"],
126
+ response_model=DeleteResponse,
127
+ )
128
+ self.router.add_api_route(
129
+ "/proposals/{proposal_id}/proposal_detailed_analysis",
130
+ self.delete_proposal_analysis_by_proposal_id,
131
+ methods=["DELETE"],
132
+ tags=["Proposal Detailed Analysis by Proposal ID"],
133
+ response_model=DeleteResponse,
134
+ )
135
+ self.router.add_api_route(
136
+ "/proposals/{proposal_id}/proposal_detailed_analysis/{id}",
137
+ self.delete_proposal_analysis_by_proposal_and_id,
138
+ methods=["DELETE"],
139
+ tags=["Proposal Detailed Analysis by Proposal and ID"],
140
  response_model=DeleteResponse,
141
  )
142
 
143
+ async def get_proposal_analysis(self):
144
  async with self.service() as service:
145
  try:
146
+ result = await service.get_proposal_analysis()
147
  if not result:
148
  return ProposalDetailedAnalysisResponse(status="success", data=[])
149
  return ProposalDetailedAnalysisResponse(
 
156
  status_code=500, detail="Failed to get proposal analysis."
157
  )
158
 
159
+ async def get_proposal_analysis_by_id(self, id: str = Path(...)):
160
+ async with self.service() as service:
161
+ try:
162
+ result = await service.get_proposal_analysis(id=id)
163
+ return ProposalDetailedAnalysisResponse(
164
+ status="success",
165
+ data=[ProposalDetailedAnalysis(**r) for r in result],
166
+ )
167
+ except Exception as e:
168
+ logger.exception(e)
169
+ raise HTTPException(
170
+ status_code=500, detail="Failed to get proposal analysis."
171
+ )
172
+
173
+ async def get_proposal_analysis_by_proposal_id(self, proposal_id: str = Path(...)):
174
  async with self.service() as service:
175
  try:
176
  result = await service.get_proposal_analysis_by_proposal_id(
 
200
  )
201
 
202
  async def create_complete_proposal_analysis(
203
+ self,
204
+ analysis: CreateProposalDetailedAnalysisRequest,
205
+ proposal_id: UUID = Path(...),
206
  ):
207
  async with self.service() as service:
208
  try:
209
+ data = analysis.model_dump(mode="json", exclude_unset=True)
210
+ data["proposal_id"] = proposal_id
211
+ result = await service.create_complete_proposal_analysis(data=data)
212
  return CompleteAnalysisResponse(status="success", data=result)
213
  except Exception as e:
214
  logger.exception(e)
 
216
  status_code=500, detail="Failed to create proposal analysis."
217
  )
218
 
219
+ async def update_proposal_analysis(
220
+ self, analysis: UpdateDetailedAnalysisRequest, id: UUID = Path(...)
221
+ ):
222
  async with self.service() as service:
223
  try:
224
+ data = analysis.model_dump(mode="json", exclude_unset=True)
225
+ data["id"] = id
226
+ result = await service.update_proposal_analysis(data=data)
227
  return ProposalDetailedAnalysisResponse(
228
  status="success",
229
  data=[ProposalDetailedAnalysis(**r) for r in result],
 
235
  )
236
 
237
  async def update_complete_proposal_analysis(
238
+ self,
239
+ analysis: CreateProposalDetailedAnalysisRequest,
240
+ proposal_id: UUID = Path(...),
241
  ):
242
  async with self.service() as service:
243
  try:
244
+ data = analysis.model_dump(mode="json", exclude_unset=True)
245
+ data["proposal_id"] = proposal_id
246
+ result = await service.update_complete_proposal_analysis(data=data)
247
  return CompleteAnalysisResponse(status="success", data=result)
248
  except Exception as e:
249
  logger.exception(e)
 
251
  status_code=500, detail="Failed to update proposal analysis."
252
  )
253
 
254
+ async def delete_proposal_analysis(self, id: str = Path(...)):
255
+ async with self.service() as service:
256
+ try:
257
+ result = await service.delete_proposal_analysis(id=id)
258
+ return DeleteResponse(status="success")
259
+ except Exception as e:
260
+ logger.exception(e)
261
+ raise HTTPException(
262
+ status_code=500, detail="Failed to delete proposal analysis."
263
+ )
264
+
265
+ async def delete_proposal_analysis_by_proposal_id(
266
+ self, proposal_id: str = Path(...)
267
+ ):
268
+ async with self.service() as service:
269
+ try:
270
+ result = await service.delete_proposal_analysis(proposal_id=proposal_id)
271
+ return DeleteResponse(status="success")
272
+ except Exception as e:
273
+ logger.exception(e)
274
+ raise HTTPException(
275
+ status_code=500, detail="Failed to delete proposal analysis."
276
+ )
277
+
278
+ async def delete_proposal_analysis_by_proposal_and_id(
279
+ self, proposal_id: str = Path(...), id: str = Path(...)
280
  ):
281
  async with self.service() as service:
282
  try:
 
 
 
 
 
283
  result = await service.delete_proposal_analysis(
284
+ proposal_id=proposal_id, id=id
285
  )
286
  return DeleteResponse(status="success")
287
  except Exception as e: