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:
parent
246ad27fe3
commit
641698be8b
@ -30,6 +30,12 @@ class TModuleCustomerCreate(TModuleCustomerBase):
|
||||
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):
|
||||
"""Full customer model with DB fields"""
|
||||
id: int
|
||||
|
||||
@ -26,7 +26,8 @@ from app.timetracking.backend.models import (
|
||||
TModuleEconomicExportResult,
|
||||
TModuleMetadata,
|
||||
TModuleUninstallRequest,
|
||||
TModuleUninstallResult
|
||||
TModuleUninstallResult,
|
||||
TModuleBulkRateUpdate
|
||||
)
|
||||
from app.timetracking.backend.vtiger_sync import vtiger_service
|
||||
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"])
|
||||
async def bulk_update_customer_hourly_rates(
|
||||
customer_ids: List[int],
|
||||
hourly_rate: float,
|
||||
request: TModuleBulkRateUpdate,
|
||||
user_id: Optional[int] = None
|
||||
):
|
||||
"""
|
||||
Opdater timepris for flere kunder på én gang.
|
||||
|
||||
Args:
|
||||
Request body:
|
||||
customer_ids: Liste af kunde-ID'er
|
||||
hourly_rate: Ny timepris i DKK (f.eks. 850.00)
|
||||
|
||||
@ -705,16 +705,9 @@ async def bulk_update_customer_hourly_rates(
|
||||
Antal opdaterede kunder
|
||||
"""
|
||||
try:
|
||||
from decimal import Decimal
|
||||
|
||||
# Validate inputs
|
||||
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))
|
||||
# Validate inputs (already validated by Pydantic)
|
||||
customer_ids = request.customer_ids
|
||||
rate_decimal = request.hourly_rate
|
||||
|
||||
# Update all selected customers
|
||||
execute_update(
|
||||
@ -731,15 +724,15 @@ async def bulk_update_customer_hourly_rates(
|
||||
entity_type="customer",
|
||||
entity_id=str(customer_id),
|
||||
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
|
||||
)
|
||||
|
||||
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 {
|
||||
"updated": updated_count,
|
||||
"hourly_rate": float(hourly_rate)
|
||||
"hourly_rate": float(rate_decimal)
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
|
||||
16
migrations/051_add_customer_event_types.sql
Normal file
16
migrations/051_add_customer_event_types.sql
Normal 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'
|
||||
));
|
||||
Loading…
Reference in New Issue
Block a user