rename bizdev into biz

apikeys
Laurent 4 months ago
parent 0ecf9c1fff
commit c1a62cf4e6
  1. 2
      api/urls.py
  2. 6
      api/views.py
  3. 0
      biz/__init__.py
  4. 18
      biz/admin.py
  5. 6
      biz/admin_urls.py
  6. 4
      biz/apps.py
  7. 0
      biz/filters.py
  8. 0
      biz/forms.py
  9. 25
      biz/migrations/0001_initial.py
  10. 0
      biz/migrations/__init__.py
  11. 4
      biz/mixins.py
  12. 0
      biz/models.py
  13. 0
      biz/serializers.py
  14. 0
      biz/services.py
  15. 0
      biz/templates/admin/biz/email_users.html
  16. 0
      biz/templates/admin/biz/prospect/change_list.html
  17. 0
      biz/templates/admin/biz/prospect/import_file.html
  18. 0
      biz/templates/admin/biz/select_email_template.html
  19. 2
      biz/templates/biz/add_prospect.html
  20. 0
      biz/templates/biz/base.html
  21. 2
      biz/templates/biz/csv_import.html
  22. 4
      biz/templates/biz/event_form.html
  23. 4
      biz/templates/biz/event_row.html
  24. 18
      biz/templates/biz/events.html
  25. 2
      biz/templates/biz/prospect_form.html
  26. 14
      biz/templates/biz/prospect_list.html
  27. 4
      biz/templates/biz/send_bulk_email.html
  28. 0
      biz/templatetags/__init__.py
  29. 7
      biz/templatetags/crm_tags.py
  30. 0
      biz/tests.py
  31. 2
      biz/urls.py
  32. 54
      biz/views.py
  33. 1
      bizdev/_instructions/base.md
  34. 23
      bizdev/migrations/0002_activity_declination_reason_alter_activity_status.py
  35. 52
      bizdev/migrations/0003_alter_activity_options_alter_prospect_options_and_more.py
  36. 18
      bizdev/migrations/0004_alter_emailtemplate_id.py
  37. 6
      bizdev/static/crm/js/prospects.js
  38. 7
      bizdev/templatetags/crm_tags.py
  39. 2
      padelclub_backend/settings.py
  40. 2
      padelclub_backend/settings_app.py
  41. 2
      padelclub_backend/urls.py
  42. 2
      tournaments/templates/admin/tournaments/dashboard.html

@ -29,7 +29,7 @@ router.register(r'device-token', views.DeviceTokenViewSet)
router.register(r'data-access', DataAccessViewSet)
router.register(r'unregistered-teams', views.UnregisteredTeamViewSet)
router.register(r'unregistered-players', views.UnregisteredPlayerViewSet)
### bizdev
### biz
router.register(r'crm-prospects', views.CRMProspectViewSet)
router.register(r'crm-entities', views.CRMEntityViewSet)
router.register(r'crm-activities', views.CRMActivityViewSet)

@ -15,8 +15,8 @@ from django.shortcuts import get_object_or_404
from .serializers import ClubSerializer, CourtSerializer, DateIntervalSerializer, DrawLogSerializer, TournamentSerializer, UserSerializer, EventSerializer, RoundSerializer, GroupStageSerializer, MatchSerializer, TeamScoreSerializer, TeamRegistrationSerializer, PlayerRegistrationSerializer, PurchaseSerializer, ShortUserSerializer, FailedApiCallSerializer, LogSerializer, DeviceTokenSerializer, CustomUserSerializer, UnregisteredTeamSerializer, UnregisteredPlayerSerializer, ImageSerializer
from tournaments.models import Club, Tournament, CustomUser, Event, Round, GroupStage, Match, TeamScore, TeamRegistration, PlayerRegistration, Court, DateInterval, Purchase, FailedApiCall, Log, DeviceToken, DrawLog, UnregisteredTeam, UnregisteredPlayer, Image
from bizdev.serializers import CRMActivitySerializer, CRMProspectSerializer, CRMEntitySerializer
from bizdev.models import Activity, Prospect, Entity
from biz.serializers import CRMActivitySerializer, CRMProspectSerializer, CRMEntitySerializer
from biz.models import Activity, Prospect, Entity
from rest_framework import viewsets
from rest_framework.response import Response
@ -858,7 +858,7 @@ def get_fft_federal_clubs(request):
"club_markers": []
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
### bizdev
### biz
class CRMActivityViewSet(SoftDeleteViewSet):
queryset = Activity.objects.all()
serializer_class = CRMActivitySerializer

@ -91,7 +91,7 @@ def create_activity_for_prospect(modeladmin, request, queryset):
prospect = queryset.first()
# Build the URL with pre-populated fields
url = reverse('admin:bizdev_activity_add')
url = reverse('admin:biz_activity_add')
url += f'?prospect={prospect.id}'
return redirect(url)
create_activity_for_prospect.short_description = "Create activity"
@ -108,7 +108,7 @@ class ProspectAdmin(SyncedObjectAdmin):
list_filter = (ProspectStatusFilter, ProspectDeclineReasonFilter, 'creation_date', StaffUserFilter, 'source', ProspectProfileFilter)
search_fields = ('first_name', 'last_name', 'email', 'entities__name')
date_hierarchy = 'creation_date'
change_list_template = "admin/bizdev/prospect/change_list.html"
change_list_template = "admin/biz/prospect/change_list.html"
ordering = ['-last_update']
filter_horizontal = ['entities']
actions = ['send_email', create_activity_for_prospect, contacted_by_sms, mark_as_should_test, mark_as_testing, mark_as_customer, declined_too_expensive, declined_use_something_else]
@ -119,7 +119,7 @@ class ProspectAdmin(SyncedObjectAdmin):
if activities:
activity_links = []
for activity in activities:
url = f"/kingdom/bizdev/activity/{activity.id}/change/"
url = f"/kingdom/biz/activity/{activity.id}/change/"
activity_links.append(f'<a href="{url}">{activity.html_desc()}</a>')
return format_html('<br>'.join(activity_links))
return "No events"
@ -139,8 +139,8 @@ class ProspectAdmin(SyncedObjectAdmin):
Prospect.objects.all().delete()
Activity.objects.all().delete()
messages.success(request, 'cleanup bizdev objects')
return redirect('admin:bizdev_prospect_changelist')
messages.success(request, 'cleanup biz objects')
return redirect('admin:biz_prospect_changelist')
def import_app_users(self, request):
users = CustomUser.objects.filter(origin=UserOrigin.APP)
@ -177,7 +177,7 @@ class ProspectAdmin(SyncedObjectAdmin):
created_count += 1
messages.success(request, f'Imported {created_count} app users into prospects')
return redirect('admin:bizdev_prospect_changelist')
return redirect('admin:biz_prospect_changelist')
def import_file(self, request):
"""
@ -190,7 +190,7 @@ class ProspectAdmin(SyncedObjectAdmin):
try:
result = self.import_csv(form.cleaned_data['file'], form.cleaned_data['source'])
messages.success(request, f'File imported successfully: {result}')
return redirect('admin:bizdev_prospect_changelist')
return redirect('admin:biz_prospect_changelist')
except Exception as e:
messages.error(request, f'Error importing file: {str(e)}')
else:
@ -205,7 +205,7 @@ class ProspectAdmin(SyncedObjectAdmin):
'opts': self.model._meta,
'has_change_permission': self.has_change_permission(request),
}
return render(request, 'admin/bizdev/prospect/import_file.html', context)
return render(request, 'admin/biz/prospect/import_file.html', context)
def import_csv(self, file, source):
"""
@ -350,7 +350,7 @@ class ProspectAdmin(SyncedObjectAdmin):
else:
form = EmailTemplateSelectionForm()
return render(request, 'admin/bizdev/select_email_template.html', {
return render(request, 'admin/biz/select_email_template.html', {
'prospects': queryset,
'form': form,
'title': 'Send Email to Prospects'

@ -63,8 +63,8 @@ def template(user, index):
return f'Bonjour {user.first_name}, \n\nJe te remercie d\'avoir téléchargé Padel Club. J\'ai pu voir que tu avais créé quelques tournois mais sans aller plus loin, est-ce que tu pourrais me dire ce qui t\'as freiné ?\n\nLaurent Morvillier'
urlpatterns = [
path('email_users/', email_users_view, name='bizdev_email_users'),
path('email_users_count/', email_users_count, name='bizdev_email_count'),
path('email_users_with_tournaments_count/', email_users_with_tournaments_count, name='bizdev_email_with_tournaments_count'),
path('email_users/', email_users_view, name='biz_email_users'),
path('email_users_count/', email_users_count, name='biz_email_count'),
path('email_users_with_tournaments_count/', email_users_with_tournaments_count, name='biz_email_with_tournaments_count'),
path('email_users_with_tournaments/', email_users_with_tournaments, name='email_users_with_tournaments'),
]

@ -1,5 +1,5 @@
from django.apps import AppConfig
class bizdevConfig(AppConfig):
class BizConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'bizdev'
name = 'biz'

@ -1,7 +1,8 @@
# Generated by Django 5.1 on 2025-07-09 15:18
# Generated by Django 5.1 on 2025-07-20 10:20
import django.db.models.deletion
import django.utils.timezone
import uuid
from django.conf import settings
from django.db import migrations, models
@ -18,12 +19,13 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='Activity',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('creation_date', models.DateTimeField(default=django.utils.timezone.now, editable=False)),
('last_update', models.DateTimeField(default=django.utils.timezone.now)),
('data_access_ids', models.JSONField(default=list)),
('status', models.CharField(blank=True, choices=[('NONE', 'None'), ('CONTACTED', 'Contacted'), ('RESPONDED', 'Responded'), ('SHOULD_TEST', 'Should test'), ('TESTING', 'Testing'), ('CUSTOMER', 'Customer'), ('LOST', 'Lost customer'), ('DECLINED_TOO_EXPENSIVE', 'Too expensive'), ('DECLINED_USE_SOMETHING_ELSE', 'Use something else'), ('DECLINED_OTHER', 'Declined other reason'), ('DECLINED_UNRELATED', 'Declined without significance')], default='NONE', max_length=50, null=True)),
('type', models.CharField(blank=True, choices=[('MAIL', 'Mailing List'), ('SMS', 'SMS Campaign'), ('CALL', 'Call'), ('PRESS', 'Press Release')], max_length=20, null=True)),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('status', models.CharField(blank=True, choices=[('NONE', 'None'), ('INBOUND', 'Inbound'), ('CONTACTED', 'Contacted'), ('RESPONDED', 'Responded'), ('SHOULD_TEST', 'Should test'), ('TESTING', 'Testing'), ('CUSTOMER', 'Customer'), ('LOST', 'Lost customer'), ('DECLINED', 'Declined'), ('DECLINED_UNRELATED', 'Declined without significance')], max_length=50, null=True)),
('declination_reason', models.CharField(blank=True, choices=[('TOO_EXPENSIVE', 'Too expensive'), ('USE_OTHER_PRODUCT', 'Use other product'), ('USE_ANDROID', 'Use Android'), ('UNKNOWN', 'Unknown')], max_length=50, null=True)),
('type', models.CharField(blank=True, choices=[('MAIL', 'Mail'), ('SMS', 'SMS'), ('CALL', 'Call'), ('PRESS', 'Press Release'), ('WORD_OF_MOUTH', 'Word of mouth')], max_length=20, null=True)),
('description', models.TextField(blank=True, null=True)),
('attachment_text', models.TextField(blank=True, null=True)),
('last_updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
@ -32,20 +34,19 @@ class Migration(migrations.Migration):
options={
'verbose_name_plural': 'Activities',
'ordering': ['-creation_date'],
'permissions': [('manage_events', 'Can manage events'), ('view_events', 'Can view events')],
},
),
migrations.CreateModel(
name='EmailTemplate',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('creation_date', models.DateTimeField(default=django.utils.timezone.now, editable=False)),
('last_update', models.DateTimeField(default=django.utils.timezone.now)),
('data_access_ids', models.JSONField(default=list)),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(max_length=100)),
('subject', models.CharField(max_length=200)),
('body', models.TextField(blank=True, null=True)),
('activities', models.ManyToManyField(blank=True, related_name='email_templates', to='bizdev.activity')),
('activities', models.ManyToManyField(blank=True, related_name='email_templates', to='biz.activity')),
('last_updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('related_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
@ -56,10 +57,10 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='Entity',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('creation_date', models.DateTimeField(default=django.utils.timezone.now, editable=False)),
('last_update', models.DateTimeField(default=django.utils.timezone.now)),
('data_access_ids', models.JSONField(default=list)),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('name', models.CharField(blank=True, max_length=200, null=True)),
('address', models.CharField(blank=True, max_length=200, null=True)),
('zip_code', models.CharField(blank=True, max_length=20, null=True)),
@ -75,28 +76,28 @@ class Migration(migrations.Migration):
migrations.CreateModel(
name='Prospect',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('creation_date', models.DateTimeField(default=django.utils.timezone.now, editable=False)),
('last_update', models.DateTimeField(default=django.utils.timezone.now)),
('data_access_ids', models.JSONField(default=list)),
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
('first_name', models.CharField(blank=True, max_length=200, null=True)),
('last_name', models.CharField(blank=True, max_length=200, null=True)),
('email', models.EmailField(max_length=254, unique=True)),
('phone', models.CharField(blank=True, max_length=25, null=True)),
('name_unsure', models.BooleanField(default=False)),
('source', models.CharField(blank=True, max_length=100, null=True)),
('entities', models.ManyToManyField(blank=True, related_name='prospects', to='bizdev.entity')),
('entities', models.ManyToManyField(blank=True, related_name='prospects', to='biz.entity')),
('last_updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('official_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
('related_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'permissions': [('manage_prospects', 'Can manage prospects'), ('view_prospects', 'Can view prospects')],
'abstract': False,
},
),
migrations.AddField(
model_name='activity',
name='prospects',
field=models.ManyToManyField(related_name='activities', to='bizdev.prospect'),
field=models.ManyToManyField(related_name='activities', to='biz.prospect'),
),
]

@ -1,6 +1,6 @@
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
from django.core.exceptions import PermissionDenied
class bizdevAccessMixin(LoginRequiredMixin, UserPassesTestMixin):
class bizAccessMixin(LoginRequiredMixin, UserPassesTestMixin):
def test_func(self):
return self.request.user.groups.filter(name='bizdev Manager').exists()
return self.request.user.groups.filter(name='biz Manager').exists()

@ -1,4 +1,4 @@
{% extends "bizdev/base.html" %}
{% extends "biz/base.html" %}
{% block content %}
<div class="container padding-bottom">

@ -1,4 +1,4 @@
{% extends "bizdev/base.html" %}
{% extends "biz/base.html" %}
{% block content %}
<div class="container mt-4">

@ -1,4 +1,4 @@
{% extends "bizdev/base.html" %} {% block content %}
{% extends "biz/base.html" %} {% block content %}
<div class="container">
<div class="grid-x padding-bottom">
<div class="cell medium-6 large-6 padding10 bubble">
@ -14,7 +14,7 @@
Save Event
</button>
<a
href="{% url 'bizdev:planned_events' %}"
href="{% url 'biz:planned_events' %}"
class="btn btn-secondary"
>Cancel</a
>

@ -7,9 +7,9 @@
<div class="right-column">
<span>{{ event.date|date:"d/m/Y H:i" }}</span>
<a href="{% url 'bizdev:edit_event' event.id %}" class="small-button">Edit</a>
<a href="{% url 'biz:edit_event' event.id %}" class="small-button">Edit</a>
<!-- {% if event.status == 'PLANNED' %}
<a href="{% url 'bizdev:start_event' event.id %}" class="small-button">Start</a>
<a href="{% url 'biz:start_event' event.id %}" class="small-button">Start</a>
{% endif %} -->
</div>
</div>

@ -1,23 +1,23 @@
{% extends "bizdev/base.html" %}
{% load bizdev_tags %}
{% extends "biz/base.html" %}
{% load biz_tags %}
{% block content %}
{% if request.user|is_bizdev_manager %}
{% if request.user|is_biz_manager %}
<div class="d-flex">
<a href="{% url 'bizdev:prospect-list' %}" class="small-button margin-v20">
<a href="{% url 'biz:prospect-list' %}" class="small-button margin-v20">
Prospects
</a>
<a href="{% url 'bizdev:add-event' %}" class="small-button margin-v20">
<a href="{% url 'biz:add-event' %}" class="small-button margin-v20">
Ajouter un évènement
</a>
<a href="{% url 'bizdev:add-prospect' %}" class="small-button margin-v20 left-margin">
<a href="{% url 'biz:add-prospect' %}" class="small-button margin-v20 left-margin">
Ajouter un prospect
</a>
<a href="{% url 'bizdev:csv-import' %}" class="small-button margin-v20 left-margin">
<a href="{% url 'biz:csv-import' %}" class="small-button margin-v20 left-margin">
Import
</a>
</div>
@ -31,7 +31,7 @@
<div class="list-group">
{% for event in completed_events %}
{% include "bizdev/event_row.html" with event=event %}
{% include "biz/event_row.html" with event=event %}
{% empty %}
<div class="list-group-item">No completed events.</div>
{% endfor %}
@ -47,7 +47,7 @@
<div class="list-group">
{% for event in planned_events %}
{% include "bizdev/event_row.html" with event=event %}
{% include "biz/event_row.html" with event=event %}
{% empty %}
<div class="list-group-item">No planned events.</div>
{% endfor %}

@ -1,4 +1,4 @@
{% extends "bizdev/base.html" %}
{% extends "biz/base.html" %}
{% block head_title %}{{ first_title }}{% endblock %}
{% block first_title %}{{ first_title }}{% endblock %}

@ -1,4 +1,4 @@
{% extends "bizdev/base.html" %}
{% extends "biz/base.html" %}
{% load static %}
@ -18,15 +18,15 @@
{% endfor %}
<div class="filter-buttons">
<button type="submit" class="btn btn-primary">Filter</button>
<a href="{% url 'bizdev:prospect-list' %}" class="btn btn-secondary">Clear</a>
<a href="{% url 'biz:prospect-list' %}" class="btn btn-secondary">Clear</a>
</div>
</form>
</div>
</div>
<!-- <div class="mb-3">
<a href="{% url 'bizdev:csv-import' %}" class="btn btn-success">Import CSV</a>
<a href="{% url 'bizdev:send-bulk-email' %}" class="btn btn-primary">Send Email</a>
<a href="{% url 'biz:csv-import' %}" class="btn btn-success">Import CSV</a>
<a href="{% url 'biz:send-bulk-email' %}" class="btn btn-primary">Send Email</a>
</div> -->
<span>{{ filter.qs|length }} résultats</span>
@ -60,11 +60,11 @@
{% endfor %}
</td>
<td>
<a href="{% url 'bizdev:edit-prospect' prospect.id %}">
<a href="{% url 'biz:edit-prospect' prospect.id %}">
<button class="btn btn-sm btn-secondary">Edit</button>
</a>
<a href="{% url 'bizdev:add-event-for-prospect' prospect.id %}">
<a href="{% url 'biz:add-event-for-prospect' prospect.id %}">
<button class="btn btn-sm btn-secondary">+ Event</button>
</a>
</td>
@ -77,5 +77,5 @@
{% endblock %}
{% block extra_js %}
<script src="{% static 'bizdev/js/prospects.js' %}"></script>
<script src="{% static 'biz/js/prospects.js' %}"></script>
{% endblock %}

@ -1,4 +1,4 @@
{% extends "bizdev/base.html" %}
{% extends "biz/base.html" %}
{% block content %}
<div class="container mt-4">
@ -41,7 +41,7 @@
</div>
<button type="submit" class="btn btn-primary">Send Email</button>
<a href="{% url 'bizdev:prospect-list' %}" class="btn btn-secondary">Cancel</a>
<a href="{% url 'biz:prospect-list' %}" class="btn btn-secondary">Cancel</a>
</form>
</div>
{% endblock %}

@ -0,0 +1,7 @@
from django import template
register = template.Library()
@register.filter(name='is_biz_manager')
def is_biz_manager(user):
return user.groups.filter(name='biz Manager').exists()

@ -1,7 +1,7 @@
from django.urls import path
from . import views
app_name = 'bizdev'
app_name = 'biz'
urlpatterns = [
path('', views.EventListView.as_view(), name='planned_events'),path('', views.EventListView.as_view(), name='events'),

@ -19,13 +19,13 @@ from .models import Event, Prospect, ActivityType
from .filters import ProspectFilter
from .forms import CSVImportForm
from .mixins import bizdevAccessMixin
from .mixins import bizAccessMixin
import csv
from io import TextIOWrapper
from datetime import datetime
# @permission_required('bizdev.view_bizdev', raise_exception=True)
# @permission_required('biz.view_biz', 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
@ -42,7 +42,7 @@ from datetime import datetime
# action = 'updated' if pk else 'added'
# messages.success(request,
# f'Prospect {prospect.entity_name} has been {action} successfully!')
# return redirect('bizdev:events')
# return redirect('biz:events')
# else:
# form = ProspectForm(instance=prospect)
@ -52,9 +52,9 @@ from datetime import datetime
# 'first_title': prospect.entity_name if prospect else 'Add Prospect',
# 'second_title': prospect.full_name() if prospect else None
# }
# return render(request, 'bizdev/prospect_form.html', context)
# return render(request, 'biz/prospect_form.html', context)
# # @permission_required('bizdev.view_bizdev', raise_exception=True)
# # @permission_required('biz.view_biz', raise_exception=True)
# # def add_prospect(request):
# # if request.method == 'POST':
# # entity_name = request.POST.get('entity_name')
@ -82,17 +82,17 @@ from datetime import datetime
# # modified_by=request.user
# # )
# # messages.success(request, f'Prospect {name} has been added successfully!')
# # return redirect('bizdev:events') # or wherever you want to redirect after success
# # return redirect('biz: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, 'bizdev/add_prospect.html')
# # return render(request, 'biz/add_prospect.html')
# class EventCreateView(bizdevAccessMixin, CreateView):
# class EventCreateView(bizAccessMixin, CreateView):
# model = Event
# form_class = EventForm
# template_name = 'bizdev/event_form.html'
# success_url = reverse_lazy('bizdev:planned_events')
# template_name = 'biz/event_form.html'
# success_url = reverse_lazy('biz:planned_events')
# def get_initial(self):
# initial = super().get_initial()
@ -106,11 +106,11 @@ from datetime import datetime
# form.instance.modified_by = self.request.user
# return super().form_valid(form)
# class EditEventView(bizdevAccessMixin, UpdateView):
# class EditEventView(bizAccessMixin, UpdateView):
# model = Event
# form_class = EventForm
# template_name = 'bizdev/event_form.html'
# success_url = reverse_lazy('bizdev:planned_events')
# template_name = 'biz/event_form.html'
# success_url = reverse_lazy('biz:planned_events')
# def form_valid(self, form):
# form.instance.modified_by = self.request.user
@ -118,7 +118,7 @@ from datetime import datetime
# messages.success(self.request, 'Event updated successfully!')
# return response
# class StartEventView(bizdevAccessMixin, BaseUpdateView):
# class StartEventView(bizAccessMixin, BaseUpdateView):
# model = Event
# http_method_names = ['post', 'get']
@ -132,23 +132,23 @@ from datetime import datetime
# if event.type == 'MAIL':
# return HttpResponseRedirect(
# reverse_lazy('bizdev:setup_email_campaign', kwargs={'event_id': event.id})
# reverse_lazy('biz:setup_email_campaign', kwargs={'event_id': event.id})
# )
# elif event.type == 'SMS':
# return HttpResponseRedirect(
# reverse_lazy('bizdev:setup_sms_campaign', kwargs={'event_id': event.id})
# reverse_lazy('biz:setup_sms_campaign', kwargs={'event_id': event.id})
# )
# elif event.type == 'PRESS':
# return HttpResponseRedirect(
# reverse_lazy('bizdev:setup_press_release', kwargs={'event_id': event.id})
# reverse_lazy('biz:setup_press_release', kwargs={'event_id': event.id})
# )
# messages.success(request, 'Event started successfully!')
# return HttpResponseRedirect(reverse_lazy('bizdev:planned_events'))
# return HttpResponseRedirect(reverse_lazy('biz:planned_events'))
# class EventListView(bizdevAccessMixin, ListView):
# class EventListView(bizAccessMixin, ListView):
# model = Event
# template_name = 'bizdev/events.html'
# template_name = 'biz/events.html'
# context_object_name = 'events' # We won't use this since we're providing custom context
# def get_context_data(self, **kwargs):
@ -161,9 +161,9 @@ from datetime import datetime
# ).order_by('-date')
# return context
# class ProspectListView(bizdevAccessMixin, ListView):
# class ProspectListView(bizAccessMixin, ListView):
# model = Prospect
# template_name = 'bizdev/prospect_list.html'
# template_name = 'biz/prospect_list.html'
# context_object_name = 'prospects'
# filterset_class = ProspectFilter
@ -178,8 +178,8 @@ from datetime import datetime
# )
# return context
# class CSVImportView(bizdevAccessMixin, FormView):
# template_name = 'bizdev/csv_import.html'
# class CSVImportView(bizAccessMixin, FormView):
# template_name = 'biz/csv_import.html'
# form_class = CSVImportForm
# success_url = reverse_lazy('prospect-list')
@ -247,10 +247,10 @@ from datetime import datetime
# return super().form_valid(form)
# class SendBulkEmailView(bizdevAccessMixin, FormView):
# template_name = 'bizdev/send_bulk_email.html'
# class SendBulkEmailView(bizAccessMixin, FormView):
# template_name = 'biz/send_bulk_email.html'
# form_class = BulkEmailForm
# success_url = reverse_lazy('bizdev:prospect-list')
# success_url = reverse_lazy('biz:prospect-list')
# def form_valid(self, form):
# prospects = form.cleaned_data['prospects']

@ -1 +0,0 @@
This is a django customer relationship managemement app.

@ -1,23 +0,0 @@
# Generated by Django 5.1 on 2025-07-10 13:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('bizdev', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='activity',
name='declination_reason',
field=models.CharField(blank=True, choices=[('TOO_EXPENSIVE', 'Too expensive'), ('USE_OTHER_PRODUCT', 'Use other product'), ('USE_ANDROID', 'Use Android'), ('UNKNOWN', 'Unknown')], max_length=50, null=True),
),
migrations.AlterField(
model_name='activity',
name='status',
field=models.CharField(blank=True, choices=[('CONTACTED', 'Contacted'), ('RESPONDED', 'Responded'), ('SHOULD_TEST', 'Should test'), ('TESTING', 'Testing'), ('CUSTOMER', 'Customer'), ('LOST', 'Lost customer'), ('DECLINED', 'Declined'), ('DECLINED_UNRELATED', 'Declined without significance')], max_length=50, null=True),
),
]

@ -1,52 +0,0 @@
# Generated by Django 5.1 on 2025-07-20 10:08
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('bizdev', '0002_activity_declination_reason_alter_activity_status'),
]
operations = [
migrations.AlterModelOptions(
name='activity',
options={'ordering': ['-creation_date'], 'verbose_name_plural': 'Activities'},
),
migrations.AlterModelOptions(
name='prospect',
options={},
),
migrations.AlterField(
model_name='activity',
name='id',
field=models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False),
),
migrations.AlterField(
model_name='activity',
name='status',
field=models.CharField(blank=True, choices=[('NONE', 'None'), ('INBOUND', 'Inbound'), ('CONTACTED', 'Contacted'), ('RESPONDED', 'Responded'), ('SHOULD_TEST', 'Should test'), ('TESTING', 'Testing'), ('CUSTOMER', 'Customer'), ('LOST', 'Lost customer'), ('DECLINED', 'Declined'), ('DECLINED_UNRELATED', 'Declined without significance')], max_length=50, null=True),
),
migrations.AlterField(
model_name='activity',
name='type',
field=models.CharField(blank=True, choices=[('MAIL', 'Mail'), ('SMS', 'SMS'), ('CALL', 'Call'), ('PRESS', 'Press Release'), ('WORD_OF_MOUTH', 'Word of mouth')], max_length=20, null=True),
),
migrations.AlterField(
model_name='emailtemplate',
name='id',
field=models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False),
),
migrations.AlterField(
model_name='entity',
name='id',
field=models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False),
),
migrations.AlterField(
model_name='prospect',
name='id',
field=models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False),
),
]

@ -1,18 +0,0 @@
# Generated by Django 5.1 on 2025-07-20 10:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('bizdev', '0003_alter_activity_options_alter_prospect_options_and_more'),
]
operations = [
migrations.AlterField(
model_name='emailtemplate',
name='id',
field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
),
]

@ -1,6 +0,0 @@
document.getElementById("select-all").addEventListener("change", function () {
const checkboxes = document.getElementsByName("selected_prospects");
for (let checkbox of checkboxes) {
checkbox.checked = this.checked;
}
});

@ -1,7 +0,0 @@
from django import template
register = template.Library()
@register.filter(name='is_bizdev_manager')
def is_bizdev_manager(user):
return user.groups.filter(name='bizdev Manager').exists()

@ -36,7 +36,7 @@ INSTALLED_APPS = [
'sync',
'tournaments',
'shop',
'bizdev',
'biz',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',

@ -39,7 +39,7 @@ QR_CODE_CACHE_ALIAS = 'qr-code'
SYNC_APPS = {
'sync': {},
'tournaments': { 'exclude': ['Log', 'FailedApiCall', 'DeviceToken', 'Image'] },
'bizdev': {},
'biz': {},
}
SYNC_MODEL_CHILDREN_SHARING = {

@ -34,7 +34,7 @@ urlpatterns = [
path('kingdom/debug/player-license-lookup/', get_player_license_info, name='player_license_lookup'),
path('kingdom/debug/bulk-license-lookup/', bulk_license_lookup, name='bulk_license_lookup'),
path('kingdom/debug/explore-api-endpoints/', explore_fft_api_endpoints, name='explore_api_endpoints'),
# path('kingdom/bizdev/', include('bizdev.admin_urls')),
# path('kingdom/biz/', include('biz.admin_urls')),
path('kingdom/', admin.site.urls),
path('api-auth/', include('rest_framework.urls')),
path('dj-auth/', include('django.contrib.auth.urls')),

@ -24,7 +24,7 @@
style="display: block; padding: 12px 15px; background: #17a2b8; color: white; text-decoration: none; border-radius: 8px; text-align: center; font-weight: 500;">
Purchases
</a>
<a href="{% url 'admin:bizdev_prospect_changelist' %}"
<a href="{% url 'admin:biz_prospect_changelist' %}"
style="display: block; padding: 12px 15px; background: #17a2b8; color: white; text-decoration: none; border-radius: 8px; text-align: center; font-weight: 500;">
Prospects
</a>

Loading…
Cancel
Save