diff --git a/app/timetracking/backend/models.py b/app/timetracking/backend/models.py index a283b6a..15285ad 100644 --- a/app/timetracking/backend/models.py +++ b/app/timetracking/backend/models.py @@ -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 diff --git a/app/timetracking/backend/router.py b/app/timetracking/backend/router.py index 2ce01b6..646d2da 100644 --- a/app/timetracking/backend/router.py +++ b/app/timetracking/backend/router.py @@ -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: diff --git a/migrations/051_add_customer_event_types.sql b/migrations/051_add_customer_event_types.sql new file mode 100644 index 0000000..70f35ff --- /dev/null +++ b/migrations/051_add_customer_event_types.sql @@ -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' +));