# views.py from django.views.generic import FormView, ListView, DetailView, CreateView, UpdateView from django.views.generic.edit import FormView, BaseUpdateView from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.decorators import permission_required from django.contrib import messages from django.shortcuts import render, redirect, get_object_or_404 from django.urls import reverse_lazy from django.http import HttpResponse, HttpResponseRedirect from django.views import View from django.utils import timezone from django.contrib.sites.shortcuts import get_current_site from django.template.loader import render_to_string from django.core.mail import send_mail from django.conf import settings from django.db import IntegrityError from .models import Event, Prospect, EmailTracker, EmailCampaign, EventType from .filters import ProspectFilter from .forms import ProspectForm, CSVImportForm, BulkEmailForm, EventForm from .mixins import CRMAccessMixin import csv from io import TextIOWrapper from datetime import datetime @permission_required('crm.view_crm', raise_exception=True) def prospect_form(request, pk=None): # Get the prospect instance if pk is provided (edit mode) prospect = get_object_or_404(Prospect, pk=pk) if pk else None if request.method == 'POST': form = ProspectForm(request.POST, instance=prospect) if form.is_valid(): prospect = form.save(commit=False) if not pk: # New prospect prospect.created_by = request.user prospect.modified_by = request.user prospect.save() action = 'updated' if pk else 'added' messages.success(request, f'Prospect {prospect.entity_name} has been {action} successfully!') return redirect('crm:events') else: form = ProspectForm(instance=prospect) context = { 'form': form, 'is_edit': prospect is not None, 'first_title': prospect.entity_name if prospect else 'Add Prospect', 'second_title': prospect.full_name() if prospect else None } return render(request, 'crm/prospect_form.html', context) # @permission_required('crm.view_crm', raise_exception=True) # def add_prospect(request): # if request.method == 'POST': # entity_name = request.POST.get('entity_name') # first_name = request.POST.get('first_name') # last_name = request.POST.get('last_name') # email = request.POST.get('email') # phone = request.POST.get('phone') # address = request.POST.get('address') # zip_code = request.POST.get('zip_code') # city = request.POST.get('city') # # region = request.POST.get('region') # try: # prospect = Prospect.objects.create( # entity_name=entity_name, # first_name=first_name, # last_name=last_name, # email=email, # phone=phone, # address=address, # zip_code=zip_code, # city=city, # # region=region, # created_by=request.user, # modified_by=request.user # ) # messages.success(request, f'Prospect {name} has been added successfully!') # return redirect('crm:events') # or wherever you want to redirect after success # except Exception as e: # messages.error(request, f'Error adding prospect: {str(e)}') # return render(request, 'crm/add_prospect.html') class EventCreateView(CRMAccessMixin, CreateView): model = Event form_class = EventForm template_name = 'crm/event_form.html' success_url = reverse_lazy('crm:planned_events') def get_initial(self): initial = super().get_initial() prospect_id = self.kwargs.get('prospect_id') if prospect_id: initial['prospects'] = [prospect_id] return initial def form_valid(self, form): form.instance.created_by = self.request.user form.instance.modified_by = self.request.user return super().form_valid(form) class EditEventView(CRMAccessMixin, UpdateView): model = Event form_class = EventForm template_name = 'crm/event_form.html' success_url = reverse_lazy('crm:planned_events') def form_valid(self, form): form.instance.modified_by = self.request.user response = super().form_valid(form) messages.success(self.request, 'Event updated successfully!') return response class StartEventView(CRMAccessMixin, BaseUpdateView): model = Event http_method_names = ['post', 'get'] def get(self, request, *args, **kwargs): return self.post(request, *args, **kwargs) def post(self, request, *args, **kwargs): event = get_object_or_404(Event, pk=kwargs['pk'], status='PLANNED') event.status = 'ACTIVE' event.save() if event.type == 'MAIL': return HttpResponseRedirect( reverse_lazy('crm:setup_email_campaign', kwargs={'event_id': event.id}) ) elif event.type == 'SMS': return HttpResponseRedirect( reverse_lazy('crm:setup_sms_campaign', kwargs={'event_id': event.id}) ) elif event.type == 'PRESS': return HttpResponseRedirect( reverse_lazy('crm:setup_press_release', kwargs={'event_id': event.id}) ) messages.success(request, 'Event started successfully!') return HttpResponseRedirect(reverse_lazy('crm:planned_events')) class EventListView(CRMAccessMixin, ListView): model = Event template_name = 'crm/events.html' context_object_name = 'events' # We won't use this since we're providing custom context def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['planned_events'] = Event.objects.filter( status='PLANNED' ).order_by('date') context['completed_events'] = Event.objects.filter( status='COMPLETED' ).order_by('-date') return context class ProspectListView(CRMAccessMixin, ListView): model = Prospect template_name = 'crm/prospect_list.html' context_object_name = 'prospects' filterset_class = ProspectFilter def get_queryset(self): return super().get_queryset().prefetch_related('prospectstatus_set__status') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['filter'] = self.filterset_class( self.request.GET, queryset=self.get_queryset() ) return context class CSVImportView(CRMAccessMixin, FormView): template_name = 'crm/csv_import.html' form_class = CSVImportForm success_url = reverse_lazy('prospect-list') def form_valid(self, form): csv_file = TextIOWrapper( form.cleaned_data['csv_file'].file, encoding='utf-8-sig' # Handle potential BOM in CSV ) reader = csv.reader(csv_file, delimiter=';') # Using semicolon delimiter # Skip header if exists next(reader, None) created_count = 0 updated_count = 0 error_count = 0 for row in reader: try: if len(row) < 10: # Ensure we have enough columns continue # Extract data from correct columns entity_name = row[0].strip() last_name = row[1].strip() first_name = row[2].strip() email = row[3].strip() phone = row[4].strip() zip_code = row[8].strip() city = row[9].strip() # Try to update existing prospect or create new one prospect, created = Prospect.objects.update_or_create( email=email, # Use email as unique identifier defaults={ 'entity_name': entity_name, 'first_name': first_name, 'last_name': last_name, 'phone': phone, 'zip_code': zip_code, 'city': city, 'modified_by': self.request.user, } ) if created: prospect.created_by = self.request.user prospect.save() created_count += 1 else: updated_count += 1 except Exception as e: error_count += 1 messages.error( self.request, f"Error processing row with email {email}: {str(e)}" ) # Add success message messages.success( self.request, f"Import completed: {created_count} created, {updated_count} updated, {error_count} errors" ) return super().form_valid(form) class SendBulkEmailView(CRMAccessMixin, FormView): template_name = 'crm/send_bulk_email.html' form_class = BulkEmailForm success_url = reverse_lazy('crm:prospect-list') def form_valid(self, form): prospects = form.cleaned_data['prospects'] subject = form.cleaned_data['subject'] content = form.cleaned_data['content'] # Create Event for this email campaign event = Event.objects.create( date=datetime.now(), type=EventType.MAILING, description=f"Bulk email: {subject}", status='COMPLETED', created_by=self.request.user, modified_by=self.request.user ) event.prospects.set(prospects) # Send emails success_count, error_count = send_bulk_email( subject=subject, content=content, prospects=prospects ) # Show result message messages.success( self.request, f"Sent {success_count} emails successfully. {error_count} failed." ) return super().form_valid(form)