kaauh_ats/recruitment/views_integration.py

238 lines
8.0 KiB
Python

import json
from datetime import datetime
import logging
from typing import Dict, Any
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from django.utils.decorators import method_decorator
from django.views import View
from django.core.exceptions import ValidationError
from django.db import transaction
from .models import Source, JobPosting, IntegrationLog
from .erp_integration_service import ERPIntegrationService
class ERPIntegrationView(View):
"""
API endpoint for receiving job requests from ERP system
"""
def get(self, request):
"""Health check endpoint"""
return JsonResponse({
'status': 'success',
'message': 'ERP Integration API is available',
'version': '1.0.0',
'supported_actions': ['create_job', 'update_job']
})
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
def post(self, request):
"""Handle POST requests from ERP system"""
try:
# Start timing for processing
start_time = datetime.now()
# Get request data
if request.content_type == 'application/json':
try:
data = json.loads(request.body.decode('utf-8'))
except json.JSONDecodeError:
return JsonResponse({
'status': 'error',
'message': 'Invalid JSON data'
}, status=400)
else:
data = request.POST.dict()
# Get action from request
action = data.get('action', '').lower()
if not action:
return JsonResponse({
'status': 'error',
'message': 'Action is required'
}, status=400)
# Validate action
valid_actions = ['create_job', 'update_job']
if action not in valid_actions:
return JsonResponse({
'status': 'error',
'message': f'Invalid action. Must be one of: {", ".join(valid_actions)}'
}, status=400)
# Get source identifier
source_name = data.get('source_name')
source_id = data.get('source_id')
# Find the source
source = None
if source_id:
source = Source.objects.filter(id=source_id).first()
elif source_name:
source = Source.objects.filter(name=source_name).first()
if not source:
return JsonResponse({
'status': 'error',
'message': 'Source not found'
}, status=404)
job_id = data.get('job_id')
if not job_id:
return JsonResponse({
'status': 'error',
'message': 'Job ID is required and must be unique'
})
if JobPosting.objects.filter(internal_job_id=job_id).exists():
return JsonResponse({
'status': 'error',
'message': 'Job with this ID already exists'
}, status=400)
# Create integration service
service = ERPIntegrationService(source)
# Validate request
is_valid, error_msg = service.validate_request(request)
if not is_valid:
service.log_integration_request(request, 'ERROR', error_message=error_msg, status_code='403')
return JsonResponse({
'status': 'error',
'message': error_msg
}, status=403)
# Log the request
service.log_integration_request(request, 'REQUEST')
# Process based on action
if action == 'create_job':
result, error_msg = self._create_job(service, data)
elif action == 'update_job':
result, error_msg = self._update_job(service, data)
# Calculate processing time
processing_time = (datetime.now() - start_time).total_seconds()
# Log the result
status_code = '200' if not error_msg else '400'
service.log_integration_request(
request,
'RESPONSE' if not error_msg else 'ERROR',
response_data={'result': result} if result else {},
status_code=status_code,
processing_time=processing_time,
error_message=error_msg
)
# Return response
if error_msg:
return JsonResponse({
'status': 'error',
'message': error_msg,
'processing_time': processing_time
}, status=400)
return JsonResponse({
'status': 'success',
'message': f'Job {action.replace("_", " ")} successfully',
'data': result,
'processing_time': processing_time
})
except Exception as e:
logger = logging.getLogger(__name__)
logger.error(f"Error in ERP integration: {str(e)}", exc_info=True)
return JsonResponse({
'status': 'error',
'message': 'Internal server error'
}, status=500)
@transaction.atomic
def _create_job(self, service: ERPIntegrationService, data: Dict[str, Any]) -> tuple[Dict[str, Any], str]:
"""Create a new job from ERP data"""
# Validate ERP data
# print(data)
is_valid, error_msg = service.validate_erp_data(data)
if not is_valid:
return None, error_msg
# Create job from ERP data
job, error_msg = service.create_job_from_erp(data)
if error_msg:
return None, error_msg
# Prepare response data
response_data = {
'job_id': job.internal_job_id,
'title': job.title,
'status': job.status,
'created_at': job.created_at.isoformat(),
'message': 'Job created successfully'
}
return response_data, ""
@transaction.atomic
def _update_job(self, service: ERPIntegrationService, data: Dict[str, Any]) -> tuple[Dict[str, Any], str]:
"""Update an existing job from ERP data"""
# Get job ID from request
job_id = data.get('job_id')
if not job_id:
return None, "Job ID is required for update"
# Validate ERP data
is_valid, error_msg = service.validate_erp_data(data)
if not is_valid:
return None, error_msg
# Update job from ERP data
job, error_msg = service.update_job_from_erp(job_id, data)
if error_msg:
return None, error_msg
# Prepare response data
response_data = {
'job_id': job.internal_job_id,
'title': job.title,
'status': job.status,
'updated_at': job.updated_at.isoformat(),
'message': 'Job updated successfully'
}
return response_data, ""
# Specific endpoint for creating jobs (POST only)
@require_http_methods(["POST"])
@csrf_exempt
def erp_create_job_view(request):
"""View for creating jobs from ERP (simpler endpoint)"""
view = ERPIntegrationView()
return view.post(request)
# Specific endpoint for updating jobs (POST only)
@require_http_methods(["POST"])
@csrf_exempt
def erp_update_job_view(request):
"""View for updating jobs from ERP (simpler endpoint)"""
view = ERPIntegrationView()
return view.post(request)
# Health check endpoint
@require_http_methods(["GET"])
def erp_integration_health(request):
"""Health check endpoint for ERP integration"""
return JsonResponse({
'status': 'healthy',
'timestamp': datetime.now().isoformat(),
'services': {
'erp_integration': 'available',
'database': 'connected'
}
})