Fix: Bulk customer rate update using request body (v1.3.53)

Fixed API endpoint to accept JSON request body instead of query params:
- Added TModuleBulkRateUpdate Pydantic model
- Changed endpoint to accept request body
- Fixed parameter references to use request.customer_ids and request.hourly_rate
- Added migration for hourly_rate_updated and time_card_toggled event types

Resolves: 'Not Found' error and audit log constraint violations
This commit is contained in:
Christian 2025-12-23 14:39:57 +01:00
parent 246ad27fe3
commit 641698be8b
3 changed files with 32 additions and 17 deletions

View File

@ -30,6 +30,12 @@ class TModuleCustomerCreate(TModuleCustomerBase):
vtiger_data: Optional[dict] = Field(default_factory=dict) vtiger_data: Optional[dict] = Field(default_factory=dict)
class TModuleBulkRateUpdate(BaseModel):
"""Model for bulk customer hourly rate update"""
customer_ids: List[int] = Field(..., min_length=1, description="List of customer IDs to update")
hourly_rate: Decimal = Field(..., ge=0, description="New hourly rate in DKK")
class TModuleCustomer(TModuleCustomerBase): class TModuleCustomer(TModuleCustomerBase):
"""Full customer model with DB fields""" """Full customer model with DB fields"""
id: int id: int

View File

@ -26,7 +26,8 @@ from app.timetracking.backend.models import (
TModuleEconomicExportResult, TModuleEconomicExportResult,
TModuleMetadata, TModuleMetadata,
TModuleUninstallRequest, TModuleUninstallRequest,
TModuleUninstallResult TModuleUninstallResult,
TModuleBulkRateUpdate
) )
from app.timetracking.backend.vtiger_sync import vtiger_service from app.timetracking.backend.vtiger_sync import vtiger_service
from app.timetracking.backend.wizard import wizard from app.timetracking.backend.wizard import wizard
@ -690,14 +691,13 @@ async def update_customer_hourly_rate(customer_id: int, hourly_rate: float, user
@router.post("/customers/bulk-update-rate", tags=["Customers"]) @router.post("/customers/bulk-update-rate", tags=["Customers"])
async def bulk_update_customer_hourly_rates( async def bulk_update_customer_hourly_rates(
customer_ids: List[int], request: TModuleBulkRateUpdate,
hourly_rate: float,
user_id: Optional[int] = None user_id: Optional[int] = None
): ):
""" """
Opdater timepris for flere kunder én gang. Opdater timepris for flere kunder én gang.
Args: Request body:
customer_ids: Liste af kunde-ID'er customer_ids: Liste af kunde-ID'er
hourly_rate: Ny timepris i DKK (f.eks. 850.00) hourly_rate: Ny timepris i DKK (f.eks. 850.00)
@ -705,16 +705,9 @@ async def bulk_update_customer_hourly_rates(
Antal opdaterede kunder Antal opdaterede kunder
""" """
try: try:
from decimal import Decimal # Validate inputs (already validated by Pydantic)
customer_ids = request.customer_ids
# Validate inputs rate_decimal = request.hourly_rate
if not customer_ids:
raise HTTPException(status_code=400, detail="No customers selected")
if hourly_rate < 0:
raise HTTPException(status_code=400, detail="Hourly rate must be positive")
rate_decimal = Decimal(str(hourly_rate))
# Update all selected customers # Update all selected customers
execute_update( execute_update(
@ -731,15 +724,15 @@ async def bulk_update_customer_hourly_rates(
entity_type="customer", entity_type="customer",
entity_id=str(customer_id), entity_id=str(customer_id),
event_type="hourly_rate_updated", event_type="hourly_rate_updated",
details={"hourly_rate": float(hourly_rate), "bulk_update": True}, details={"hourly_rate": float(rate_decimal), "bulk_update": True},
user_id=user_id user_id=user_id
) )
logger.info(f"✅ Bulk updated hourly rate for {updated_count} customers to {hourly_rate} DKK") logger.info(f"✅ Bulk updated hourly rate for {updated_count} customers to {rate_decimal} DKK")
return { return {
"updated": updated_count, "updated": updated_count,
"hourly_rate": float(hourly_rate) "hourly_rate": float(rate_decimal)
} }
except HTTPException: except HTTPException:

View File

@ -0,0 +1,16 @@
-- Migration: Add customer-related event types to tmodule_sync_log
-- Version: v1.3.52
-- Description: Add 'hourly_rate_updated' and 'time_card_toggled' event types
-- Drop existing constraint
ALTER TABLE tmodule_sync_log DROP CONSTRAINT IF EXISTS check_event_type;
-- Add new constraint with additional event types
ALTER TABLE tmodule_sync_log ADD CONSTRAINT check_event_type CHECK (event_type IN (
'sync_started', 'sync_completed', 'sync_failed',
'approval', 'rejection', 'bulk_approval',
'order_created', 'order_updated', 'order_cancelled',
'export_started', 'export_completed', 'export_failed',
'module_installed', 'module_uninstalled',
'hourly_rate_updated', 'time_card_toggled'
));