--- a/svv/orders.py Fri Jan 07 01:23:24 2011 +0200
+++ b/svv/orders.py Fri Jan 07 02:06:49 2011 +0200
@@ -163,6 +163,14 @@
self.errors[field].append(form_error)
+ def build_name_for_armed_input (self, name) :
+ """
+ Return the name used for the checkbox associated with the named armed text input
+ """
+
+ return name + '_enabled'
+
+
def process_raw_field (self, name, default=None, required=None) :
"""
Process a generic incoming data field.
@@ -182,7 +190,7 @@
else :
return default
- def process_string_field (self, name, default=None, required=None, strip=True) :
+ def process_text_field (self, name, default=None, required=None, strip=True) :
"""
Process a generic incoming string field.
@@ -246,6 +254,44 @@
except ValueError, ex :
raise FormError(name, value, "Invalid date/time value: " + str(ex))
+ def process_checkbox_field (self, name, required=None) :
+ """
+ Process an incoming checkbox input's value.
+
+ Any non-empty/non-whitespace value will be accepted as True.
+ """
+
+ value = self.process_raw_field(name, required)
+
+ if not value and required :
+ raise FormError(name, value, "Must be checked")
+
+ elif value and value.strip() :
+ # checked
+ return True
+
+ else :
+ # unchecked
+ return False
+
+ def process_armed_text_field (self, name, required=None) :
+ """
+ A text field that must be enabled by a checkbox before being used.
+
+ If not enabled, returns False. Otherwise, text field value, and fails if empty but required.
+ """
+
+ checkbox_name = self.build_name_for_armed_input(name)
+
+ if self.process_checkbox_field(checkbox_name) :
+ # use input value
+ return self.process_text_field(name, required=required)
+
+ else :
+ # not selected
+ return False
+
+
def process_multifield (self, table, id, fields) :
"""
Process a set of user-given field values for an object with an unique id, and some set of additional fields.
@@ -323,18 +369,23 @@
return not self.errors
- def render_text_input (self, name, value=None, multiline=False) :
+ def render_text_input (self, name, value=None, multiline=False, rows=10, autoscale=True) :
"""
Render HTML for a generic text field input.
name - field name, as used for POST
value - default field value
multiline - use a multi-line <textarea> instead
+ rows - number of rows for <textarea> per default
+ autoscale - automatically scale the <textarea> to the number of lines of text
"""
if multiline :
+ if autoscale and value :
+ rows = value.count('\n') * 5 / 4
+
# XXX: textarea can't be self-closing for some reason?
- return tags.textarea(name=name, id=name, _selfclosing=False, _whitespace_sensitive=True)(value)
+ return tags.textarea(name=name, id=name, rows=rows, _selfclosing=False, _whitespace_sensitive=True)(value)
else :
return tags.input(type='text', name=name, id=name, value=value)
@@ -368,6 +419,42 @@
tags.script("$(document).ready(function () { $('#" + name + "').datetimepicker(); });"),
)
+ def render_checkbox_input (self, name, checked=None) :
+ """
+ Render HTML for a checkbox.
+ """
+
+ return tags.input(type="checkbox", name=name, id=name, value="1",
+ checked=("checked" if checked else None)
+ )
+
+ def render_armed_text_input (self, name, value=False, default=None) :
+ """
+ Render HTML for a text field that must be enabled by a checkbox before being used.
+
+ value - the three-state value
+ False - not checked, use default as value
+ None - checked, use empty value
+ str - checked, ues value
+ """
+
+ checkbox_name = self.build_name_for_armed_input(name)
+
+ if value is False :
+ checked = False
+ value = default
+
+ else :
+ checked = True
+
+ return (
+ self.render_checkbox_input(checkbox_name, checked),
+ self.render_text_input(name, value),
+
+ tags.script("$(document).ready(function () { $('#" + name + "').formEnabledBy($('#" + checkbox_name + "')); });")
+ )
+
+
def render_form_field (self, name, title, description, inputs) :
"""
Render the label, input control, error note and description for a single field, along with their containing <li>.
@@ -439,7 +526,7 @@
try :
customer_id = self.process_integer_field('customer_id')
- customer_name = self.process_string_field('customer_name')
+ customer_name = self.process_text_field('customer_name')
if not customer_id and not customer_name :
raise FormError('customer_name', None, "Must enter a customer")
@@ -465,9 +552,9 @@
try :
contact_id = self.process_integer_field('contact_id')
- contact_name = self.process_string_field('contact_name')
- contact_phone = self.process_string_field('contact_phone')
- contact_email = self.process_string_field('contact_email')
+ contact_name = self.process_text_field('contact_name')
+ contact_phone = self.process_text_field('contact_phone')
+ contact_email = self.process_text_field('contact_email')
contact_customer = customer_id
if not contact_id and not contact_name and (contact_phone or contact_email) and customer_name :
@@ -500,8 +587,8 @@
"""
try :
- event_name = self.process_string_field('event_name')
- event_description = self.process_string_field('event_description', strip=False)
+ event_name = self.process_text_field('event_name')
+ event_description = self.process_text_field('event_description', strip=False)
event_start = self.process_datetime_field('event_start')
event_end = self.process_datetime_field('event_end')
@@ -741,6 +828,47 @@
DEFAULT_PLACE = u"Otaniemi"
+ DEFAULT_TEXT = u"""\
+# Vuokrasopimus
+### Teekkarispeksi ry AV-tekniikka
+
+## Sopimusehdot
+
+1. ## Osapuolet
+ 1. Teekkarispeksi ry (Y-tunnus 1888541-7), jäljempänä “Vuokranantaja”.
+ 2. {order.customer.name}, jäljempänä “Vuokraaja”. 1.1 ja 1.2 jäljempänä yhdessä “osapuolet”.
+
+2. ## Kaluston lainaaminen
+ 1. ### Yleistä
+ Tässä sopimuksessa sovitaan toiminnasta Vuokranantajan lainatessa tanssimattoja Vuokraajalle.
+
+ 2. ### Vuokranantajan velvollisuudet
+ Vuokranantaja sitoutuu toimittamaan sovittuna ajankohtana Vuokraajalle erikseen sovittava (liite) määrä tanssimattoja.
+
+ 3. ### Blaa Blaa
+ Etc.
+
+3. ## Tätä sopimusta ja sitä koskevia erimielisyyksiä koskevat määräykset
+ 1. ### Sopimuksen voimassaolo
+ Sopimus on osapuolia sitova sen jälkeen, kun osapuolet ovat sen allekirjoittaneet.
+
+ 2. ### Muutosten tekeminen
+ Muutokset sopimukseen on tehtävä kirjallisesti molempien osapuolten kesken.
+
+ 3. ### Blaa Blaa
+
+ Etc.
+
+## Nouto
+ Aika: _______________ Paikka: _______________
+
+## Palautus
+ Aika: _______________ Paikka: _______________
+ """
+
+ # user clicked 'Edit' button, i.e. they want to view the rest of the edit fields
+ edit = None
+
def defaults (self) :
today = datetime.date.today()
@@ -749,89 +877,10 @@
self.prefill_placetime_default = "%s, %s" % (self.DEFAULT_PLACE, today.strftime("%d.%m.%Y"))
self.prefill_ourname = False
self.prefill_ourname_default = None
-
- def build_name_for_armed_input (self, name) :
- """
- Return the name used for the checkbox associated with the named armed text input
- """
- return name + '_enabled'
-
- def render_checkbox_input (self, name, checked=None) :
- """
- Render HTML for a checkbox.
- """
-
- return tags.input(type="checkbox", name=name, id=name, value="1",
- checked=("checked" if checked else None)
- )
-
- def render_armed_text_input (self, name, value=False, default=None) :
- """
- Render HTML for a text field that must be enabled by a checkbox before being used.
-
- value - the three-state value
- False - not checked, use default as value
- None - checked, use empty value
- str - checked, ues value
- """
-
- checkbox_name = self.build_name_for_armed_input(name)
-
- if value is False :
- checked = False
- value = default
-
- else :
- checked = True
-
- return (
- self.render_checkbox_input(checkbox_name, checked),
- self.render_text_input(name, value),
+ self.edit = False
- tags.script("$(document).ready(function () { $('#" + name + "').formEnabledBy($('#" + checkbox_name + "')); });")
- )
-
- def process_checkbox_field (self, name, required=None) :
- """
- Process an incoming checkbox input's value.
-
- The value must be a literal "1" to be accepted as True, and only a missing or empty value will be
- recognized as False.
- """
-
- value = self.process_raw_field(name, required)
-
- if not value and required :
- raise FormError(name, value, "Must be checked")
-
- elif not value :
- # unchecked
- return False
-
- elif value == "1" :
- # checked
- return True
-
- else :
- raise FormError(name, value, "Unrecognized checkbox state")
-
- def process_armed_text_field (self, name, required=None) :
- """
- A text field that must be enabled by a checkbox before being used.
-
- If not enabled, returns False. Otherwise, text field value, and fails if empty but required.
- """
-
- checkbox_name = self.build_name_for_armed_input(name)
-
- if self.process_checkbox_field(checkbox_name) :
- # use input value
- return self.process_string_field(name, required=required)
-
- else :
- # not selected
- return False
+ self.contract_text = self.DEFAULT_TEXT
def render (self, action, submit=u"Tulosta Vuokrasopimus") :
@@ -849,8 +898,16 @@
self.render_armed_text_input('prefill_ourname', self.prefill_ourname, self.prefill_ourname_default)
)),
+ (
+ self.render_form_field('contract_text', u"Sopimusteksti", u"Vuokrasopimuksen vapaamuotoinen otsikko, teksti, sopimusehdot, yms. Voidaan käyttää muuttujakenttiä (i.e. {...}). XXX: listaa kentät", (
+ self.render_text_input('contract_text', self.contract_text, multiline=True, autoscale=True)
+ )),
+
+ ) if self.edit else None,
+
tags.li(
tags.input(type='submit', value=submit),
+ tags.input(type='submit', name='edit', value=u"Muokkaa lisää"),
),
),
),
@@ -859,13 +916,23 @@
def process (self, data) :
+ """
+ Bind incoming data.
+
+ Returns true if no error input, and not requesting the full editing form ("Edit more" button).
+ """
+
# bind the raw post data
self.data = data
self.prefill_placetime = self.process_armed_text_field('prefill_placetime')
self.prefill_ourname = self.process_armed_text_field('prefill_ourname')
+
+ self.edit = self.process_checkbox_field('edit')
- return not self.errors
+ self.contract_text = self.process_text_field('contract_text', default=self.DEFAULT_TEXT)
+
+ return not self.errors and not self.edit
class OrdersView (PageHandler) :
"""
@@ -1205,21 +1272,6 @@
Generate and return PDF document for rental contract.
"""
- def load_params (self, data) :
- """
- Return OrderContractForm with parameters for generation
- """
-
- form = OrderContractForm(self.app)
-
- form.defaults()
-
- if data :
- # XXX: can't fail
- form.process(data)
-
- return form
-
def process (self, id):
"""
Return OrderModel object for given ID
@@ -1231,8 +1283,40 @@
# order object
self.order = self.session.query(Order).options(db.eagerload(Order.customer), db.eagerload(Order.contact)).get(id)
- # form params
- self.params = self.load_params(self.POST)
+ # form
+ self.form = OrderContractForm(self.app)
+ self.form.defaults()
+
+ # XXX: also use GET data?
+ data = self.request.values
+
+ if self.form.process(data) :
+ # render PDF
+ pass
+
+ else :
+ # show form again
+
+ # XXX: fix the pagelayout shit, this is brutal
+ handler = PageHandler(self.app, self.request, self.urlmap)
+
+ # monkey-map
+ handler.render_content = self.render_content
+
+ log.warn("Monkeyhack %r -> %r", self, handler)
+
+ # XXX: this invokes handler.process(), but...
+ return handler.respond(id=id)
+
+ def render_content (self, id) :
+ """
+ Display PDF gen form.
+ """
+
+ return (
+ tags.h1(u"Vuokrasopimus"),
+ self.form.render(action=self.url_for(OrderContractDocument, id=id)),
+ )
def generate_document (self, id) :
"""
@@ -1240,7 +1324,7 @@
"""
order = self.order
- params = self.params
+ params = self.form
title = "Teekkarispeksi Ry - Vuokrasopimus"
author = "Teekkarispeksi Ry"
@@ -1270,47 +1354,8 @@
from reportlab.platypus import Paragraph as p
- text = u"""\
-# Vuokrasopimus
-### Teekkarispeksi ry AV-tekniikka
-
-## Sopimusehdot
-
-1. ## Osapuolet
- 1. Teekkarispeksi ry (Y-tunnus 1888541-7), jäljempänä “Vuokranantaja”.
- 2. {order.customer.name}, jäljempänä “Vuokraaja”. 1.1 ja 1.2 jäljempänä yhdessä “osapuolet”.
-
-2. ## Kaluston lainaaminen
- 1. ### Yleistä
- Tässä sopimuksessa sovitaan toiminnasta Vuokranantajan lainatessa tanssimattoja Vuokraajalle.
-
- 2. ### Vuokranantajan velvollisuudet
- Vuokranantaja sitoutuu toimittamaan sovittuna ajankohtana Vuokraajalle erikseen sovittava (liite) määrä tanssimattoja.
-
- 3. ### Blaa Blaa
- Etc.
-
-3. ## Tätä sopimusta ja sitä koskevia erimielisyyksiä koskevat määräykset
- 1. ### Sopimuksen voimassaolo
- Sopimus on osapuolia sitova sen jälkeen, kun osapuolet ovat sen allekirjoittaneet.
-
- 2. ### Muutosten tekeminen
- Muutokset sopimukseen on tehtävä kirjallisesti molempien osapuolten kesken.
-
- 3. ### Blaa Blaa
-
- Etc.
-
-## Nouto
- Aika: _______________ Paikka: _______________
-
-## Palautus
- Aika: _______________ Paikka: _______________
-
- """
-
# format
- text = text.format(
+ text = params.contract_text.format(
order = order,
)