diff --git a/dav_base/static/dav_base/css/local.css b/dav_base/static/dav_base/css/local.css
index 51487ee..b7362e3 100644
--- a/dav_base/static/dav_base/css/local.css
+++ b/dav_base/static/dav_base/css/local.css
@@ -147,4 +147,34 @@ thead input {
*/
.no-padding {
padding: 0px;
+}
+
+/*
+ * We need more label colors
+ */
+.label-black {
+ background-color: #333;
+}
+.label-dav-brown {
+ background-color: #925f36;
+}
+.label-dav-purple {
+ background-color: #a694c2;
+}
+.label-dav-cyan {
+ background-color: #86cfe4;
+}
+
+/*
+ * We need more button colors
+ */
+.btn-black {
+ background-color: #333;
+ border-color: #ccc;
+ color: #fff;
+}
+.btn-black.focus, .btn-black:focus, .btn-black:hover {
+ background-color: #555;
+ border-color: #ccc;
+ color: #fff;
}
\ No newline at end of file
diff --git a/dav_events/models/eventstatus.py b/dav_events/models/eventstatus.py
index ee2a221..90b255e 100644
--- a/dav_events/models/eventstatus.py
+++ b/dav_events/models/eventstatus.py
@@ -12,6 +12,7 @@ BOOTSTRAP_CONTEXT_CHOICES = (
('info', 'info'),
('warning', 'warning'),
('danger', 'danger'),
+ ('black', 'black'),
)
diff --git a/dav_events/templates/dav_events/event_detail.html b/dav_events/templates/dav_events/event_detail.html
index 0440de5..f4b95c9 100644
--- a/dav_events/templates/dav_events/event_detail.html
+++ b/dav_events/templates/dav_events/event_detail.html
@@ -145,6 +145,17 @@
{% trans 'Veröffentlichung bestätigen' %}
{% endif %}
+ {% if has_permission_clear %}
+
+ {% if is_cleared %}
+ {% bootstrap_icon 'check' %}
+ {% else %}
+ {% bootstrap_icon 'unchecked' %}
+ {% endif %}
+ {% trans 'Abgerechnet' %}
+
+ {% endif %}
diff --git a/dav_events/tests/test_screenshots.py b/dav_events/tests/test_screenshots.py
index 44ec355..f0246ab 100644
--- a/dav_events/tests/test_screenshots.py
+++ b/dav_events/tests/test_screenshots.py
@@ -19,8 +19,8 @@ TEST_EVENT_DATA_S = {
'mode': 'training',
'sport': 'S',
'ski_lift': True,
- 'first_day': '24.12.2019',
- 'last_day': '26.12.2019',
+ 'first_day': '24.12.2020',
+ 'last_day': '26.12.2020',
'country': 'CH',
'location': u'St. Antönien',
'transport_other': 'Helikopter & SUV',
@@ -32,7 +32,7 @@ TEST_EVENT_DATA_S = {
'accommodation': 'NONE',
'meals_other': u'Fünf-Sterne-Küche per Zimmerservice und Minibar',
'requirements_add': u': https://de.wikipedia.org/wiki/Heliskiing',
- 'pre_meeting_1': '10.12.2019 18:35',
+ 'pre_meeting_1': '10.12.2020 18:35',
'trainer_firstname': u'Trainer1 Ö.',
'trainer_familyname': u'Ä. Tourenleiter',
'trainer_email': TEST_TRAINER_EMAIL,
@@ -64,8 +64,8 @@ TEST_EVENT_DATA_S = {
}
TEST_EVENT_DATA_W = {
'level': 'advanced',
- 'first_day': '21.6.2019',
- 'alt_first_day': '22.06.2019',
+ 'first_day': '21.6.2020',
+ 'alt_first_day': '22.06.2020',
'terrain': 'flats',
'location': u'Karlsruhe (Schloßpark)',
'transport': 'public',
@@ -624,6 +624,38 @@ class TestCase(SeleniumAuthMixin, RoleMixin, ScreenshotTestCase):
if screenshots:
self.save_screenshot('event_list_after', sequence=sequence_name)
+ def clear_event(self, title, screenshots=True):
+ c = self.selenium
+
+ sequence_name = 'clear'
+
+ c.get(self.complete_url(reverse('dav_events:root')))
+ button = self.wait_on_presence(c, (By.ID, 'btn-events-list'))
+ button.click()
+ self.wait_until_stale(c, button)
+
+ if screenshots:
+ self.save_screenshot('event_list_before', sequence=sequence_name)
+
+ link = c.find_element_by_link_text(title)
+ link.click()
+ self.wait_until_stale(c, link)
+
+ if screenshots:
+ self.save_screenshot('event_details', sequence=sequence_name)
+
+ button = c.find_element_by_id('btn-confirmclearance')
+ button.click()
+ self.wait_until_stale(c, button)
+ if screenshots:
+ self.save_screenshot('confirmed_clearance', sequence=sequence_name)
+
+ link = c.find_element_by_link_text(ugettext('Veranstaltungsliste'))
+ link.click()
+ self.wait_until_stale(c, link)
+ if screenshots:
+ self.save_screenshot('event_list_after', sequence=sequence_name)
+
def setUp(self):
super(TestCase, self).setUp()
@@ -699,3 +731,8 @@ class TestCase(SeleniumAuthMixin, RoleMixin, ScreenshotTestCase):
self.wait_until_stale(c, link)
self.save_screenshot('event_export_form')
self.logout(c)
+
+ self.login(c, self.manager_super.username, TEST_PASSWORD)
+ self.clear_event(TEST_EVENT_DATA_M['title'])
+ self.logout(c)
+
diff --git a/dav_events/views/events.py b/dav_events/views/events.py
index 11874d2..6431087 100644
--- a/dav_events/views/events.py
+++ b/dav_events/views/events.py
@@ -150,6 +150,7 @@ class EventDetailView(EventPermissionMixin, generic.DetailView):
context['has_permission_submit'] = self.has_permission('submit', obj)
context['has_permission_accept'] = self.has_permission('accept', obj)
context['has_permission_publish'] = self.has_permission('publish', obj)
+ context['has_permission_clear'] = self.has_permission('clear', obj)
context['has_permission_update'] = self.has_permission('update', obj)
context['is_submitted'] = obj.workflow.has_reached_status('submitted')
context['is_accepted'] = obj.workflow.has_reached_status('accepted')
@@ -157,6 +158,7 @@ class EventDetailView(EventPermissionMixin, generic.DetailView):
context['is_publishing_any'] = obj.workflow.has_reached_status('publishing*')
context['is_published'] = obj.workflow.has_reached_status('published')
context['is_published_any'] = obj.workflow.has_reached_status('published*')
+ context['is_cleared'] = obj.workflow.has_reached_status('cleared')
return context
@method_decorator(login_required)
@@ -436,6 +438,9 @@ class EventUpdateStatusView(EventPermissionMixin, generic.DetailView):
elif status.startswith('publish'):
if not self.has_permission('publish', event):
raise PermissionDenied(status)
+ elif status.startswith('clear'):
+ if not self.has_permission('clear', event):
+ raise PermissionDenied(status)
else:
if not self.has_permission('update', event):
raise PermissionDenied(status)
@@ -457,6 +462,8 @@ class EventUpdateStatusView(EventPermissionMixin, generic.DetailView):
messages.success(request, _(u'Veranstaltung freigegeben.'))
elif status.startswith('publish'):
messages.success(request, _(u'Veröffentlichung registriert.'))
+ elif status.startswith('clear'):
+ messages.success(request, _(u'Abrechnung vermerkt.'))
else:
messages.success(request, _(u'Veranstaltungsstatus registriert.'))
diff --git a/dav_events/workflow.py b/dav_events/workflow.py
index c9c0713..69195d5 100644
--- a/dav_events/workflow.py
+++ b/dav_events/workflow.py
@@ -30,6 +30,7 @@ DEFAULT_EVENT_STATI = {
'published_web': (79, _(u'Veröffentlicht (Web)'), 'success'),
'published': (80, _(u'Veröffentlicht'), 'success'),
'expired': (100, _(u'Ausgelaufen'), None),
+ 'cleared': (110, _(u'Abgerechnet'), 'black'),
}
@@ -429,6 +430,9 @@ class BasicWorkflow(object):
elif permission == 'publish':
if has_role(user, 'publisher'):
return True
+ elif permission == 'clear':
+ if has_role(user, 'manager_super'):
+ return True
elif permission == 'update':
if not self.has_reached_status('submitted'):
if user == event.owner: