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)
|
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
|
||||||
|
|||||||
@ -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 på én gang.
|
Opdater timepris for flere kunder på é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:
|
||||||
|
|||||||
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