Skip to content
This repository has been archived by the owner on Sep 5, 2019. It is now read-only.

Commit

Permalink
Adds an occupancy report to reservation resources
Browse files Browse the repository at this point in the history
Resolves #183
  • Loading branch information
Denis Krienbühl committed May 12, 2016
1 parent 8669db8 commit ff329a7
Show file tree
Hide file tree
Showing 15 changed files with 444 additions and 176 deletions.
3 changes: 3 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
Changelog
---------

- Adds an occupancy report to reservation resources.
[href]

- Fixes unreserved allocations showing associated tickets.
[href]

Expand Down
9 changes: 2 additions & 7 deletions onegov/town/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,15 +224,8 @@ def get_sortable_asset():
yield 'sortable_custom.js'


@TownApp.webasset('events')
def get_events_asset():
yield 'url.js'
yield 'events.js'


@TownApp.webasset('fullcalendar')
def get_fullcalendar_asset():
yield 'url.js'
yield 'fullcalendar.css'
yield 'moment.js'
yield 'moment.de.js'
Expand Down Expand Up @@ -305,4 +298,6 @@ def get_common_asset():
yield 'jquery.popupoverlay.js'
yield 'videoframe.js'
yield 'datetimepicker.js'
yield 'url.js'
yield 'date-range-selector.js'
yield 'common.js'
21 changes: 21 additions & 0 deletions onegov/town/assets/js/date-range-selector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// set date filter on input change
var set_date_range_selector_filter = function(name, value) {
var location = new Url();
location.query[name] = convert_date(value, datetimepicker_i18n[get_locale()].format, 'Y-m-d');
delete location.query.page;
window.location.href = location.toString();
};

if (Modernizr.inputtypes.date) {
$('.date-range-selector input[type="date"]').on('input', function() {
set_date_range_selector_filter($(this).attr('name'), $(this).val());
});
} else {
$('.date-range-selector input[type="date"]').each(function() {
$(this).datetimepicker({
onChangeDateTime: function(_dp, $input) {
set_date_range_selector_filter($input.attr('name'), $input.val());
}
});
});
}
21 changes: 0 additions & 21 deletions onegov/town/assets/js/events.js

This file was deleted.

7 changes: 7 additions & 0 deletions onegov/town/assets/js/reservationcalendar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,13 @@ rc.setupHistory = function(fcOptions) {
url.query.view = view.name;
url.query.date = view.intervalStart.format('YYYYMMDD');

$('a.calendar-dependent').each(function(_ix, el) {
var dependentUrl = new Url($(el).attr('href'));
dependentUrl.query.view = url.query.view;
dependentUrl.query.date = url.query.date;
$(el).attr('href', dependentUrl.toString());
});

var state = [
{
'view': view.name,
Expand Down
10 changes: 10 additions & 0 deletions onegov/town/layout.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import sedate

from cached_property import cached_property
from dateutil import rrule
from onegov.core.layout import ChameleonLayout
Expand Down Expand Up @@ -69,6 +71,9 @@ def primary_color(self):
return self.town.theme_options.get(
'primary-color', user_options['primary-color'])

def today(self):
return sedate.to_timezone(sedate.utcnow(), self.timezone).date()

@cached_property
def default_map_view(self):
return self.town.default_map_view or None
Expand Down Expand Up @@ -780,6 +785,11 @@ def editbar_links(self):
url=self.request.link(self.model, 'cleanup'),
classes=('cleanup-link', )
),
Link(
text=_("Occupancy"),
url=self.request.link(self.model, 'belegung'),
classes=('occupancy-link', 'calendar-dependent')
)
]


Expand Down
17 changes: 10 additions & 7 deletions onegov/town/locale/de_ch/LC_MESSAGES/onegov.town.po
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE 1.0\n"
"POT-Creation-Date: 2016-04-28 16:18+0200\n"
"POT-Creation-Date: 2016-05-11 14:15+0200\n"
"PO-Revision-Date: 2015-10-15 09:42+0200\n"
"Last-Translator: Denis Krienbühl <denis.krienbuehl@seantis.ch>\n"
"Language-Team: German\n"
Expand Down Expand Up @@ -145,6 +145,9 @@ msgstr "Es existieren Reservationen für diese Reservations-Ressource"
msgid "Clean up"
msgstr "Aufräumen"

msgid "Occupancy"
msgstr "Belegung"

msgid "Do you really want to delete this event?"
msgstr "Möchten Sie die Veranstaltung wirklich löschen?"

Expand Down Expand Up @@ -692,12 +695,6 @@ msgstr "Möchten Sie wirklich alle Reservationen absagen?"
msgid "Rejecting these reservations can't be undone."
msgstr "Die Absage aller Reservationen kann nicht rückgängig gemacht werden."

msgid "Edit details"
msgstr "Details bearbeiten"

msgid "Accept event"
msgstr "Veranstaltung annehmen"

#, python-format
msgid "Reject ${title}"
msgstr "${title} absagen"
Expand All @@ -712,6 +709,12 @@ msgstr "Die Absage von ${title} kann nicht rückgängig gemacht werden."
msgid "Reject reservation"
msgstr "Reservation absagen"

msgid "Edit details"
msgstr "Details bearbeiten"

msgid "Accept event"
msgstr "Veranstaltung annehmen"

msgid "Link"
msgstr "Verknüpfung"

Expand Down
6 changes: 6 additions & 0 deletions onegov/town/models/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ class DaypassResource(Resource, HiddenFromPublicExtension, SearchableResource,
# the default view
view = 'month'

# show or hide quota numbers in reports
show_quota = True


class RoomResource(Resource, HiddenFromPublicExtension, SearchableResource,
ContactExtension, PersonLinkExtension,
Expand All @@ -105,3 +108,6 @@ class RoomResource(Resource, HiddenFromPublicExtension, SearchableResource,

# the default view
view = 'agendaWeek'

# show or hide quota numbers in reports
show_quota = False
36 changes: 34 additions & 2 deletions onegov/town/templates/macros.pt
Original file line number Diff line number Diff line change
Expand Up @@ -503,11 +503,11 @@
</div>
</metal:atoz>

<metal:calendar_day_box define-macro="calendar-day" i18n:domain="onegov.town">
<metal:calendar_day define-macro="calendar-day" i18n:domain="onegov.town">
<h2 class="calendar-day-box">
<metal:block use-macro="layout.macros['calendar-day-content']" />
</h2>
</metal:calendar_day_box>
</metal:calendar_day>

<metal:calendar_day_box define-macro="calendar-day-content" i18n:domain="onegov.town">
<span>${layout.format_date(date, 'weekday_long')}</span>
Expand Down Expand Up @@ -541,3 +541,35 @@
<div tal:condition="not occurrences" i18n:translate="">No events found.</div>
</tal:block>
</metal:occurrences>

<metal:date_range_selector define-macro="date-range-selector" i18n:domain="onegov.town">
<div class="date-range-selector">
<form action="" method="GET">
<div metal:define-slot="before-date-range"></div>

<div class="row date-range-selector">
<div class="large-6 columns">
<div class="row collapse">
<label i18n:translate="">From</label>
<input class="small" name="start" type="date" value="${start}" placeholder="${layout.today().isoformat()}">
</div>
</div>
<div class="large-6 columns">
<div class="row collapse">
<label i18n:translate="">To</label>
<input class="small" name="end" type="date" value="${end}" placeholder="${layout.today().isoformat()}">
</div>
</div>
</div>
<noscript>
<div class="row">
<div class="large-6 columns">
<div class="row collapse">
<input type="submit" value="Filter by date" class="button" i18n:attributes="value">
</div>
</div>
</div>
</noscript>
</form>
</div>
</metal:date_range_selector>
33 changes: 5 additions & 28 deletions onegov/town/templates/occurrences.pt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

<div class="large-4 medium-4 columns">

<div class="occurrences-filter-result">
<div class="date-range-selector-result">
<span>${number_of_occurrences}</span>
<span i18n:translate="">Events</span>
</div>
Expand All @@ -33,36 +33,13 @@
</tal:block>
</div>

<div class="occurrences-filter-date">
<form action="" method="GET">
<metal:block use-macro="layout.macros['date-range-selector']">
<tal:block metal:fill-slot="before-date-range">
<tal:block tal:repeat="tag active_tags">
<input type="hidden" name="tags" value="${tag}">
</tal:block>
<div class="row">
<div class="large-6 columns">
<div class="row collapse">
<label i18n:translate="">From</label>
<input class="small" name="start" type="date" value="${start}" placeholder="${date_placeholder}">
</div>
</div>
<div class="large-6 columns">
<div class="row collapse">
<label i18n:translate="">To</label>
<input class="small" name="end" type="date" value="${end}" placeholder="${date_placeholder}">
</div>
</div>
</div>
<noscript>
<div class="row occurrences-filter-date-submit">
<div class="large-6 columns">
<div class="row collapse">
<input type="submit" value="Filter by date" class="button" i18n:attributes="value">
</div>
</div>
</div>
</noscript>
</form>
</div>
</tal:block>
</metal:block>

<div class="occurrences-add-box">
<dl>
Expand Down
54 changes: 54 additions & 0 deletions onegov/town/templates/resource_occupancy.pt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<div metal:use-macro="layout.base" i18n:domain="onegov.town">
<tal:block metal:fill-slot="title">
${title}
</tal:block>
<tal:block metal:fill-slot="content">
<span class="page-lead">
<tal:block condition="start != end">
${layout.format_date(start, 'date_long')} - ${layout.format_date(end, 'date_long')}
</tal:block>
<tal:block condition="start == end">
${layout.format_date(start, 'date_long')}
</tal:block>
</span>

<div class="row">
<div class="small-12 medium-8 columns">
<div class="row occupancy-block" tal:repeat="date occupancy">
<tal:block define="entries occupancy[date]">
<div class="columns small-12 medium-3">
<metal:block use-macro="layout.macros['calendar-day']" />
</div>
<div class="columns small-12 medium-9">
<ul class="occupancy-entry">
<li tal:repeat="entry entries">
<tal:block tal:define="whole_day entry.start.time() != entry.end.time()">
<span class="date" tal:condition="whole_day">
${layout.format_time_range(entry.start, entry.end)}
</span>
<span class="date" tal:condition="not:whole_day" i18n:translate>
Whole day
</span>
<span class="quota" tal:condition="resource.show_quota">
(${entry.quota})
</span>
<div class="title">
<a href="${entry.url}">${entry.title}</a>
</div>
</tal:block>
</li>
</ul>
</div>
</tal:block>
</div>
</div>
<div class="small-12 medium-4 columns">
<div class="date-range-selector-result">
<span>${count}</span>
<span i18n:translate>Reservations</span>
</div>
<metal:block tal:define="start start.isoformat(); end end.isoformat()" use-macro="layout.macros['date-range-selector']" />
</div>
</div>
</tal:block>
</div>
38 changes: 37 additions & 1 deletion onegov/town/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,42 @@ def test_reserve_in_parallel(town_app):
).follow()


def test_occupancy_view(town_app):

# prepate the required data
resources = ResourceCollection(town_app.libres_context)
resource = resources.by_name('sbb-tageskarte')
scheduler = resource.get_scheduler(town_app.libres_context)

allocations = scheduler.allocate(
dates=(datetime(2015, 8, 28), datetime(2015, 8, 28)),
whole_day=True
)

client = Client(town_app)
reserve = bound_reserve(client, allocations[0])
transaction.commit()

client.login_admin()

# create a reservation
assert reserve().json == {'success': True}
formular = client.get('/ressource/sbb-tageskarte/formular')
formular.form['email'] = 'info@example.org'
formular.form.submit().follow().click('Abschliessen')

ticket = client.get('/tickets/ALL/open').click('Annehmen').follow()

# at this point, the reservation won't show up in the occupancy view
occupancy = client.get('/ressource/sbb-tageskarte/belegung?date=20150828')
assert len(occupancy.pyquery('.occupancy-block')) == 0

# ..until we accept it
ticket.click('Alle Reservationen annehmen')
occupancy = client.get('/ressource/sbb-tageskarte/belegung?date=20150828')
assert len(occupancy.pyquery('.occupancy-block')) == 1


def test_reserve_session_separation(town_app):
c1 = Client(town_app)
c1.login_admin()
Expand Down Expand Up @@ -2102,7 +2138,7 @@ def events(query=''):

def total_events(query=''):
page = client.get('/veranstaltungen/?{}'.format(query))
return int(page.pyquery('.occurrences-filter-result span')[0].text)
return int(page.pyquery('.date-range-selector-result span')[0].text)

def dates(query=''):
page = client.get('/veranstaltungen/?{}'.format(query))
Expand Down
Loading

0 comments on commit ff329a7

Please sign in to comment.