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

Commit

Permalink
Adds a claim/disclaim action to submissions with a registration window
Browse files Browse the repository at this point in the history
  • Loading branch information
Denis Krienbühl committed Mar 26, 2018
1 parent d8b4a85 commit cedbeec
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 23 deletions.
2 changes: 1 addition & 1 deletion onegov/form/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def add(self, name, form, state, id=None, payment_method=None,
registration_window = definition.current_registration_window

if registration_window:
assert registration_window.accepts_submissions
assert registration_window.accepts_submissions(spots)

# look up the right class depending on the type
submission_class = FormSubmission.get_polymorphic_class(
Expand Down
10 changes: 5 additions & 5 deletions onegov/form/models/registration_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ def localized_end(self):
), self.timezone, 'up'
)

@property
def accepts_submissions(self):
def accepts_submissions(self, required_spots=1):
if not self.enabled:
return False

Expand All @@ -108,17 +107,18 @@ def accepts_submissions(self):
if self.limit is None:
return True

return self.available_spots > 0
return self.available_spots >= required_spots

def disassociate(self):
""" Disassociates all records linked to this window. """

for submission in self.submissions:
submission.disclaim()
submission.registration_window_id = None

@property
def available_spots(self):
return self.limit - self.claimed_spots - self.requested_spots
return max(self.limit - self.claimed_spots - self.requested_spots, 0)

@property
def claimed_spots(self):
Expand All @@ -132,7 +132,7 @@ def claimed_spots(self):
@property
def requested_spots(self):
return object_session(self).execute(text("""
SELECT SUM(GREATEST(COALESCE(spots, 0) - COALESCE(claimed, 0), 0))
SELECT GREATEST(SUM(spots - COALESCE(claimed, 0)), 0)
FROM submissions
WHERE registration_window_id = :id
AND submissions.state = 'complete'
Expand Down
47 changes: 45 additions & 2 deletions onegov/form/models/submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@
from onegov.core.orm.types import UTCDateTime
from onegov.file import AssociatedFiles, File
from onegov.form.display import render_field
from onegov.form.extensions import Extendable
from onegov.form.parser import parse_form
from onegov.form.utils import extract_text_from_html, hash_definition
from onegov.form.extensions import Extendable
from onegov.pay import Payable
from onegov.pay import process_payment
from sedate import utcnow
from sqlalchemy import Column, Enum, ForeignKey, Integer, Text
from sqlalchemy import CheckConstraint
from sqlalchemy import Column
from sqlalchemy import Enum
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import Text
from sqlalchemy_utils import observes
from uuid import uuid4
from wtforms import StringField, TextAreaField
Expand Down Expand Up @@ -86,6 +91,13 @@ class FormSubmission(Base, TimestampMixin, Payable, AssociatedFiles,
"polymorphic_on": 'state'
}

__table_args__ = (
CheckConstraint(
'COALESCE(claimed, 0) <= spots',
name='claimed_no_more_than_requested'
),
)

@property
def form_class(self):
""" Parses the form definition and returns a form class. """
Expand Down Expand Up @@ -161,6 +173,37 @@ def process_payment(self, price, provider=None, token=None):

return True

def claim(self, spots=None):
""" Claimes the given number of spots (defaults to the requested
number of spots).
"""
spots = spots or self.spots

assert self.registration_window

if self.registration_window.limit:
limit = self.registration_window.limit
claimed = self.registration_window.claimed_spots

assert spots <= (limit - claimed)

self.claimed = spots

def disclaim(self, spots=None):
""" Disclaims the given number of spots (defaults to all spots that
were claimed so far).
"""
spots = spots or self.claimed

assert self.registration_window

if self.claimed is None:
self.claimed = 0
else:
self.claimed = max(0, self.claimed - spots)


class PendingFormSubmission(FormSubmission):
__mapper_args__ = {'polymorphic_identity': 'pending'}
Expand Down
147 changes: 132 additions & 15 deletions onegov/form/tests/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,28 +182,28 @@ def test_registration_window_spots(session):
session.flush()

window.enabled = False
assert not window.accepts_submissions
assert not window.accepts_submissions()

window.enabled = True
window.end = today - days(1)
assert not window.accepts_submissions
assert not window.accepts_submissions()

window.start = today + days(1)
window.end = today + days(5)
assert not window.accepts_submissions
assert not window.accepts_submissions()

window.start = today - days(5)
window.overflow = True
assert window.accepts_submissions
assert window.accepts_submissions()

window.overflow = False
window.limit = None
assert window.accepts_submissions
assert window.accepts_submissions()
assert window.claimed_spots == 0
assert window.requested_spots == 0

window.limit = 2
assert window.accepts_submissions
assert window.accepts_submissions()
assert window.claimed_spots == 0
assert window.requested_spots == 0

Expand All @@ -214,7 +214,7 @@ def test_registration_window_spots(session):
spots=1
)

assert window.accepts_submissions
assert window.accepts_submissions()
assert window.claimed_spots == 0
assert window.requested_spots == 1

Expand All @@ -225,29 +225,146 @@ def test_registration_window_spots(session):
spots=1
)

assert not window.accepts_submissions
assert not window.accepts_submissions()
assert window.claimed_spots == 0
assert window.requested_spots == 2

window.overflow = True
assert window.accepts_submissions
assert window.accepts_submissions()

s1.claimed = 1
s1.claim(1)
session.flush()

assert window.accepts_submissions
assert window.accepts_submissions()
assert window.claimed_spots == 1
assert window.requested_spots == 1

window.overflow = False
assert not window.accepts_submissions
assert not window.accepts_submissions()

s2.claimed = 1
s2.claim(1)
session.flush()

assert not window.accepts_submissions
assert not window.accepts_submissions()
assert window.claimed_spots == 2
assert window.requested_spots == 0

window.overflow = True
assert window.accepts_submissions
assert window.accepts_submissions()


def test_registration_claims_with_no_limit(session):
forms = FormCollection(session)
today = date.today()

summer = forms.definitions.add('Summercamp', definition="E-Mail = @@@")

window = summer.add_registration_window(today - days(5), today + days(5))
window.limit = None

session.flush()

submission = forms.submissions.add(
name='summercamp',
form=summer.form_class(data={'e_mail': 'info@example.org'}),
state='complete',
spots=100
)

submission.claim()
session.flush()

assert submission.claimed == 100
assert submission.spots == 100
assert window.claimed_spots == 100
assert window.requested_spots == 0

submission.disclaim()
session.flush()

assert submission.claimed == 0
assert submission.spots == 100
assert window.claimed_spots == 0
assert window.requested_spots == 100

submission.claim(50)
session.flush()

assert submission.claimed == 50
assert submission.spots == 100
assert window.claimed_spots == 50
assert window.requested_spots == 50


def test_registration_claims_with_a_limit(session):
forms = FormCollection(session)
today = date.today()

summer = forms.definitions.add('Summercamp', definition="E-Mail = @@@")

window = summer.add_registration_window(today - days(5), today + days(5))
window.limit = 10
window.overflow = True

session.flush()

submission = forms.submissions.add(
name='summercamp',
form=summer.form_class(data={'e_mail': 'info@example.org'}),
state='complete',
spots=100
)

with pytest.raises(AssertionError):
submission.claim()

with pytest.raises(AssertionError):
submission.claim(11)

submission.claim(spots=10)
session.flush()

assert window.claimed_spots == 10
assert window.requested_spots == 90
assert window.available_spots == 0

submission.disclaim()
session.flush()

assert window.claimed_spots == 0
assert window.requested_spots == 100
assert window.available_spots == 0


def test_register_more_than_allowed(session):
forms = FormCollection(session)
today = date.today()

summer = forms.definitions.add('Summercamp', definition="E-Mail = @@@")

window = summer.add_registration_window(today - days(5), today + days(5))
window.limit = 1
window.overflow = False

session.flush()

with pytest.raises(AssertionError):
forms.submissions.add(
name='summercamp',
form=summer.form_class(data={'e_mail': 'info@example.org'}),
state='complete',
spots=2
)

window.overflow = True
session.flush()

forms.submissions.add(
name='summercamp',
form=summer.form_class(data={'e_mail': 'info@example.org'}),
state='complete',
spots=2
)

window.overflow = False
session.flush()

0 comments on commit cedbeec

Please sign in to comment.