diff --git a/app/customers/backend/router.py b/app/customers/backend/router.py index bb19ed8..c68bcf5 100644 --- a/app/customers/backend/router.py +++ b/app/customers/backend/router.py @@ -11,6 +11,7 @@ import logging from app.core.database import execute_query, execute_query_single from app.services.cvr_service import get_cvr_service +from app.services.customer_activity_logger import CustomerActivityLogger logger = logging.getLogger(__name__) @@ -413,6 +414,9 @@ async def create_customer(customer: CustomerCreate): logger.info(f"✅ Created customer {customer_id}: {customer.name}") + # Log activity + CustomerActivityLogger.log_created(customer_id, customer.name) + # Fetch and return created customer created = execute_query_single( "SELECT * FROM customers WHERE id = %s", @@ -429,7 +433,7 @@ async def update_customer(customer_id: int, update: CustomerUpdate): """Update customer information""" # Verify customer exists existing = execute_query_single( - "SELECT id FROM customers WHERE id = %s", + "SELECT id, name FROM customers WHERE id = %s", (customer_id,)) if not existing: raise HTTPException(status_code=404, detail="Customer not found") @@ -439,6 +443,8 @@ async def update_customer(customer_id: int, update: CustomerUpdate): params = [] update_dict = update.dict(exclude_unset=True) + fields_changed = list(update_dict.keys()) + for field, value in update_dict.items(): updates.append(f"{field} = %s") params.append(value) @@ -454,6 +460,9 @@ async def update_customer(customer_id: int, update: CustomerUpdate): execute_update(query, tuple(params)) logger.info(f"✅ Updated customer {customer_id}") + # Log activity + CustomerActivityLogger.log_updated(customer_id, existing['name'], fields_changed) + # Fetch and return updated customer updated = execute_query_single( "SELECT * FROM customers WHERE id = %s", diff --git a/app/services/customer_activity_logger.py b/app/services/customer_activity_logger.py new file mode 100644 index 0000000..2f41601 --- /dev/null +++ b/app/services/customer_activity_logger.py @@ -0,0 +1,164 @@ +""" +Customer Activity Logger +Helper service for logging all customer-related events +""" + +import logging +from typing import Optional, Dict, Any +import json +from app.core.database import execute_insert + +logger = logging.getLogger(__name__) + + +class CustomerActivityLogger: + """Centralized customer activity logging""" + + @staticmethod + def log( + customer_id: int, + activity_type: str, + description: str, + user_id: Optional[int] = 1, # Default to system user + metadata: Optional[Dict[str, Any]] = None + ) -> Optional[int]: + """ + Log a customer activity event + + Args: + customer_id: Customer ID + activity_type: Type of activity (customer_updated, contact_added, subscription_changed, etc.) + description: Human-readable description + user_id: User ID performing action (1 = system) + metadata: Additional event data as dict + + Returns: + Activity ID or None on failure + """ + try: + # Store metadata as JSON string if provided + metadata_str = json.dumps(metadata) if metadata else None + + activity_id = execute_insert( + """INSERT INTO customer_activities + (customer_id, activity_type, description, user_id, metadata) + VALUES (%s, %s, %s, %s, %s) + RETURNING id""", + (customer_id, activity_type, description, user_id, metadata_str) + ) + + logger.debug(f"📝 Logged customer activity: {activity_type} for customer {customer_id}") + return activity_id + + except Exception as e: + logger.error(f"❌ Failed to log customer activity: {e}") + return None + + # Specific activity types + + @staticmethod + def log_created(customer_id: int, customer_name: str, user_id: Optional[int] = 1): + """Log customer creation""" + return CustomerActivityLogger.log( + customer_id=customer_id, + activity_type='customer_created', + description=f'Kunde oprettet: {customer_name}', + user_id=user_id + ) + + @staticmethod + def log_updated(customer_id: int, customer_name: str, fields_changed: list, user_id: Optional[int] = 1): + """Log customer update""" + fields_str = ', '.join(fields_changed) + return CustomerActivityLogger.log( + customer_id=customer_id, + activity_type='customer_updated', + description=f'Kunde opdateret: {customer_name} - Ændrede felter: {fields_str}', + user_id=user_id, + metadata={'fields_changed': fields_changed} + ) + + @staticmethod + def log_deleted(customer_id: int, customer_name: str, user_id: Optional[int] = 1): + """Log customer deletion""" + return CustomerActivityLogger.log( + customer_id=customer_id, + activity_type='customer_deleted', + description=f'Kunde slettet: {customer_name}', + user_id=user_id + ) + + @staticmethod + def log_contact_added(customer_id: int, contact_name: str, user_id: Optional[int] = 1): + """Log contact added""" + return CustomerActivityLogger.log( + customer_id=customer_id, + activity_type='contact_added', + description=f'Kontaktperson tilføjet: {contact_name}', + user_id=user_id + ) + + @staticmethod + def log_contact_updated(customer_id: int, contact_name: str, user_id: Optional[int] = 1): + """Log contact updated""" + return CustomerActivityLogger.log( + customer_id=customer_id, + activity_type='contact_updated', + description=f'Kontaktperson opdateret: {contact_name}', + user_id=user_id + ) + + @staticmethod + def log_contact_deleted(customer_id: int, contact_name: str, user_id: Optional[int] = 1): + """Log contact deleted""" + return CustomerActivityLogger.log( + customer_id=customer_id, + activity_type='contact_deleted', + description=f'Kontaktperson slettet: {contact_name}', + user_id=user_id + ) + + @staticmethod + def log_subscription_created(customer_id: int, subscription_name: str, user_id: Optional[int] = 1): + """Log subscription created""" + return CustomerActivityLogger.log( + customer_id=customer_id, + activity_type='subscription_created', + description=f'Abonnement oprettet: {subscription_name}', + user_id=user_id + ) + + @staticmethod + def log_subscription_updated(customer_id: int, subscription_name: str, user_id: Optional[int] = 1): + """Log subscription updated""" + return CustomerActivityLogger.log( + customer_id=customer_id, + activity_type='subscription_updated', + description=f'Abonnement opdateret: {subscription_name}', + user_id=user_id + ) + + @staticmethod + def log_subscription_deleted(customer_id: int, subscription_name: str, user_id: Optional[int] = 1): + """Log subscription deleted""" + return CustomerActivityLogger.log( + customer_id=customer_id, + activity_type='subscription_deleted', + description=f'Abonnement slettet: {subscription_name}', + user_id=user_id + ) + + @staticmethod + def log_sync(customer_id: int, source: str, details: str, user_id: Optional[int] = 1): + """Log external sync""" + return CustomerActivityLogger.log( + customer_id=customer_id, + activity_type=f'{source}_sync', + description=f'{source} synkronisering: {details}', + user_id=user_id, + metadata={'source': source} + ) + + +# Export singleton instance +customer_activity_logger = CustomerActivityLogger()