diff --git a/RIGS/forms.py b/RIGS/forms.py
index d3dfb39e..922558c3 100644
--- a/RIGS/forms.py
+++ b/RIGS/forms.py
@@ -84,11 +84,16 @@ class EventForm(forms.ModelForm):
return items
def _get_or_initialise_item(self, pk, data, event):
- if (pk < 0):
+ try:
+ item = models.EventItem.objects.get(pk=pk,event=event)
+ except models.EventItem.DoesNotExist:
+ # This occurs for one of two reasons
+ # 1) The event has been duplicated, so the item PKs belong to another event
+ # 2) The items are brand new, with negative PK values
+ # In either case, we want to create the items
item = models.EventItem()
- else:
- item = models.EventItem.objects.get(pk=pk)
+ # Take the data from the form and update the item object
item.name = data['name']
item.description = data['description']
item.quantity = data['quantity']
diff --git a/RIGS/rigboard.py b/RIGS/rigboard.py
index b13a19c8..42a79b3b 100644
--- a/RIGS/rigboard.py
+++ b/RIGS/rigboard.py
@@ -18,6 +18,7 @@ from PyPDF2 import PdfFileMerger, PdfFileReader
from RIGS import models, forms
import datetime
import re
+import copy
__author__ = 'ghost'
@@ -85,6 +86,23 @@ class EventUpdate(generic.UpdateView):
def get_success_url(self):
return reverse_lazy('event_detail', kwargs={'pk': self.object.pk})
+class EventDuplicate(EventUpdate):
+ def get_object(self, queryset=None):
+ old = super(EventDuplicate, self).get_object(queryset) # Get the object (the event you're duplicating)
+ new = copy.copy(old) # Make a copy of the object in memory
+ new.based_on = old # Make the new event based on the old event
+
+ if self.request.method in ('POST', 'PUT'): # This only happens on save (otherwise items won't display in editor)
+ new.pk = None # This means a new event will be created on save, and all items will be re-created
+
+ messages.info(self.request, 'Event data duplicated but not yet saved. Click save to complete operation.')
+
+ return new
+
+ def get_context_data(self, **kwargs):
+ context = super(EventDuplicate, self).get_context_data(**kwargs)
+ context["duplicate"] = True
+ return context
class EventPrint(generic.View):
def get(self, request, pk):
@@ -133,24 +151,6 @@ class EventPrint(generic.View):
response.write(merged.getvalue())
return response
-
-class EventDuplicate(generic.RedirectView):
- permanent = False;
- def get_redirect_url(self, *args, **kwargs):
- new = get_object_or_404(models.Event, pk=kwargs['pk'])
- new.pk = None
- new.based_on = models.Event.objects.get(pk=kwargs['pk'])
- new.save()
-
- old = get_object_or_404(models.Event, pk=kwargs['pk'])
- for item in old.items.all():
- item.pk = None
- item.event = new
- item.save()
-
- return reverse_lazy('event_update', kwargs={'pk': new.pk})
-
-
class EventArchive(generic.ArchiveIndexView):
model = models.Event
date_field = "start_date"
diff --git a/RIGS/templates/RIGS/event_form.html b/RIGS/templates/RIGS/event_form.html
index 4d3c3509..b0b94e14 100644
--- a/RIGS/templates/RIGS/event_form.html
+++ b/RIGS/templates/RIGS/event_form.html
@@ -123,7 +123,9 @@
- {% if object.pk %}
+ {% if duplicate %}
+ Duplicate of Event N{{ object.pk|stringformat:"05d" }}
+ {% elif object.pk %}
Event N{{ object.pk|stringformat:"05d" }}
{% else %}
New Event
diff --git a/RIGS/test_functional.py b/RIGS/test_functional.py
index 65f83252..9cf38f2f 100644
--- a/RIGS/test_functional.py
+++ b/RIGS/test_functional.py
@@ -425,6 +425,83 @@ class EventTest(LiveServerTestCase):
event = models.Event.objects.get(name='Test Event Name')
self.assertIn("N0000%d | Test Event Name"%event.pk, self.browser.find_element_by_xpath('//h1').text)
+ def testEventDuplicate(self):
+ testEvent = models.Event.objects.create(name="TE E1", status=models.Event.PROVISIONAL, start_date=date.today() + timedelta(days=6), description="start future no end")
+
+ item1 = models.EventItem(
+ event=testEvent,
+ name="Test Item 1",
+ cost="10.00",
+ quantity="1",
+ order=1
+ ).save()
+ item2 = models.EventItem(
+ event=testEvent,
+ name="Test Item 2",
+ description="Foo",
+ cost="9.72",
+ quantity="3",
+ order=2,
+ ).save()
+
+ self.browser.get(self.live_server_url + '/event/' + str(testEvent.pk) + '/duplicate/')
+ self.authenticate('/event/' + str(testEvent.pk) + '/duplicate/')
+
+ wait = WebDriverWait(self.browser, 10) #setup WebDriverWait to use later (to wait for animations)
+ self.browser.implicitly_wait(3) #Set session-long wait (only works for non-existant DOM objects)
+
+ save = self.browser.find_element_by_xpath(
+ '(//button[@type="submit"])[3]')
+ form = self.browser.find_element_by_tag_name('form')
+
+
+ # Check the items are visible
+ table = self.browser.find_element_by_id('item-table') # ID number is known, see above
+ self.assertIn("Test Item 1", table.text)
+ self.assertIn("Test Item 2", table.text)
+
+ # Add item
+ form.find_element_by_xpath('//button[contains(@class, "item-add")]').click()
+ wait.until(animation_is_finished())
+ modal = self.browser.find_element_by_id("itemModal")
+ modal.find_element_by_id("item_name").send_keys("Test Item 3")
+ modal.find_element_by_id("item_description").send_keys("This is an item description\nthat for reasons unkown spans two lines")
+ e = modal.find_element_by_id("item_quantity")
+ e.click()
+ e.send_keys(Keys.UP)
+ e.send_keys(Keys.UP)
+ e = modal.find_element_by_id("item_cost")
+ e.send_keys("23.95")
+ e.send_keys(Keys.ENTER) # enter submit
+
+ # Attempt to save
+ save.click()
+
+ self.assertNotIn("N0000%d"%testEvent.pk, self.browser.find_element_by_xpath('//h1').text)
+
+ # Check the new items are visible
+ table = self.browser.find_element_by_id('item-table') # ID number is known, see above
+ self.assertIn("Test Item 1", table.text)
+ self.assertIn("Test Item 2", table.text)
+ self.assertIn("Test Item 3", table.text)
+
+ infoPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Event Info")]/..')
+ self.assertIn("N0000%d"%testEvent.pk, infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
+
+
+
+ self.browser.get(self.live_server_url + '/event/' + str(testEvent.pk)) #Go back to the old event
+
+ #Check that based-on hasn't crept into the old event
+ infoPanel = self.browser.find_element_by_xpath('//div[contains(text(), "Event Info")]/..')
+ self.assertNotIn("N0000%d"%testEvent.pk, infoPanel.find_element_by_xpath('//dt[text()="Based On"]/following-sibling::dd[1]').text)
+
+ # Check the items are as they were
+ table = self.browser.find_element_by_id('item-table') # ID number is known, see above
+ self.assertIn("Test Item 1", table.text)
+ self.assertIn("Test Item 2", table.text)
+ self.assertNotIn("Test Item 3", table.text)
+
def testDateValidation(self):
self.browser.get(self.live_server_url + '/event/create/')
# Gets redirected to login and back