pretix-map 0.1.3__py3-none-any.whl → 0.1.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. pretix_map-0.1.5.dist-info/METADATA +88 -0
  2. {pretix_map-0.1.3.dist-info → pretix_map-0.1.5.dist-info}/RECORD +32 -30
  3. {pretix_map-0.1.3.dist-info → pretix_map-0.1.5.dist-info}/WHEEL +1 -1
  4. {pretix_map-0.1.3.dist-info → pretix_map-0.1.5.dist-info}/licenses/LICENSE +15 -15
  5. pretix_mapplugin/__init__.py +1 -1
  6. pretix_mapplugin/apps.py +28 -28
  7. pretix_mapplugin/geocoding.py +162 -102
  8. pretix_mapplugin/locale/de/LC_MESSAGES/django.po +12 -12
  9. pretix_mapplugin/locale/de_Informal/LC_MESSAGES/django.po +12 -12
  10. pretix_mapplugin/management/commands/geocode_existing_orders.py +271 -271
  11. pretix_mapplugin/migrations/0001_initial.py +27 -27
  12. pretix_mapplugin/migrations/0002_remove_ordergeocodedata_geocoded_timestamp_and_more.py +32 -32
  13. pretix_mapplugin/migrations/0003_mapmilestone.py +27 -0
  14. pretix_mapplugin/models.py +71 -47
  15. pretix_mapplugin/signals.py +77 -92
  16. pretix_mapplugin/static/pretix_mapplugin/css/salesmap.css +51 -51
  17. pretix_mapplugin/static/pretix_mapplugin/js/salesmap.js +342 -442
  18. pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.Default.css +59 -59
  19. pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.css +14 -14
  20. pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-heat.js +10 -10
  21. pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-src.esm.js +14419 -14419
  22. pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-src.js +14512 -14512
  23. pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet.css +661 -661
  24. pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet.js +5 -5
  25. pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet.markercluster.js +2 -2
  26. pretix_mapplugin/tasks.py +144 -113
  27. pretix_mapplugin/templates/pretix_mapplugin/map_page.html +154 -68
  28. pretix_mapplugin/templates/pretix_mapplugin/milestones.html +53 -0
  29. pretix_mapplugin/urls.py +38 -21
  30. pretix_mapplugin/views.py +272 -163
  31. pretix_map-0.1.3.dist-info/METADATA +0 -195
  32. {pretix_map-0.1.3.dist-info → pretix_map-0.1.5.dist-info}/entry_points.txt +0 -0
  33. {pretix_map-0.1.3.dist-info → pretix_map-0.1.5.dist-info}/top_level.txt +0 -0
@@ -1,68 +1,154 @@
1
- {% extends "pretixcontrol/event/settings_base.html" %}
2
- {% load i18n %}
3
- {% load static %}
4
- {% load eventurl %}
5
-
6
- {% block title %}{% trans "Ticket Sales Map" %}{% endblock %}
7
-
8
- {% block inside %}
9
- <h1>{% trans "Ticket Sales Map" %}</h1>
10
-
11
- {# -- Controls Row -- #}
12
- <div class="form-inline" style="margin-bottom: 1em;">
13
- <div class="form-group" style="margin-right: 10px;">
14
- <button id="view-toggle-btn" class="btn btn-default">Switch to Heatmap View</button>
15
- </div>
16
- {# -- NEW Cluster Toggle Button -- #}
17
- <div class="form-group" style="margin-right: 10px;">
18
- <button id="cluster-toggle-btn" class="btn btn-default" disabled>Disable Clustering</button>
19
- </div>
20
- {# -- End Cluster Toggle Button -- #}
21
- </div>
22
- {# -- End Controls Row -- #}
23
-
24
- {# -- NEW Heatmap Options Panel (Initially hidden for pins view) -- #}
25
- <div id="heatmap-options-panel" class="panel panel-default"
26
- style="display: none; padding: 15px; margin-bottom: 1em; max-width: 400px;">
27
- <h4>{% trans "Heatmap Options" %}</h4>
28
- <div class="form-group">
29
- <label for="heatmap-radius">Radius: <span id="radius-value">25</span></label>
30
- <input type="range" id="heatmap-radius" class="form-control" min="1" max="100" value="25" step="1" disabled>
31
- </div>
32
- <div class="form-group">
33
- <label for="heatmap-blur">Blur: <span id="blur-value">15</span></label>
34
- <input type="range" id="heatmap-blur" class="form-control" min="1" max="50" value="15" step="1" disabled>
35
- </div>
36
- <div class="form-group">
37
- <label for="heatmap-maxZoom">Max Zoom: <span id="maxzoom-value">18</span></label>
38
- <input type="range" id="heatmap-maxZoom" class="form-control" min="1" max="18" value="18" step="1" disabled>
39
- </div>
40
- {# Add more options like gradient if desired later #}
41
- </div>
42
- {# -- End Heatmap Options Panel -- #}
43
-
44
-
45
- {# -- Map Area -- #}
46
- <div style="position: relative; border: 1px solid #ccc;">
47
- <div id="sales-map-container"
48
- data-data-url="{% url 'plugins:pretix_mapplugin:event.settings.salesmap.data' organizer=request.organizer.slug event=request.event.slug %}">
49
- </div>
50
- <div id="map-status-overlay"
51
- style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 1000; display: flex; justify-content: center; align-items: center; text-align: center;">
52
- <p>Loading map data...</p>
53
- </div>
54
- </div>
55
- {# -- End Map Area -- #}
56
-
57
-
58
- {# === Leaflet & Plugins (Keep as is) === #}
59
- <script src="{% static 'pretix_mapplugin/libs/leaflet-sales-map/leaflet-heat.js' %}"></script>
60
- <link rel="stylesheet" href="{% static 'pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.css' %}"/>
61
- <link rel="stylesheet" href="{% static 'pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.Default.css' %}"/>
62
- <script src="{% static 'pretix_mapplugin/libs/leaflet-sales-map/leaflet.markercluster.js' %}"></script>
63
-
64
- {# === Your JS/CSS (Keep as is) === #}
65
- <script src="{% static 'pretix_mapplugin/js/salesmap.js' %}"></script>
66
- <link rel="stylesheet" href="{% static 'pretix_mapplugin/css/salesmap.css' %}"/>
67
-
68
- {% endblock %}
1
+ {% extends "pretixcontrol/event/settings_base.html" %}
2
+ {% load i18n %}
3
+ {% load static %}
4
+ {% load eventurl %}
5
+
6
+ {% block title %}{% trans "Ticket Sales Map" %}{% endblock %}
7
+
8
+ {% block inside %}
9
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
10
+ <div class="plugin-map-content-wrapper" style="display: flex; flex-direction: column; min-height: 85vh;">
11
+
12
+ <h1>{% trans "Ticket Sales Map" %}</h1>
13
+
14
+ <div class="form-inline map-controls-row" style="margin-bottom: 1em; display: flex; flex-wrap: wrap; align-items: flex-start; gap: 10px;">
15
+
16
+ <div class="map-buttons-group" style="display: flex; flex-wrap: wrap; gap: 5px; align-items: center;">
17
+ <div class="form-group">
18
+ <button id="view-toggle-btn" class="btn btn-default" disabled>{% trans "Heatmap View" %}</button>
19
+ </div>
20
+ <div class="form-group">
21
+ <button id="cluster-toggle-btn" class="btn btn-default" disabled>{% trans "Clustering" %}</button>
22
+ </div>
23
+ <div class="form-group">
24
+ <button id="grid-toggle-btn" class="btn btn-default" disabled>{% trans "Density Grid" %}</button>
25
+ </div>
26
+ <div class="form-group">
27
+ <button id="weight-toggle-btn" class="btn btn-default" disabled>{% trans "Weight by Revenue" %}</button>
28
+ </div>
29
+ <div class="form-group">
30
+ <div class="checkbox" style="margin-left: 10px; margin-top: 8px;">
31
+ <label><input type="checkbox" id="show-canceled-check"> {% trans "Show Canceled" %}</label>
32
+ </div>
33
+ </div>
34
+ <div class="form-group">
35
+ <button id="filter-toggle-btn" class="btn btn-default" disabled>{% trans "Filter" %} <span class="caret"></span></button>
36
+ </div>
37
+ <div class="form-group">
38
+ <select id="compare-event-select" class="form-control" style="width: auto;" disabled>
39
+ <option value="">{% trans "Compare..." %}</option>
40
+ {% for e in other_events %}
41
+ <option value="{{ e.slug }}">{{ e.name }}</option>
42
+ {% endfor %}
43
+ </select>
44
+ </div>
45
+ <div class="form-group">
46
+ <button id="list-toggle-btn" class="btn btn-info" disabled>{% trans "Failed Orders" %}</button>
47
+ </div>
48
+ <div class="form-group">
49
+ <button id="stats-toggle-btn" class="btn btn-primary" disabled>{% trans "Analytics View" %}</button>
50
+ </div>
51
+ {% if "can_change_event_settings" in request.eventperm %}
52
+ <div class="form-group">
53
+ <form action="{% url 'plugins:pretix_mapplugin:event.settings.salesmap.trigger' organizer=request.organizer.slug event=request.event.slug %}" method="post" style="display: inline-block;">
54
+ {% csrf_token %}
55
+ <button type="submit" class="btn btn-warning" title="{% trans "Trigger Geocoding" %}"><i class="fa fa-refresh"></i></button>
56
+ </form>
57
+ </div>
58
+ {% endif %}
59
+ </div>
60
+
61
+ <div id="heatmap-options-panel" class="panel panel-default" style="display: none; padding: 10px; min-width: 300px;">
62
+ <div style="display: flex; justify-content: space-between;">
63
+ <h5 style="margin: 0;">Heatmap</h5>
64
+ <button id="heatmap-reset-btn" class="btn btn-xs btn-link">Reset</button>
65
+ </div>
66
+ <div class="form-horizontal" style="margin-top: 5px;">
67
+ <div class="form-group form-group-sm"><label class="col-sm-4">Radius</label><div class="col-sm-6"><input type="range" id="heatmap-radius" min="1" max="100" value="25"></div><div class="col-sm-2"><span id="radius-value">25</span></div></div>
68
+ <div class="form-group form-group-sm"><label class="col-sm-4">Blur</label><div class="col-sm-6"><input type="range" id="heatmap-blur" min="1" max="50" value="15"></div><div class="col-sm-2"><span id="blur-value">15</span></div></div>
69
+ <div class="form-group form-group-sm"><label class="col-sm-4">Max Zoom</label><div class="col-sm-6"><input type="range" id="heatmap-maxZoom" min="1" max="18" value="18"></div><div class="col-sm-2"><span id="maxzoom-value">18</span></div></div>
70
+ </div>
71
+ </div>
72
+
73
+ <div id="filter-options-panel" class="panel panel-default" style="display: none; padding: 10px; min-width: 200px; max-height: 300px; overflow-y: auto;">
74
+ <h5 style="margin: 0 0 5px 0;">Ticket Types</h5>
75
+ <div id="filter-checkboxes"></div>
76
+ </div>
77
+ </div>
78
+
79
+ <div class="map-wrapper" style="position: relative; border: 1px solid #ccc; flex-grow: 1; display: flex; flex-direction: column; min-height: 500px;">
80
+ <div id="sales-map-container" style="flex-grow: 1; min-height: 500px;" data-data-url="{% url 'plugins:pretix_mapplugin:event.settings.salesmap.data' organizer=request.organizer.slug event=request.event.slug %}"></div>
81
+
82
+ <div id="failed-orders-container" style="display: none; padding: 20px; background: white; flex-grow: 1; overflow-y: auto;">
83
+ <h3>{% trans "Orders with missing geodata" %}</h3>
84
+ <table class="table table-hover">
85
+ <thead><tr><th>Code</th><th>Address</th><th>Action</th></tr></thead>
86
+ <tbody id="failed-orders-tbody"></tbody>
87
+ </table>
88
+ </div>
89
+
90
+ <div id="analytics-view-container" style="display: none; padding: 20px; background: #fafafa; flex-grow: 1; overflow-y: auto;">
91
+ <div class="row">
92
+ <div class="col-md-4">
93
+ <div class="panel panel-default">
94
+ <div class="panel-heading">Key Figures</div>
95
+ <div class="panel-body" id="stats-summary-text"></div>
96
+ </div>
97
+ </div>
98
+ <div class="col-md-8">
99
+ <div class="panel panel-default">
100
+ <div class="panel-heading">Top Cities (Sales Count)</div>
101
+ <div class="panel-body"><canvas id="cities-chart" height="150"></canvas></div>
102
+ </div>
103
+ </div>
104
+ </div>
105
+ <div class="row" style="margin-top: 20px;">
106
+ <div class="col-md-6">
107
+ <div class="panel panel-default">
108
+ <div class="panel-heading">Ticket Type Distribution</div>
109
+ <div class="panel-body"><canvas id="items-chart" height="200"></canvas></div>
110
+ </div>
111
+ </div>
112
+ <div class="col-md-6">
113
+ <div class="panel panel-default">
114
+ <div class="panel-heading">Revenue by Ticket Type</div>
115
+ <div class="panel-body"><canvas id="revenue-chart" height="200"></canvas></div>
116
+ </div>
117
+ </div>
118
+ </div>
119
+ </div>
120
+
121
+ <div id="map-status-overlay" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 1000; display: flex; justify-content: center; align-items: center;">
122
+ <p>Loading...</p>
123
+ </div>
124
+ </div>
125
+
126
+ <div id="timeline-controls" style="margin-top: 10px; padding: 10px; background: #f5f5f5; border-radius: 4px; border: 1px solid #ddd;">
127
+ <div style="display: flex; justify-content: space-between; align-items: center;">
128
+ <div>
129
+ <label style="margin-bottom: 0;">{% trans "Timeline:" %} <span id="timeline-date-display" style="font-weight: normal;"></span></label>
130
+ <span id="timeline-count-display" class="badge"></span>
131
+ </div>
132
+ <div>
133
+ <select id="timeline-interval-select" class="form-control input-sm" style="width: auto; display: inline-block;">
134
+ <option value="hour">{% trans "Hourly" %}</option>
135
+ <option value="day" selected>{% trans "Daily" %}</option>
136
+ <option value="week">{% trans "Weekly" %}</option>
137
+ <option value="month">{% trans "Monthly" %}</option>
138
+ </select>
139
+ </div>
140
+ </div>
141
+ <div style="display: flex; gap: 10px; align-items: center; margin-top: 5px;">
142
+ <button id="timeline-play-btn" class="btn btn-sm btn-default"><i class="fa fa-play"></i> Play</button>
143
+ <input type="range" id="timeline-slider" min="0" max="100" value="100" style="flex-grow: 1; cursor: pointer;">
144
+ </div>
145
+ </div>
146
+ </div>
147
+
148
+ <script src="{% static 'pretix_mapplugin/libs/leaflet-sales-map/leaflet-heat.js' %}"></script>
149
+ <link rel="stylesheet" href="{% static 'pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.css' %}"/>
150
+ <link rel="stylesheet" href="{% static 'pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.Default.css' %}"/>
151
+ <script src="{% static 'pretix_mapplugin/libs/leaflet-sales-map/leaflet.markercluster.js' %}"></script>
152
+ <script src="{% static 'pretix_mapplugin/js/salesmap.js' %}"></script>
153
+ <link rel="stylesheet" href="{% static 'pretix_mapplugin/css/salesmap.css' %}"/>
154
+ {% endblock %}
@@ -0,0 +1,53 @@
1
+ {% extends "pretixcontrol/event/settings_base.html" %}
2
+ {% load i18n %}
3
+ {% load bootstrap3 %}
4
+
5
+ {% block title %}{% trans "Map Milestones" %}{% endblock %}
6
+
7
+ {% block inside %}
8
+ <h1>{% trans "Map Milestones" %}</h1>
9
+ <p>
10
+ {% trans "Define important dates (e.g. newsletter dispatch, ticket start) to see them in the Sales Map timeline." %}
11
+ </p>
12
+ <form action="" method="post" class="form-horizontal">
13
+ {% csrf_token %}
14
+ <div class="formset" data-formset-prefix="{{ formset.prefix }}">
15
+ {{ formset.management_form }}
16
+ {% bootstrap_formset_errors formset %}
17
+ <table class="table table-condensed">
18
+ <thead>
19
+ <tr>
20
+ <th>{% trans "Date" %}</th>
21
+ <th>{% trans "Label" %}</th>
22
+ <th>{% trans "Delete" %}</th>
23
+ </tr>
24
+ </thead>
25
+ <tbody>
26
+ {% for form in formset %}
27
+ <tr class="formset-row">
28
+ <td>
29
+ {{ form.id }}
30
+ {% bootstrap_field form.date layout='inline' %}
31
+ </td>
32
+ <td>
33
+ {% bootstrap_field form.label layout='inline' %}
34
+ </td>
35
+ <td>
36
+ {% if formset.can_delete %}
37
+ {% bootstrap_field form.DELETE layout='inline' %}
38
+ {% endif %}
39
+ </td>
40
+ </tr>
41
+ {% endfor %}
42
+ </tbody>
43
+ </table>
44
+ </div>
45
+ <div class="form-group">
46
+ <div class="col-sm-offset-2 col-sm-10">
47
+ <button type="submit" class="btn btn-primary">
48
+ {% trans "Save" %}
49
+ </button>
50
+ </div>
51
+ </div>
52
+ </form>
53
+ {% endblock %}
pretix_mapplugin/urls.py CHANGED
@@ -1,21 +1,38 @@
1
- from django.urls import re_path
2
-
3
- from .views import SalesMapDataView, SalesMapView # Import your views
4
-
5
- # Define the URL patterns for the event settings area
6
- # These URLs will be prefixed with /control/event/<organizer>/<event>/
7
- # based on how Pretix includes plugin URLs.
8
- urlpatterns = [
9
- # URL for the API endpoint providing coordinate data
10
- re_path(
11
- r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/sales-map/data/',
12
- SalesMapDataView.as_view(),
13
- name="event.settings.salesmap.data", # Unique name for URL reversing
14
- ),
15
- # URL for the HTML page displaying the map
16
- re_path(
17
- r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/sales-map/',
18
- SalesMapView.as_view(),
19
- name="event.settings.salesmap.show", # Unique name for URL reversing
20
- ),
21
- ]
1
+ from django.urls import re_path
2
+
3
+ from .views import SalesMapDataView, SalesMapView, MilestoneSettingsView, TriggerGeocodingView, SingleGeocodeView
4
+
5
+ # Define the URL patterns for the event settings area
6
+ # These URLs will be prefixed with /control/event/<organizer>/<event>/
7
+ urlpatterns = [
8
+ # URL for the API endpoint providing coordinate data
9
+ re_path(
10
+ r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/sales-map/data/',
11
+ SalesMapDataView.as_view(),
12
+ name="event.settings.salesmap.data",
13
+ ),
14
+ # URL for triggering geocoding for all
15
+ re_path(
16
+ r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/sales-map/trigger/',
17
+ TriggerGeocodingView.as_view(),
18
+ name="event.settings.salesmap.trigger",
19
+ ),
20
+ # URL for single order geocoding
21
+ re_path(
22
+ r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/sales-map/retry/(?P<order>[^/]+)/',
23
+ SingleGeocodeView.as_view(),
24
+ name="event.settings.salesmap.retry",
25
+ ),
26
+ # URL for milestone management
27
+ re_path(
28
+ r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/sales-map/milestones/',
29
+ MilestoneSettingsView.as_view(),
30
+ name="event.settings.salesmap.milestones",
31
+ ),
32
+ # URL for the HTML page displaying the map
33
+ re_path(
34
+ r'^control/event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/sales-map/',
35
+ SalesMapView.as_view(),
36
+ name="event.settings.salesmap.show",
37
+ ),
38
+ ]