fixes #141: maximum number of available tickets

This commit is contained in:
Davide Alberani 2016-07-31 23:25:05 +02:00
parent e7ed1a7afc
commit 49c924e76f
3 changed files with 53 additions and 24 deletions

View file

@ -25,15 +25,15 @@
</button> </button>
</div> </div>
<div class="input-group input-group-lg"> <div class="input-group input-group">
<span class="input-group-addon min100">{{'Title' | translate}}</span> <span class="input-group-addon min100">{{'Title' | translate}}</span>
<input type="text" class="form-control" placeholder="{{'Title' | translate}}" ng-model="event.title" ng-required="true"> <input type="text" class="form-control" placeholder="{{'Title' | translate}}" ng-model="event.title" ng-required="true">
</div> </div>
<div class="input-group input-group-lg top5"> <div class="input-group input-group top5">
<span class="input-group-addon min100">{{'Tagline' | translate}}</span> <span class="input-group-addon min100">{{'Tagline' | translate}}</span>
<input type="text" class="form-control" placeholder="{{'Tagline' | translate}}" ng-model="event.tagline"> <input type="text" class="form-control" placeholder="{{'Tagline' | translate}}" ng-model="event.tagline">
</div> </div>
<div class="input-group input-group-lg top5"> <div class="input-group input-group top5">
<span class="input-group-addon min100">{{'Short summary' | translate}}</span> <span class="input-group-addon min100">{{'Short summary' | translate}}</span>
<input type="text" class="form-control" placeholder="{{'Short summary' | translate}}" ng-model="event.summary"> <input type="text" class="form-control" placeholder="{{'Short summary' | translate}}" ng-model="event.summary">
</div> </div>
@ -74,18 +74,27 @@
</div> </div>
</div> </div>
<div class="input-group input-group-lg top5"> <div class="input-group input-group top5">
<span class="input-group-addon min100">{{'Where' | translate}}</span> <span class="input-group-addon min100">{{'Where' | translate}}</span>
<input type="text" class="form-control" placeholder="{{'Where' | translate}}" ng-model="event.where"> <input type="text" class="form-control" placeholder="{{'Where' | translate}}" ng-model="event.where">
</div> </div>
<div class="input-group input-group-lg top5"> <div class="input-group input-group top5">
<span class="input-group-addon min100">{{'Group ID' | translate}}</span> <span class="input-group-addon min100">{{'Group ID' | translate}}</span>
<input type="text" class="form-control" placeholder="{{'Used to share persons amongst multiple events. Must be hard to guess (if empty, will be autogenerated)' | translate}}" ng-model="event.group_id"> <input type="text" class="form-control" placeholder="{{'Used to share persons amongst multiple events. Must be hard to guess (if empty, will be autogenerated)' | translate}}" ng-model="event.group_id">
</div> </div>
</fieldset>
<div class="panel panel-default table-striped top5">
<div class="panel-heading">
<h1>{{'Ticket limits'}}</h1>
</div>
<div class="panel-body">
<div class="input-group input-group top5">
<span class="input-group-addon min100">{{'Number of tickets' | translate}}</span>
<input type="number" min="0" class="form-control" placeholder="{{'Number of tickets (0 or empty means unlimited)' | translate}}" ng-model="event.number_of_tickets">
</div>
</div>
</div>
<label></label>
<input type="submit" class="outside-screen" /> <input type="submit" class="outside-screen" />
<div ng-if="!eventFormDisabled" ng-class="{clearfix: true, alert: true, 'alert-success': !eventForm.$dirty, 'alert-danger': eventForm.$dirty}"> <div ng-if="!eventFormDisabled" ng-class="{clearfix: true, alert: true, 'alert-success': !eventForm.$dirty, 'alert-danger': eventForm.$dirty}">
<button type="button" class="btn btn-default pull-right" ng-click="save($event)" ng-disabled="!eventForm.$dirty"> <button type="button" class="btn btn-default pull-right" ng-click="save($event)" ng-disabled="!eventForm.$dirty">
@ -93,6 +102,7 @@
{{'save' | translate}} {{'save' | translate}}
</button> </button>
</div> </div>
</fieldset>
</form> </form>
</div> </div>
</div> </div>

View file

@ -32,7 +32,8 @@
<tr> <tr>
<th><strong>{{'Event' | translate}}</strong></th> <th><strong>{{'Event' | translate}}</strong></th>
<th ng-if="hasPermission('event|update')" class="hcenter"><strong>{{'Attendees / Registered' | translate}}</strong></th> <th ng-if="hasPermission('event|update')" class="hcenter"><strong>{{'Attendees / Registered' | translate}}</strong></th>
<th class="hcenter"><strong>{{'Actions' | translate}}</strong></th> <th class="hcenter"><strong>{{'Tickets' | translate}}</strong></th>
<th ng-if="hasPermission('event|update') || hasPermission('event|delete')" class="hcenter"><strong>{{'Actions' | translate}}</strong></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -53,11 +54,14 @@
</div> </div>
</td> </td>
<td ng-if="hasPermission('event:tickets-all|read')" class="hcenter"> <td ng-if="hasPermission('event:tickets-all|read')" class="hcenter">
<p><span ng-init="attendeesNr = ((event.tickets || []) | attendeesFilter).length">{{attendeesNr}}</span> / {{((event.tickets || []) | registeredFilter).length}} ({{((attendeesNr / ((event.tickets || []) | registeredFilter).length * 100) || 0).toFixed()}}%)</p> <p><span ng-init="attendeesNr = ((event.tickets || []) | attendeesFilter).length">{{attendeesNr}}</span> / {{event.tickets_sold || 0}} ({{((attendeesNr / (event.tickets_sold || 0) * 100) || 0).toFixed()}}%)</p>
</td> </td>
<td> <td>
<div ng-if="hasPermission('event:tickets-all|create')" class="top5 hcenter"><button ng-click="$state.go('event.ticket.new', {id: event._id})" class="min150 btn btn-success" type="button" title="{{'Join this event' | translate}}"><span class="fa fa-user-plus vcenter"></span> {{'Join this event' | translate}}</button></div> <div ng-if="hasPermission('event:tickets-all|create')" class="top5 hcenter"><button ng-click="$state.go('event.ticket.new', {id: event._id})" class="min150 btn btn-success" type="button" title="{{'Join this event' | translate}}"><span class="fa fa-user-plus vcenter"></span> {{'Join this event' | translate}}</button></div>
<div ng-if="hasPermission('ticket|update')" class="top5 hcenter"><button ng-click="$state.go('event.tickets', {id: event._id})" class="min150 btn btn-primary" type="button" title="{{'Manage tickets' | translate}}"><span class="fa fa-ticket"></span> {{'Manage tickets' | translate}}</button></div> <div ng-if="hasPermission('ticket|update')" class="top5 hcenter"><button ng-click="$state.go('event.tickets', {id: event._id})" class="min150 btn btn-primary" type="button" title="{{'Manage tickets' | translate}}"><span class="fa fa-ticket"></span> {{'Manage tickets' | translate}}</button></div>
<div class="top5 hcenter" ng-if="event.number_of_tickets">{{event.number_of_tickets}} {{'tickets' | translate}}, {{event.number_of_tickets - (event.tickets_sold || 0)}} {{'still available' | translate}}</div>
</td>
<td ng-if="hasPermission('event|update') || hasPermission('event|delete')">
<div ng-if="hasPermission('event|update')" class="top5 hcenter"><button ng-click="$state.go('event.edit', {id: event._id})" type="button" class="min150 btn btn-warning" title="{{'Edit event' | translate}}"><span class="fa fa-cog"></span> {{'Edit event' | translate}}</button></div> <div ng-if="hasPermission('event|update')" class="top5 hcenter"><button ng-click="$state.go('event.edit', {id: event._id})" type="button" class="min150 btn btn-warning" title="{{'Edit event' | translate}}"><span class="fa fa-cog"></span> {{'Edit event' | translate}}</button></div>
<div ng-if="hasPermission('event|delete')" class="top5 hcenter bottom5"><button ng-click="deleteEvent(event._id)" type="button" class="min150 btn btn-danger" title="{{'Delete event' | translate}}"><span class="fa fa-trash"></span> {{'Delete event' | translate}}</button></div> <div ng-if="hasPermission('event|delete')" class="top5 hcenter bottom5"><button ng-click="deleteEvent(event._id)" type="button" class="min150 btn btn-danger" title="{{'Delete event' | translate}}"><span class="fa fa-trash"></span> {{'Delete event' | translate}}</button></div>
</td> </td>

View file

@ -590,15 +590,17 @@ class EventsHandler(CollectionHandler):
collection = 'events' collection = 'events'
def filter_get(self, output): def filter_get(self, output):
if not self.has_permission('tickets-all|read'):
if 'tickets' in output: if 'tickets' in output:
output['tickets_sold'] = len([t for t in output['tickets'] if not t.get('cancelled')])
if not self.has_permission('tickets-all|read'):
output['tickets'] = [] output['tickets'] = []
return output return output
def filter_get_all(self, output): def filter_get_all(self, output):
if not self.has_permission('tickets-all|read'):
for event in output.get('events') or []: for event in output.get('events') or []:
if 'tickets' in event: if 'tickets' in event:
event['tickets_sold'] = len([t for t in event['tickets'] if not t.get('cancelled')])
if not self.has_permission('tickets-all|read'):
event['tickets'] = [] event['tickets'] = []
return output return output
@ -660,6 +662,12 @@ class EventsHandler(CollectionHandler):
return {'tickets': tickets} return {'tickets': tickets}
def handle_post_tickets(self, id_, resource_id, data): def handle_post_tickets(self, id_, resource_id, data):
event = self.db.query('events', {'_id': id_})[0]
if 'number_of_tickets' in event:
tickets = event.get('tickets') or []
tickets = [t for t in tickets if not t.get('cancelled')]
if len(tickets) >= event['number_of_tickets']:
raise InputException('no more tickets available')
uuid, arguments = self.uuid_arguments uuid, arguments = self.uuid_arguments
self._clean_dict(data) self._clean_dict(data)
data['seq'] = self.get_next_seq('event_%s_tickets' % id_) data['seq'] = self.get_next_seq('event_%s_tickets' % id_)
@ -702,8 +710,15 @@ class EventsHandler(CollectionHandler):
current_event = current_event[0] current_event = current_event[0]
else: else:
current_event = {} current_event = {}
old_ticket_data = self._get_ticket_data(ticket_query, tickets = current_event.get('tickets') or []
current_event.get('tickets') or []) old_ticket_data = self._get_ticket_data(ticket_query, tickets)
# We updating the "cancelled" status of a ticket; check if we still have a ticket available
if 'number_of_tickets' in current_event and old_ticket_data.get('cancelled') and not data.get('cancelled'):
active_tickets = [t for t in tickets if not t.get('cancelled')]
if len(active_tickets) >= current_event['number_of_tickets']:
raise InputException('no more tickets available')
merged, doc = self.db.update('events', query, merged, doc = self.db.update('events', query,
data, updateList='tickets', create=False) data, updateList='tickets', create=False)
new_ticket_data = self._get_ticket_data(ticket_query, new_ticket_data = self._get_ticket_data(ticket_query,