PupaClic commited on
Commit
75d92aa
·
1 Parent(s): 7ff20d3

feat(barrier-sizes): add CRUD operations and update associations for barrier sizes

Browse files
.env.example ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AquaBarrier Core API Environment Configuration Template
2
+ # Copy this file to .env and update the values
3
+
4
+ # Security Settings (REQUIRED)
5
+ SECRET_KEY=your-secret-key-here
6
+ JWT_ALGORITHM=HS256
7
+ ACCESS_TOKEN_EXPIRE_MINUTES=15
8
+ REFRESH_TOKEN_EXPIRE_DAYS=7
9
+
10
+ # SQL Server Database Configuration (REQUIRED)
11
+ SQLSERVER_USER=your-db-username
12
+ SQLSERVER_PASSWORD=your-db-password
13
+ SQLSERVER_HOST=localhost
14
+ SQLSERVER_PORT=1433
15
+ SQLSERVER_DB=your-database-name
16
+ SQLSERVER_DRIVER=ODBC Driver 18 for SQL Server
17
+
18
+ # Application Settings (OPTIONAL)
19
+ APP_NAME=AquaBarrier Core API
20
+ API_V1_STR=/api/v1
21
+ CORS_ORIGINS=*
22
+ LOG_LEVEL=INFO
app/controllers/bidders.py CHANGED
@@ -205,6 +205,47 @@ def create_barrier_size(
205
 
206
 
207
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  @router.get(
209
  "/{bidder_id}/barrier-sizes",
210
  response_model=List[BidderBarrierSizeDetail],
@@ -344,19 +385,22 @@ def update_barrier_size(
344
  result = barrier_size_service.update_barrier_with_association(
345
  db=db,
346
  barrier_size_id=id,
347
- height=barrier_update.height,
348
- width=barrier_update.width,
349
- length=barrier_update.length,
350
- cable_units=barrier_update.cable_units,
351
- price=barrier_update.price,
352
- is_standard=barrier_update.is_standard,
353
  inventory_id=barrier_update.inventory_id,
354
  install_advisor_fees=barrier_update.install_advisor_fees,
355
  bidder_id=barrier_update.bidder_id
356
  )
357
 
358
  if not result:
359
- raise HTTPException(status_code=404, detail="Barrier size not found")
 
 
 
360
 
361
  logger.info(f"Successfully updated barrier size {id}")
362
  return result
 
205
 
206
 
207
 
208
+ @router.get(
209
+ "/barrier-sizes/all",
210
+ response_model=List[BarrierSizesOut],
211
+ summary="Get all barrier sizes (for debugging)",
212
+ response_description="List of all barrier sizes in the system"
213
+ )
214
+ def get_all_barrier_sizes(db: Session = Depends(get_db)):
215
+ """Get all barrier sizes in the system (for debugging purposes)"""
216
+ try:
217
+ barrier_sizes = barrier_size_service.get_all(db, skip=0, limit=50)
218
+ logger.info(f"Found {len(barrier_sizes)} barrier sizes in database")
219
+ return barrier_sizes
220
+ except Exception as e:
221
+ logger.error(f"Error getting all barrier sizes: {e}")
222
+ raise HTTPException(
223
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
224
+ detail="Failed to get barrier sizes"
225
+ )
226
+
227
+ @router.get(
228
+ "/barrier-sizes/{barrier_size_id}",
229
+ response_model=BarrierSizesOut,
230
+ summary="Get a specific barrier size by ID (for debugging)",
231
+ response_description="Specific barrier size details"
232
+ )
233
+ def get_barrier_size_by_id(barrier_size_id: int, db: Session = Depends(get_db)):
234
+ """Get a specific barrier size by ID (for debugging purposes)"""
235
+ try:
236
+ barrier_size = barrier_size_service.get(db, barrier_size_id)
237
+ if not barrier_size:
238
+ raise HTTPException(status_code=404, detail=f"Barrier size {barrier_size_id} not found")
239
+ return barrier_size
240
+ except HTTPException:
241
+ raise
242
+ except Exception as e:
243
+ logger.error(f"Error getting barrier size {barrier_size_id}: {e}")
244
+ raise HTTPException(
245
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
246
+ detail="Failed to get barrier size"
247
+ )
248
+
249
  @router.get(
250
  "/{bidder_id}/barrier-sizes",
251
  response_model=List[BidderBarrierSizeDetail],
 
385
  result = barrier_size_service.update_barrier_with_association(
386
  db=db,
387
  barrier_size_id=id,
388
+ height=barrier_update.Height,
389
+ width=barrier_update.Width,
390
+ length=barrier_update.Lenght,
391
+ cable_units=barrier_update.CableUnits,
392
+ price=barrier_update.Price,
393
+ is_standard=barrier_update.IsStandard,
394
  inventory_id=barrier_update.inventory_id,
395
  install_advisor_fees=barrier_update.install_advisor_fees,
396
  bidder_id=barrier_update.bidder_id
397
  )
398
 
399
  if not result:
400
+ raise HTTPException(
401
+ status_code=404,
402
+ detail=f"Barrier size {id} not found. Please create the barrier size first using POST /api/v1/bidders/barrier-sizes"
403
+ )
404
 
405
  logger.info(f"Successfully updated barrier size {id}")
406
  return result
app/db/repositories/bidders_barrier_sizes_repo.py CHANGED
@@ -180,4 +180,98 @@ class BiddersBarrierSizesRepository:
180
  "barrier_size_id": barrier_size_id,
181
  "bidder_barrier_size_id": bidder_barrier_size_id,
182
  "message": f"Successfully inserted barrier size (ID: {barrier_size_id}) and bidder association (ID: {bidder_barrier_size_id})"
183
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  "barrier_size_id": barrier_size_id,
181
  "bidder_barrier_size_id": bidder_barrier_size_id,
182
  "message": f"Successfully inserted barrier size (ID: {barrier_size_id}) and bidder association (ID: {bidder_barrier_size_id})"
183
+ }
184
+
185
+ def get_by_barrier_size_and_bidder(self, barrier_size_id: int, bidder_id: int) -> List[dict]:
186
+ """Get association details for a specific barrier size and bidder combination"""
187
+ associations = (
188
+ self.db.query(BiddersBarrierSizes)
189
+ .filter(
190
+ BiddersBarrierSizes.BarrierSizeId == barrier_size_id,
191
+ BiddersBarrierSizes.BidderId == bidder_id
192
+ )
193
+ .all()
194
+ )
195
+
196
+ # Convert to dict format for easier consumption
197
+ return [
198
+ {
199
+ "Id": assoc.Id,
200
+ "InventoryId": assoc.InventoryId,
201
+ "BidderId": assoc.BidderId,
202
+ "BarrierSizeId": assoc.BarrierSizeId,
203
+ "InstallAdvisorFees": assoc.InstallAdvisorFees,
204
+ "IsStandard": assoc.IsStandard
205
+ }
206
+ for assoc in associations
207
+ ]
208
+
209
+ def update_or_create_association(
210
+ self,
211
+ barrier_size_id: int,
212
+ bidder_id: int,
213
+ inventory_id: Optional[int] = None,
214
+ install_advisor_fees: Optional[float] = None,
215
+ is_standard: Optional[bool] = None
216
+ ) -> BiddersBarrierSizes:
217
+ """Update existing association or create new one if it doesn't exist"""
218
+ # Try to find existing association
219
+ association = (
220
+ self.db.query(BiddersBarrierSizes)
221
+ .filter(
222
+ BiddersBarrierSizes.BarrierSizeId == barrier_size_id,
223
+ BiddersBarrierSizes.BidderId == bidder_id
224
+ )
225
+ .first()
226
+ )
227
+
228
+ if association:
229
+ # Update existing association
230
+ if inventory_id is not None:
231
+ association.InventoryId = inventory_id
232
+ if install_advisor_fees is not None:
233
+ association.InstallAdvisorFees = install_advisor_fees
234
+ if is_standard is not None:
235
+ association.IsStandard = is_standard
236
+
237
+ self.db.commit()
238
+ self.db.refresh(association)
239
+ return association
240
+ else:
241
+ # Create new association
242
+ return self.create_association(
243
+ bidder_id=bidder_id,
244
+ barrier_size_id=barrier_size_id,
245
+ inventory_id=inventory_id,
246
+ install_advisor_fees=install_advisor_fees,
247
+ is_standard=is_standard
248
+ )
249
+
250
+ def update_association_fields(
251
+ self,
252
+ barrier_size_id: int,
253
+ inventory_id: Optional[int] = None,
254
+ install_advisor_fees: Optional[float] = None,
255
+ is_standard: Optional[bool] = None
256
+ ) -> int:
257
+ """Update fields for all associations with a specific barrier size"""
258
+ associations = (
259
+ self.db.query(BiddersBarrierSizes)
260
+ .filter(BiddersBarrierSizes.BarrierSizeId == barrier_size_id)
261
+ .all()
262
+ )
263
+
264
+ updated_count = 0
265
+ for association in associations:
266
+ if inventory_id is not None:
267
+ association.InventoryId = inventory_id
268
+ if install_advisor_fees is not None:
269
+ association.InstallAdvisorFees = install_advisor_fees
270
+ if is_standard is not None:
271
+ association.IsStandard = is_standard
272
+ updated_count += 1
273
+
274
+ if updated_count > 0:
275
+ self.db.commit()
276
+
277
+ return updated_count
app/schemas/barrier_size.py CHANGED
@@ -18,7 +18,10 @@ class BarrierSizesCreate(BarrierSizesBase):
18
 
19
  class BarrierSizesUpdate(BarrierSizesBase):
20
  """Schema for updating a barrier size. All fields are optional."""
21
- pass
 
 
 
22
 
23
  class BarrierSizesOut(BarrierSizesBase):
24
  """Schema for barrier size output. Id is always present from database."""
 
18
 
19
  class BarrierSizesUpdate(BarrierSizesBase):
20
  """Schema for updating a barrier size. All fields are optional."""
21
+ # Additional fields for updating bidder associations
22
+ bidder_id: Optional[int] = None # Optional bidder ID for association updates
23
+ inventory_id: Optional[int] = None # Optional inventory ID for BiddersBarrierSizes
24
+ install_advisor_fees: Optional[float] = None # Optional install advisor fees
25
 
26
  class BarrierSizesOut(BarrierSizesBase):
27
  """Schema for barrier size output. Id is always present from database."""
app/services/barrier_size_service.py CHANGED
@@ -188,3 +188,118 @@ def create_barrier_with_association(
188
  logger.error(f"Error creating barrier size with association: {e}")
189
  db.rollback()
190
  raise
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
188
  logger.error(f"Error creating barrier size with association: {e}")
189
  db.rollback()
190
  raise
191
+
192
+ def update_barrier_with_association(
193
+ db: Session,
194
+ barrier_size_id: int,
195
+ height: Optional[float] = None,
196
+ width: Optional[float] = None,
197
+ length: Optional[float] = None,
198
+ cable_units: Optional[int] = None,
199
+ price: Optional[float] = None,
200
+ is_standard: Optional[bool] = None,
201
+ inventory_id: Optional[int] = None,
202
+ install_advisor_fees: Optional[float] = None,
203
+ bidder_id: Optional[int] = None
204
+ ):
205
+ """
206
+ Update barrier size and/or bidder association.
207
+
208
+ Updates both BarrierSizes table and BiddersBarrierSizes table if bidder_id is provided.
209
+ Only updates the fields that are provided (non-None values).
210
+
211
+ Args:
212
+ db: Database session
213
+ barrier_size_id: ID of the barrier size to update
214
+ height: New height value (optional)
215
+ width: New width value (optional)
216
+ length: New length value (optional)
217
+ cable_units: New cable units value (optional)
218
+ price: New price value (optional)
219
+ is_standard: New is_standard flag (optional)
220
+ inventory_id: New inventory ID for the bidder association (optional)
221
+ install_advisor_fees: New install advisor fees for the bidder association (optional)
222
+ bidder_id: Bidder ID for the association update (optional)
223
+
224
+ Returns:
225
+ dict: Updated barrier size information
226
+ """
227
+ try:
228
+ # First check if barrier size exists
229
+ logger.info(f"Checking if barrier size {barrier_size_id} exists in database")
230
+ barrier_size = get_barrier_size(db, barrier_size_id)
231
+ logger.info(f"Barrier size query result: {barrier_size}")
232
+
233
+ if not barrier_size:
234
+ logger.warning(f"Barrier size {barrier_size_id} not found in database")
235
+ # Get some sample barrier size IDs to help with debugging
236
+ sample_barrier_sizes = get_barrier_sizes(db, skip=0, limit=5)
237
+ sample_ids = [bs.Id for bs in sample_barrier_sizes] if sample_barrier_sizes else []
238
+ logger.info(f"Available barrier size IDs (sample): {sample_ids}")
239
+ return None
240
+
241
+ # Prepare update data for BarrierSizes table using correct schema field names
242
+ barrier_update_data = {}
243
+ if height is not None:
244
+ barrier_update_data['Height'] = height
245
+ if width is not None:
246
+ barrier_update_data['Width'] = width
247
+ if length is not None:
248
+ barrier_update_data['Lenght'] = length # Note: keeping the misspelled column name
249
+ if cable_units is not None:
250
+ barrier_update_data['CableUnits'] = cable_units
251
+ if price is not None:
252
+ barrier_update_data['Price'] = price
253
+ if is_standard is not None:
254
+ barrier_update_data['IsStandard'] = is_standard
255
+
256
+ # Update BarrierSizes table if there are fields to update
257
+ if barrier_update_data:
258
+ from app.schemas.barrier_size import BarrierSizesUpdate
259
+ barrier_update_obj = BarrierSizesUpdate(**barrier_update_data)
260
+ update_barrier_size(db, barrier_size_id, barrier_update_obj)
261
+
262
+ # Update BiddersBarrierSizes association if bidder-related fields are provided
263
+ if bidder_id is not None or inventory_id is not None or install_advisor_fees is not None:
264
+ bidders_barrier_repo = BiddersBarrierSizesRepository(db)
265
+
266
+ if bidder_id is not None:
267
+ # Update or create association for this bidder
268
+ bidders_barrier_repo.update_or_create_association(
269
+ barrier_size_id=barrier_size_id,
270
+ bidder_id=bidder_id,
271
+ inventory_id=inventory_id,
272
+ install_advisor_fees=install_advisor_fees
273
+ )
274
+ else:
275
+ # Update existing associations with new inventory_id or install_advisor_fees
276
+ bidders_barrier_repo.update_association_fields(
277
+ barrier_size_id=barrier_size_id,
278
+ inventory_id=inventory_id,
279
+ install_advisor_fees=install_advisor_fees
280
+ )
281
+
282
+ # Return updated barrier size information
283
+ updated_barrier = get_barrier_size(db, barrier_size_id)
284
+
285
+ # Get association details if bidder_id was provided
286
+ association_details = {}
287
+ if bidder_id is not None:
288
+ bidders_barrier_repo = BiddersBarrierSizesRepository(db)
289
+ associations = bidders_barrier_repo.get_by_barrier_size_and_bidder(barrier_size_id, bidder_id)
290
+ if associations:
291
+ association_details = associations[0] # Get the first/only association
292
+
293
+ result = {
294
+ "barrier_size": updated_barrier.__dict__ if updated_barrier else None,
295
+ "association": association_details,
296
+ "updated_fields": list(barrier_update_data.keys()) + (["bidder_association"] if bidder_id is not None else [])
297
+ }
298
+
299
+ logger.info(f"Successfully updated barrier size {barrier_size_id}: {result}")
300
+ return result
301
+
302
+ except Exception as e:
303
+ logger.error(f"Error updating barrier size with association: {e}")
304
+ db.rollback()
305
+ raise
test_barrier_update.py ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Script to test barrier size creation and update functionality
4
+ """
5
+ import requests
6
+ import json
7
+
8
+ BASE_URL = "http://127.0.0.1:9291/api/v1"
9
+
10
+ def create_barrier_size():
11
+ """Create a new barrier size and return its ID"""
12
+ print("Creating a new barrier size...")
13
+
14
+ # First, let's check what barrier sizes already exist
15
+ try:
16
+ response = requests.get(f"{BASE_URL}/bidders/barrier-sizes/all")
17
+ if response.status_code == 200:
18
+ existing_barriers = response.json()
19
+ print(f"Found {len(existing_barriers)} existing barrier sizes:")
20
+ for barrier in existing_barriers[:5]: # Show first 5
21
+ print(f" - ID: {barrier['Id']}, Height: {barrier.get('Height')}, Price: {barrier.get('Price')}")
22
+
23
+ if existing_barriers:
24
+ # Use the first existing barrier size for testing
25
+ barrier_id = existing_barriers[0]['Id']
26
+ print(f"Using existing barrier size ID: {barrier_id}")
27
+ return barrier_id
28
+ else:
29
+ print(f"Could not fetch existing barriers: {response.status_code}")
30
+ except Exception as e:
31
+ print(f"Error fetching existing barriers: {e}")
32
+
33
+ # Create a new barrier size
34
+ barrier_data = {
35
+ "Height": 10.0,
36
+ "Width": 12.0,
37
+ "Lenght": 25.0,
38
+ "CableUnits": 3,
39
+ "Price": 1500.00,
40
+ "IsStandard": True,
41
+ "bidder_id": 21378, # Using the same bidder ID from the original request
42
+ "inventory_id": 1
43
+ }
44
+
45
+ try:
46
+ response = requests.post(f"{BASE_URL}/bidders/barrier-sizes", json=barrier_data)
47
+ if response.status_code == 201:
48
+ result = response.json()
49
+ barrier_id = result['Id']
50
+ print(f"Successfully created barrier size with ID: {barrier_id}")
51
+ return barrier_id
52
+ else:
53
+ print(f"Failed to create barrier size: {response.status_code}")
54
+ print(f"Response: {response.text}")
55
+ return None
56
+ except Exception as e:
57
+ print(f"Error creating barrier size: {e}")
58
+ return None
59
+
60
+ def update_barrier_size(barrier_id):
61
+ """Update the barrier size"""
62
+ print(f"\\nUpdating barrier size {barrier_id}...")
63
+
64
+ update_data = {
65
+ "Height": 12,
66
+ "Width": 15,
67
+ "Lenght": 20,
68
+ "CableUnits": 1500,
69
+ "Price": 2500,
70
+ "IsStandard": True,
71
+ "bidder_id": 21378,
72
+ "inventory_id": 1
73
+ }
74
+
75
+ try:
76
+ response = requests.put(f"{BASE_URL}/bidders/barrier-sizes/{barrier_id}", json=update_data)
77
+ print(f"Update response status: {response.status_code}")
78
+ print(f"Update response: {response.text}")
79
+
80
+ if response.status_code == 200:
81
+ print("✅ Barrier size updated successfully!")
82
+ return True
83
+ else:
84
+ print("❌ Failed to update barrier size")
85
+ return False
86
+ except Exception as e:
87
+ print(f"Error updating barrier size: {e}")
88
+ return False
89
+
90
+ def test_specific_barrier_id():
91
+ """Test the specific barrier ID 32739 that was failing"""
92
+ print(f"\\nTesting specific barrier ID 32739...")
93
+
94
+ # First check if it exists
95
+ try:
96
+ response = requests.get(f"{BASE_URL}/bidders/barrier-sizes/32739")
97
+ print(f"Check response status: {response.status_code}")
98
+ if response.status_code == 200:
99
+ print("✅ Barrier size 32739 exists!")
100
+ return update_barrier_size(32739)
101
+ else:
102
+ print(f"❌ Barrier size 32739 does not exist: {response.text}")
103
+ return False
104
+ except Exception as e:
105
+ print(f"Error checking barrier size 32739: {e}")
106
+ return False
107
+
108
+ if __name__ == "__main__":
109
+ print("🧪 Testing Barrier Size Update Functionality")
110
+ print("=" * 50)
111
+
112
+ # Test the specific barrier ID that was failing
113
+ if not test_specific_barrier_id():
114
+ # If 32739 doesn't exist, create/use another barrier size
115
+ barrier_id = create_barrier_size()
116
+ if barrier_id:
117
+ update_barrier_size(barrier_id)
118
+ else:
119
+ print("❌ Could not create or find a barrier size to test with")