pretix-map 0.1.0__tar.gz → 0.1.2__tar.gz
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.
- {pretix_map-0.1.0/pretix_map.egg-info → pretix_map-0.1.2}/PKG-INFO +3 -1
- {pretix_map-0.1.0 → pretix_map-0.1.2}/README.rst +2 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2/pretix_map.egg-info}/PKG-INFO +3 -1
- pretix_map-0.1.2/pretix_mapplugin/__init__.py +1 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/management/commands/geocode_existing_orders.py +69 -36
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/signals.py +27 -22
- pretix_map-0.1.2/pretix_mapplugin/tasks.py +113 -0
- pretix_map-0.1.0/pretix_mapplugin/__init__.py +0 -1
- pretix_map-0.1.0/pretix_mapplugin/tasks.py +0 -90
- {pretix_map-0.1.0 → pretix_map-0.1.2}/LICENSE +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/MANIFEST.in +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_map.egg-info/SOURCES.txt +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_map.egg-info/dependency_links.txt +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_map.egg-info/entry_points.txt +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_map.egg-info/requires.txt +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_map.egg-info/top_level.txt +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/apps.py +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/geocoding.py +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/locale/de/LC_MESSAGES/django.mo +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/locale/de/LC_MESSAGES/django.po +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/locale/de_Informal/.gitkeep +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/locale/de_Informal/LC_MESSAGES/django.mo +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/locale/de_Informal/LC_MESSAGES/django.po +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/management/__init__.py +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/management/commands/__init__.py +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/migrations/0001_initial.py +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/migrations/__init__.py +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/models.py +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/.gitkeep +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/css/salesmap.css +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/js/salesmap.js +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.Default.css +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/MarkerCluster.css +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/images/layers-2x.png +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/images/layers.png +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/images/marker-icon-2x.png +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/images/marker-icon.png +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/images/marker-shadow.png +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-heat.js +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-src.esm.js +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-src.esm.js.map +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-src.js +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet-src.js.map +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet.css +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet.js +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet.js.map +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet.markercluster.js +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/libs/leaflet-sales-map/leaflet.markercluster.js.map +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/templates/pretix_mapplugin/.gitkeep +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/templates/pretix_mapplugin/map_page.html +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/urls.py +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/views.py +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/pyproject.toml +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/setup.cfg +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/setup.py +0 -0
- {pretix_map-0.1.0 → pretix_map-0.1.2}/tests/test_main.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pretix-map
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.2
|
4
4
|
Summary: An overview map of the catchment area of previous orders. Measured by postcode
|
5
5
|
Author-email: MarkenJaden <jjsch1410@gmail.com>
|
6
6
|
Maintainer-email: MarkenJaden <jjsch1410@gmail.com>
|
@@ -140,10 +140,12 @@ This command is essential for processing orders that were placed *before* the ma
|
|
140
140
|
**Example Workflow:**
|
141
141
|
|
142
142
|
1. **Test with Dry Run (All Organizers):**
|
143
|
+
|
143
144
|
.. code-block:: bash
|
144
145
|
|
145
146
|
python manage.py geocode_existing_orders --dry-run
|
146
147
|
2. **(If satisfied) Run for Real (All Organizers):**
|
148
|
+
|
147
149
|
.. code-block:: bash
|
148
150
|
|
149
151
|
python manage.py geocode_existing_orders
|
@@ -125,10 +125,12 @@ This command is essential for processing orders that were placed *before* the ma
|
|
125
125
|
**Example Workflow:**
|
126
126
|
|
127
127
|
1. **Test with Dry Run (All Organizers):**
|
128
|
+
|
128
129
|
.. code-block:: bash
|
129
130
|
|
130
131
|
python manage.py geocode_existing_orders --dry-run
|
131
132
|
2. **(If satisfied) Run for Real (All Organizers):**
|
133
|
+
|
132
134
|
.. code-block:: bash
|
133
135
|
|
134
136
|
python manage.py geocode_existing_orders
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pretix-map
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.2
|
4
4
|
Summary: An overview map of the catchment area of previous orders. Measured by postcode
|
5
5
|
Author-email: MarkenJaden <jjsch1410@gmail.com>
|
6
6
|
Maintainer-email: MarkenJaden <jjsch1410@gmail.com>
|
@@ -140,10 +140,12 @@ This command is essential for processing orders that were placed *before* the ma
|
|
140
140
|
**Example Workflow:**
|
141
141
|
|
142
142
|
1. **Test with Dry Run (All Organizers):**
|
143
|
+
|
143
144
|
.. code-block:: bash
|
144
145
|
|
145
146
|
python manage.py geocode_existing_orders --dry-run
|
146
147
|
2. **(If satisfied) Run for Real (All Organizers):**
|
148
|
+
|
147
149
|
.. code-block:: bash
|
148
150
|
|
149
151
|
python manage.py geocode_existing_orders
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.1.2"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
from django.core.management.base import BaseCommand, CommandError
|
3
|
-
from django.core.exceptions import FieldDoesNotExist
|
3
|
+
from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist
|
4
4
|
|
5
5
|
# --- Import Pretix Global Settings accessor ---
|
6
6
|
from django_scopes import scope
|
@@ -8,6 +8,7 @@ from django_scopes import scope
|
|
8
8
|
# Check if Pretix version uses AbstractSettingsHolder or GlobalSettingsObject
|
9
9
|
# Adjust import based on Pretix version if needed. Assume AbstractSettingsHolder for newer Pretix.
|
10
10
|
try:
|
11
|
+
# Newer Pretix often uses this pattern via AbstractSettingsHolder
|
11
12
|
from pretix.base.settings import GlobalSettingsObject as SettingsProxy
|
12
13
|
except ImportError:
|
13
14
|
try:
|
@@ -21,7 +22,11 @@ except ImportError:
|
|
21
22
|
except ImportError:
|
22
23
|
# Fallback or raise error if neither is found
|
23
24
|
logger.error("Could not determine Pretix settings accessor for management command.")
|
24
|
-
|
25
|
+
|
26
|
+
|
27
|
+
# This will likely cause the command to fail later, but allows it to start
|
28
|
+
class SettingsProxy:
|
29
|
+
def __init__(self): self.settings = {} # Empty dict to avoid errors later
|
25
30
|
|
26
31
|
# --- Import necessary Pretix models ---
|
27
32
|
from pretix.base.models import Order, Event, Organizer
|
@@ -40,16 +45,23 @@ class Command(BaseCommand):
|
|
40
45
|
|
41
46
|
def add_arguments(self, parser):
|
42
47
|
parser.add_argument(
|
43
|
-
'--organizer',
|
48
|
+
'--organizer',
|
49
|
+
type=str,
|
50
|
+
help='Slug of a specific organizer to process orders for.',
|
44
51
|
)
|
45
52
|
parser.add_argument(
|
46
|
-
'--event',
|
53
|
+
'--event',
|
54
|
+
type=str,
|
55
|
+
help='Slug of a specific event to process orders for. Requires --organizer.',
|
47
56
|
)
|
48
57
|
parser.add_argument(
|
49
|
-
'--dry-run',
|
58
|
+
'--dry-run',
|
59
|
+
action='store_true',
|
60
|
+
help='Simulate the process without actually queuing tasks.',
|
50
61
|
)
|
51
62
|
parser.add_argument(
|
52
|
-
'--force-recode',
|
63
|
+
'--force-recode',
|
64
|
+
action='store_true',
|
53
65
|
help='Queue geocoding even for orders that already have geocode data.',
|
54
66
|
)
|
55
67
|
|
@@ -65,13 +77,12 @@ class Command(BaseCommand):
|
|
65
77
|
# --- Read User-Agent using Pretix Settings accessor ---
|
66
78
|
user_agent = DEFAULT_NOMINATIM_USER_AGENT
|
67
79
|
try:
|
68
|
-
# Get settings holder instance
|
69
80
|
gs = SettingsProxy()
|
70
81
|
# Construct the setting key specific to plugins
|
71
|
-
#
|
72
|
-
# Check Pretix docs or experiment if needed. Assuming the former.
|
82
|
+
# The format 'plugin:plugin_name:setting_name' is common
|
73
83
|
setting_key = 'plugin:pretix_mapplugin:nominatim_user_agent'
|
74
|
-
|
84
|
+
# Use .get() which is safer for dictionaries possibly returned by load_config
|
85
|
+
user_agent = getattr(gs, 'settings', {}).get(setting_key, DEFAULT_NOMINATIM_USER_AGENT)
|
75
86
|
|
76
87
|
if user_agent == DEFAULT_NOMINATIM_USER_AGENT:
|
77
88
|
self.stdout.write(self.style.WARNING(
|
@@ -88,12 +99,14 @@ class Command(BaseCommand):
|
|
88
99
|
organizers_to_process = []
|
89
100
|
if organizer_slug:
|
90
101
|
try:
|
102
|
+
# Fetch specific organizer (outside scope)
|
91
103
|
organizer = Organizer.objects.get(slug=organizer_slug)
|
92
104
|
organizers_to_process.append(organizer)
|
93
105
|
self.stdout.write(f"Processing specified organizer: {organizer.name} ({organizer_slug})")
|
94
106
|
except Organizer.DoesNotExist:
|
95
107
|
raise CommandError(f"Organizer with slug '{organizer_slug}' not found.")
|
96
108
|
else:
|
109
|
+
# Fetch all organizers (outside scope)
|
97
110
|
organizers_to_process = list(Organizer.objects.all())
|
98
111
|
self.stdout.write(f"Processing all {len(organizers_to_process)} organizers...")
|
99
112
|
|
@@ -105,9 +118,10 @@ class Command(BaseCommand):
|
|
105
118
|
# --- Iterate through organizers and activate scope ---
|
106
119
|
for organizer in organizers_to_process:
|
107
120
|
self.stdout.write(f"\n--- Processing Organizer: {organizer.name} ({organizer.slug}) ---")
|
121
|
+
current_organizer_pk = organizer.pk # Get the PK needed for the task kwarg
|
108
122
|
|
109
123
|
with scope(organizer=organizer):
|
110
|
-
# --- Get orders ---
|
124
|
+
# --- Get orders within scope ---
|
111
125
|
orders_qs = Order.objects.filter(status=Order.STATUS_PAID)
|
112
126
|
|
113
127
|
# --- Filter by event if specified ---
|
@@ -119,74 +133,93 @@ class Command(BaseCommand):
|
|
119
133
|
except Event.DoesNotExist:
|
120
134
|
self.stderr.write(self.style.WARNING(
|
121
135
|
f" Event '{event_slug}' not found for this organizer. Skipping event filter."))
|
122
|
-
|
136
|
+
# If filtering by event and it's not found for this org, skip this org entirely
|
137
|
+
if organizer_slug and event_slug:
|
138
|
+
self.stdout.write(
|
139
|
+
f" Skipping organizer '{organizer.slug}' as specified event was not found.")
|
140
|
+
continue # Move to the next organizer
|
123
141
|
|
124
142
|
# --- Filter orders needing geocoding ---
|
125
|
-
relation_name = 'geocode_data' # Ensure this matches your model
|
143
|
+
relation_name = 'geocode_data' # Ensure this matches your model's related_name
|
126
144
|
if not force_recode:
|
127
145
|
try:
|
128
146
|
Order._meta.get_field(relation_name) # Check existence
|
147
|
+
# Filter orders that don't have the related geocode entry
|
129
148
|
orders_to_process_qs = orders_qs.filter(**{f'{relation_name}__isnull': True})
|
130
149
|
self.stdout.write(" Selecting paid orders missing geocode data...")
|
131
150
|
except FieldDoesNotExist:
|
132
|
-
|
133
|
-
|
134
|
-
|
151
|
+
# This indicates a code/model setup error, stop for this org
|
152
|
+
self.stderr.write(self.style.ERROR(
|
153
|
+
f" Configuration Error: Reverse relation '{relation_name}' not found on Order model. Check OrderGeocodeData model definition (related_name). Skipping organizer '{organizer.slug}'."))
|
154
|
+
continue # Skip this organizer
|
135
155
|
except Exception as e:
|
136
|
-
|
137
|
-
|
156
|
+
# Catch other potential errors during query construction
|
157
|
+
self.stderr.write(self.style.ERROR(
|
158
|
+
f" Error checking relation '{relation_name}': {e}. Skipping organizer '{organizer.slug}'."))
|
159
|
+
continue # Skip this organizer
|
138
160
|
else:
|
161
|
+
# If forcing, process all orders that matched the initial filters (paid, event)
|
139
162
|
orders_to_process_qs = orders_qs
|
140
|
-
self.stdout.write(
|
163
|
+
self.stdout.write(
|
164
|
+
self.style.WARNING(" Processing ALL selected paid orders (--force-recode specified)..."))
|
141
165
|
|
142
166
|
# --- Process orders for this scope ---
|
143
|
-
current_org_orders_count = orders_to_process_qs.count()
|
144
|
-
all_checked_for_org = orders_qs.count()
|
145
|
-
total_processed_orders += all_checked_for_org
|
167
|
+
current_org_orders_count = orders_to_process_qs.count() # Count orders to queue
|
168
|
+
all_checked_for_org = orders_qs.count() # Count all orders checked for this filter set
|
169
|
+
total_processed_orders += all_checked_for_org # Add to overall total
|
146
170
|
|
147
171
|
if current_org_orders_count == 0:
|
148
172
|
self.stdout.write(f" No orders need geocoding ({all_checked_for_org} checked).")
|
149
|
-
continue
|
173
|
+
continue # Skip to next organizer
|
150
174
|
|
151
175
|
self.stdout.write(
|
152
176
|
f" Found {current_org_orders_count} order(s) to potentially geocode ({all_checked_for_org} checked).")
|
153
177
|
org_queued = 0
|
154
178
|
org_skipped = 0
|
155
179
|
|
156
|
-
|
180
|
+
# Iterate and queue tasks
|
181
|
+
for order in orders_to_process_qs.iterator(): # Use iterator for memory efficiency
|
157
182
|
if dry_run:
|
183
|
+
# Provide slightly more info in dry run
|
158
184
|
self.stdout.write(
|
159
|
-
f" [DRY RUN] Would queue Order: {order.code} (PK: {order.pk}) Event: {order.event.slug}")
|
185
|
+
f" [DRY RUN] Would queue Order: {order.code} (PK: {order.pk}, Org PK: {current_organizer_pk}) Event: {order.event.slug}")
|
160
186
|
org_queued += 1
|
161
187
|
else:
|
162
188
|
try:
|
163
|
-
# --- Pass user_agent to task ---
|
189
|
+
# --- Pass user_agent AND organizer_pk to the task ---
|
164
190
|
geocode_order_task.apply_async(
|
165
|
-
args=[order.pk],
|
166
|
-
kwargs={
|
191
|
+
args=[order.pk], # Positional arg is order_pk
|
192
|
+
kwargs={
|
193
|
+
'nominatim_user_agent': user_agent,
|
194
|
+
'organizer_pk': current_organizer_pk # Pass organizer PK
|
195
|
+
}
|
167
196
|
)
|
197
|
+
# Don't log every single queue success unless verbose requested
|
168
198
|
org_queued += 1
|
169
199
|
except Exception as e:
|
170
|
-
|
200
|
+
# Log error if queueing fails
|
201
|
+
self.stderr.write(self.style.ERROR(
|
202
|
+
f" ERROR queuing task for Order {order.code} (PK: {order.pk}): {e}"))
|
171
203
|
logger.exception(f"Failed to queue geocoding task via command for order {order.code}: {e}")
|
172
204
|
org_skipped += 1
|
173
205
|
|
174
|
-
|
206
|
+
# Report summary for the current organizer
|
207
|
+
self.stdout.write(f" Finished Organizer: Queued: {org_queued}, Skipped: {org_skipped}.")
|
175
208
|
total_queued += org_queued
|
176
209
|
total_skipped += org_skipped
|
177
|
-
# End scope
|
210
|
+
# End scope 'with' block
|
178
211
|
|
179
|
-
# --- Final Report ---
|
212
|
+
# --- Final Overall Report ---
|
180
213
|
self.stdout.write("=" * 40)
|
181
214
|
self.stdout.write("Overall Summary:")
|
182
215
|
self.stdout.write(f" Organizers processed: {len(organizers_to_process)}")
|
183
|
-
self.stdout.write(f" Total orders checked (paid): {total_processed_orders}")
|
216
|
+
self.stdout.write(f" Total orders checked (paid, matching filters): {total_processed_orders}")
|
184
217
|
if dry_run:
|
185
218
|
self.stdout.write(
|
186
219
|
self.style.SUCCESS(f"[DRY RUN] Complete. Would have queued tasks for {total_queued} order(s)."))
|
187
220
|
else:
|
188
|
-
self.stdout.write(self.style.SUCCESS(f"Complete.
|
221
|
+
self.stdout.write(self.style.SUCCESS(f"Complete. Successfully queued tasks for {total_queued} order(s)."))
|
189
222
|
if total_skipped > 0:
|
190
|
-
self.stdout.write(
|
191
|
-
|
223
|
+
self.stdout.write(self.style.WARNING(
|
224
|
+
f"Skipped {total_skipped} order(s) total due to errors during queueing (check logs)."))
|
192
225
|
self.stdout.write("=" * 40)
|
@@ -3,7 +3,6 @@ from django.dispatch import receiver
|
|
3
3
|
from django.urls import reverse, NoReverseMatch
|
4
4
|
from django.utils.translation import gettext_lazy as _
|
5
5
|
from django.http import HttpRequest
|
6
|
-
# Import Django settings to read config in web process
|
7
6
|
from django.conf import settings
|
8
7
|
|
9
8
|
# --- Pretix Signals ---
|
@@ -13,50 +12,56 @@ from pretix.control.signals import nav_event
|
|
13
12
|
# --- Tasks ---
|
14
13
|
from .tasks import geocode_order_task
|
15
14
|
# --- Geocoding Default ---
|
16
|
-
from .geocoding import DEFAULT_NOMINATIM_USER_AGENT
|
15
|
+
from .geocoding import DEFAULT_NOMINATIM_USER_AGENT
|
17
16
|
|
18
17
|
logger = logging.getLogger(__name__)
|
19
18
|
|
20
19
|
# --- Constants ---
|
21
20
|
MAP_VIEW_URL_NAME = 'plugins:pretix_mapplugin:event.settings.salesmap.show'
|
22
21
|
REQUIRED_MAP_PERMISSION = 'can_view_orders'
|
23
|
-
PLUGIN_NAME = 'pretix_mapplugin'
|
22
|
+
PLUGIN_NAME = 'pretix_mapplugin'
|
24
23
|
|
25
24
|
|
26
|
-
# --- Signal Receiver for Geocoding (
|
25
|
+
# --- Signal Receiver for Geocoding (Passes organizer_pk) ---
|
27
26
|
@receiver(order_paid, dispatch_uid="sales_mapper_order_paid_geocode")
|
28
27
|
def trigger_geocoding_on_payment(sender, order, **kwargs):
|
29
28
|
"""
|
30
29
|
Listens for the order_paid signal, reads geocoding config,
|
31
|
-
and queues the geocoding task with
|
30
|
+
and queues the geocoding task with order_pk, organizer_pk, and config.
|
32
31
|
"""
|
33
|
-
user_agent = DEFAULT_NOMINATIM_USER_AGENT
|
32
|
+
user_agent = DEFAULT_NOMINATIM_USER_AGENT
|
33
|
+
organizer_pk = None # Initialize
|
34
34
|
try:
|
35
|
-
#
|
36
|
-
|
35
|
+
# Ensure order has event and organizer before proceeding
|
36
|
+
if not order or not order.event or not order.event.organizer:
|
37
|
+
logger.error(f"Order {order.code} is missing event or organizer information. Cannot queue task.")
|
38
|
+
return
|
39
|
+
|
40
|
+
organizer_pk = order.event.organizer.pk # Get organizer PK
|
41
|
+
|
42
|
+
# --- Read User-Agent from settings ---
|
37
43
|
if hasattr(settings, 'plugins') and hasattr(settings.plugins, PLUGIN_NAME):
|
38
44
|
plugin_settings = getattr(settings.plugins, PLUGIN_NAME)
|
39
|
-
user_agent = plugin_settings.get(
|
40
|
-
'nominatim_user_agent', # Setting name in pretix.cfg
|
41
|
-
DEFAULT_NOMINATIM_USER_AGENT
|
42
|
-
)
|
45
|
+
user_agent = plugin_settings.get('nominatim_user_agent', DEFAULT_NOMINATIM_USER_AGENT)
|
43
46
|
else:
|
44
|
-
logger.warning(
|
45
|
-
f"Could not access settings.plugins.{PLUGIN_NAME}, "
|
46
|
-
"using default Nominatim User-Agent for task."
|
47
|
-
)
|
47
|
+
logger.warning(f"Could not access settings.plugins.{PLUGIN_NAME}, using default User-Agent.")
|
48
48
|
|
49
|
-
# --- Queue task with user_agent as keyword
|
49
|
+
# --- Queue task with user_agent and organizer_pk as keyword arguments ---
|
50
50
|
geocode_order_task.apply_async(
|
51
|
-
args=[order.pk],
|
52
|
-
kwargs={
|
51
|
+
args=[order.pk], # Keep order_pk as positional argument
|
52
|
+
kwargs={
|
53
|
+
'nominatim_user_agent': user_agent,
|
54
|
+
'organizer_pk': organizer_pk # Pass organizer PK
|
55
|
+
}
|
53
56
|
)
|
54
|
-
logger.info(f"Geocoding task queued for paid order {order.code} (PK: {order.pk}).")
|
57
|
+
logger.info(f"Geocoding task queued for paid order {order.code} (PK: {order.pk}, Org PK: {organizer_pk}).")
|
55
58
|
|
56
|
-
except ImportError:
|
59
|
+
except ImportError:
|
57
60
|
logger.exception("Could not import geocode_order_task. Check tasks.py.")
|
58
61
|
except Exception as e:
|
59
|
-
|
62
|
+
# Log the organizer PK as well if available
|
63
|
+
org_info = f" (Org PK: {organizer_pk})" if organizer_pk else ""
|
64
|
+
logger.exception(f"Failed to queue geocoding task for order {order.code}{org_info}: {e}")
|
60
65
|
|
61
66
|
|
62
67
|
# --- Signal Receiver for Adding Navigation Item (No changes needed) ---
|
@@ -0,0 +1,113 @@
|
|
1
|
+
import logging
|
2
|
+
from django.db import transaction
|
3
|
+
from django.core.exceptions import ObjectDoesNotExist
|
4
|
+
|
5
|
+
# --- Import django-scopes ---
|
6
|
+
from django_scopes import scope
|
7
|
+
|
8
|
+
# --- Use Pretix Celery app instance ---
|
9
|
+
from pretix.celery_app import app
|
10
|
+
# --- Import necessary Pretix models ---
|
11
|
+
from pretix.base.models import Order, Organizer # Import Organizer
|
12
|
+
|
13
|
+
# --- Import your Geocode model and geocoding functions ---
|
14
|
+
from .models import OrderGeocodeData
|
15
|
+
from .geocoding import (
|
16
|
+
get_formatted_address_from_order,
|
17
|
+
geocode_address,
|
18
|
+
DEFAULT_NOMINATIM_USER_AGENT
|
19
|
+
)
|
20
|
+
|
21
|
+
logger = logging.getLogger(__name__)
|
22
|
+
|
23
|
+
|
24
|
+
@app.task(bind=True, max_retries=3, default_retry_delay=60, ignore_result=True)
|
25
|
+
# --- Accept organizer_pk as kwarg ---
|
26
|
+
def geocode_order_task(self, order_pk: int, organizer_pk: int | None = None, nominatim_user_agent: str | None = None):
|
27
|
+
"""
|
28
|
+
Celery task to geocode the address for a given order PK.
|
29
|
+
Accepts organizer_pk and Nominatim User-Agent as arguments.
|
30
|
+
Fetches Organizer first, then activates scope.
|
31
|
+
"""
|
32
|
+
organizer = None
|
33
|
+
order = None
|
34
|
+
try:
|
35
|
+
# --- Step 1: Fetch Organizer (unscoped) ---
|
36
|
+
if organizer_pk is None:
|
37
|
+
# This should ideally not happen if called correctly, but handle defensively
|
38
|
+
logger.error(f"organizer_pk not provided for Order PK {order_pk}. Cannot activate scope.")
|
39
|
+
# Depending on policy, you might retry, skip, or raise an error.
|
40
|
+
# Skipping for now.
|
41
|
+
return
|
42
|
+
|
43
|
+
try:
|
44
|
+
organizer = Organizer.objects.get(pk=organizer_pk)
|
45
|
+
except ObjectDoesNotExist:
|
46
|
+
logger.error(f"Organizer with PK {organizer_pk} not found (for Order PK {order_pk}).")
|
47
|
+
# Don't retry if organizer doesn't exist
|
48
|
+
return
|
49
|
+
|
50
|
+
# --- Step 2: Activate Scope ---
|
51
|
+
with scope(organizer=organizer):
|
52
|
+
# --- Step 3: Fetch Order (now within scope) ---
|
53
|
+
try:
|
54
|
+
order = Order.objects.select_related(
|
55
|
+
'invoice_address' # Only need this direct relation now
|
56
|
+
).get(pk=order_pk)
|
57
|
+
except ObjectDoesNotExist:
|
58
|
+
logger.error(f"Order with PK {order_pk} not found within scope of Org {organizer_pk}.")
|
59
|
+
# Don't retry if order doesn't exist in this scope
|
60
|
+
return
|
61
|
+
|
62
|
+
logger.info(
|
63
|
+
f"Starting geocoding task for Order {order.code} (PK: {order_pk}) within scope of Organizer '{organizer.slug}'")
|
64
|
+
|
65
|
+
# --- Rest of the logic runs within scope ---
|
66
|
+
relation_name = 'geocode_data'
|
67
|
+
if OrderGeocodeData.objects.filter(order_id=order_pk).exists():
|
68
|
+
logger.info(f"Geocode data already exists for Order {order.code} (checked within scope). Skipping.")
|
69
|
+
return
|
70
|
+
|
71
|
+
address_str = get_formatted_address_from_order(order)
|
72
|
+
if not address_str:
|
73
|
+
logger.info(f"Order {order.code} has no address suitable for geocoding. Storing null coordinates.")
|
74
|
+
with transaction.atomic():
|
75
|
+
OrderGeocodeData.objects.update_or_create(
|
76
|
+
order=order, defaults={'latitude': None, 'longitude': None}
|
77
|
+
)
|
78
|
+
return
|
79
|
+
|
80
|
+
logger.debug(f"Attempting to geocode address for Order {order.code}: '{address_str}'")
|
81
|
+
coordinates = geocode_address(address_str, nominatim_user_agent=nominatim_user_agent)
|
82
|
+
|
83
|
+
with transaction.atomic():
|
84
|
+
if coordinates:
|
85
|
+
latitude, longitude = coordinates
|
86
|
+
obj, created = OrderGeocodeData.objects.update_or_create(
|
87
|
+
order=order, defaults={'latitude': latitude, 'longitude': longitude}
|
88
|
+
)
|
89
|
+
log_level = logging.INFO if created else logging.DEBUG
|
90
|
+
logger.log(log_level,
|
91
|
+
f"Saved{' new' if created else ' updated'} geocode data for Order {order.code}: ({latitude}, {longitude})")
|
92
|
+
else:
|
93
|
+
logger.warning(f"Geocoding failed for Order {order.code}. Storing null coordinates.")
|
94
|
+
obj, created = OrderGeocodeData.objects.update_or_create(
|
95
|
+
order=order, defaults={'latitude': None, 'longitude': None}
|
96
|
+
)
|
97
|
+
log_level = logging.INFO if created else logging.DEBUG
|
98
|
+
logger.log(log_level,
|
99
|
+
f"Saved{' new' if created else ' updated'} null geocode data for Order {order.code} after failed attempt.")
|
100
|
+
# --- Scope deactivated automatically ---
|
101
|
+
|
102
|
+
# --- Outer exception handling ---
|
103
|
+
except ObjectDoesNotExist:
|
104
|
+
# Should be caught earlier now, but keep for safety
|
105
|
+
obj_type = "Organizer" if organizer is None else "Order"
|
106
|
+
obj_pk = organizer_pk if organizer is None else order_pk
|
107
|
+
logger.error(f"{obj_type} with PK {obj_pk} not found.")
|
108
|
+
except Exception as e:
|
109
|
+
org_info = f" (Org PK: {organizer_pk})" if organizer_pk else ""
|
110
|
+
order_info = f" (Order PK: {order_pk})" if order_pk else ""
|
111
|
+
logger.exception(f"Unexpected error in geocode_order_task{org_info}{order_info}: {e}")
|
112
|
+
# Retry on potentially temporary errors
|
113
|
+
raise self.retry(exc=e)
|
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = "0.1.0"
|
@@ -1,90 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
from django.db import transaction
|
3
|
-
from django.core.exceptions import ObjectDoesNotExist
|
4
|
-
|
5
|
-
# --- Use Pretix Celery app instance ---
|
6
|
-
from pretix.celery_app import app
|
7
|
-
# --- Import necessary Pretix models ---
|
8
|
-
from pretix.base.models import Order
|
9
|
-
|
10
|
-
# --- Import your Geocode model and geocoding functions ---
|
11
|
-
from .models import OrderGeocodeData
|
12
|
-
from .geocoding import (
|
13
|
-
get_formatted_address_from_order,
|
14
|
-
geocode_address,
|
15
|
-
DEFAULT_NOMINATIM_USER_AGENT # Import default for safety/logging
|
16
|
-
)
|
17
|
-
|
18
|
-
logger = logging.getLogger(__name__)
|
19
|
-
|
20
|
-
|
21
|
-
# Define the Celery task
|
22
|
-
# bind=True gives access to self (the task instance) for retrying
|
23
|
-
# ignore_result=True as we don't need the return value stored in Celery backend
|
24
|
-
@app.task(bind=True, max_retries=3, default_retry_delay=60, ignore_result=True)
|
25
|
-
def geocode_order_task(self, order_pk: int,
|
26
|
-
nominatim_user_agent: str | None = None): # Added nominatim_user_agent kwarg
|
27
|
-
"""
|
28
|
-
Celery task to geocode the address for a given order PK.
|
29
|
-
Accepts the Nominatim User-Agent as an argument.
|
30
|
-
"""
|
31
|
-
try:
|
32
|
-
# Fetch order with related address and country data efficiently
|
33
|
-
order = Order.objects.select_related(
|
34
|
-
'invoice_address',
|
35
|
-
).get(pk=order_pk)
|
36
|
-
logger.info(f"Starting geocoding task for Order {order.code} (PK: {order_pk})")
|
37
|
-
|
38
|
-
# Check if already geocoded to prevent redundant work
|
39
|
-
# Replace 'geocode_data' if your related_name is different
|
40
|
-
relation_name = 'geocode_data' # Ensure this matches your OrderGeocodeData.order related_name
|
41
|
-
if hasattr(order, relation_name) and getattr(order, relation_name) is not None:
|
42
|
-
logger.info(f"Geocode data already exists for Order {order.code}. Skipping.")
|
43
|
-
return # Exit successfully
|
44
|
-
|
45
|
-
# 1. Get formatted address string
|
46
|
-
address_str = get_formatted_address_from_order(order)
|
47
|
-
if not address_str:
|
48
|
-
logger.info(f"Order {order.code} has no address suitable for geocoding. Storing null coordinates.")
|
49
|
-
# Store null to prevent reprocessing
|
50
|
-
with transaction.atomic():
|
51
|
-
OrderGeocodeData.objects.update_or_create(
|
52
|
-
order=order,
|
53
|
-
defaults={'latitude': None, 'longitude': None}
|
54
|
-
)
|
55
|
-
return # Exit successfully, nothing to geocode
|
56
|
-
|
57
|
-
# 2. Perform geocoding, passing the user agent received by the task
|
58
|
-
logger.debug(f"Attempting to geocode address for Order {order.code}: '{address_str}'")
|
59
|
-
coordinates = geocode_address(address_str, nominatim_user_agent=nominatim_user_agent)
|
60
|
-
|
61
|
-
# 3. Store result (or null if failed) using atomic transaction
|
62
|
-
with transaction.atomic():
|
63
|
-
if coordinates:
|
64
|
-
latitude, longitude = coordinates
|
65
|
-
obj, created = OrderGeocodeData.objects.update_or_create(
|
66
|
-
order=order,
|
67
|
-
defaults={'latitude': latitude, 'longitude': longitude}
|
68
|
-
)
|
69
|
-
log_level = logging.INFO if created else logging.DEBUG # Be less noisy on updates
|
70
|
-
logger.log(log_level,
|
71
|
-
f"Saved{' new' if created else ' updated'} geocode data for Order {order.code}: ({latitude}, {longitude})")
|
72
|
-
else:
|
73
|
-
logger.warning(f"Geocoding failed for Order {order.code}. Storing null coordinates.")
|
74
|
-
# Store nulls to indicate an attempt was made and failed
|
75
|
-
obj, created = OrderGeocodeData.objects.update_or_create(
|
76
|
-
order=order,
|
77
|
-
defaults={'latitude': None, 'longitude': None}
|
78
|
-
)
|
79
|
-
log_level = logging.INFO if created else logging.DEBUG
|
80
|
-
logger.log(log_level,
|
81
|
-
f"Saved{' new' if created else ' updated'} null geocode data for Order {order.code} after failed attempt.")
|
82
|
-
|
83
|
-
except ObjectDoesNotExist: # More specific exception
|
84
|
-
logger.error(f"Order with PK {order_pk} not found in geocode_order_task.")
|
85
|
-
# Don't retry if the order doesn't exist
|
86
|
-
except Exception as e:
|
87
|
-
# Catch any other unexpected errors
|
88
|
-
logger.exception(f"Unexpected error in geocode_order_task for Order PK {order_pk}: {e}")
|
89
|
-
# Retry on potentially temporary errors (database, network issues etc.)
|
90
|
-
raise self.retry(exc=e) # Let Celery handle retry logic
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/locale/de_Informal/LC_MESSAGES/django.mo
RENAMED
File without changes
|
{pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/locale/de_Informal/LC_MESSAGES/django.po
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/css/salesmap.css
RENAMED
File without changes
|
{pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/static/pretix_mapplugin/js/salesmap.js
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pretix_map-0.1.0 → pretix_map-0.1.2}/pretix_mapplugin/templates/pretix_mapplugin/map_page.html
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|