Remove legacy 'forms' package and templates
yay!
This commit is contained in:
parent
66769ab34b
commit
d0b78babd2
|
@ -1,39 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Forms
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from formencode import Schema
|
||||
|
||||
from .core import Form, Field, FieldSet, GenericFieldSet
|
||||
from .simpleform import SimpleForm, FormRenderer
|
||||
from .alchemy import AlchemyForm
|
||||
from .fields import AssociationProxyField
|
||||
from .renderers import *
|
||||
|
||||
from . import fields
|
||||
from . import renderers
|
||||
from . import validators
|
|
@ -1,117 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
FormAlchemy Forms
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from rattail.core import Object
|
||||
|
||||
import formalchemy as fa
|
||||
from pyramid.renderers import render
|
||||
from webhelpers2.html import HTML, tags
|
||||
|
||||
from tailbone.db import Session
|
||||
|
||||
|
||||
class TemplateEngine(fa.templates.TemplateEngine):
|
||||
"""
|
||||
Mako template engine for FormAlchemy.
|
||||
"""
|
||||
|
||||
def render(self, template, prefix='/forms/', suffix='.mako', **kwargs):
|
||||
template = ''.join((prefix, template, suffix))
|
||||
return render(template, kwargs)
|
||||
|
||||
|
||||
class AlchemyForm(Object):
|
||||
"""
|
||||
Form to contain a :class:`formalchemy.FieldSet` instance.
|
||||
"""
|
||||
id = None
|
||||
create_label = "Create"
|
||||
update_label = "Save"
|
||||
|
||||
allow_successive_creates = False
|
||||
|
||||
def __init__(self, request, fieldset, session=None, csrf_field='_csrf', **kwargs):
|
||||
super(AlchemyForm, self).__init__(**kwargs)
|
||||
self.request = request
|
||||
self.fieldset = fieldset
|
||||
self.session = session
|
||||
self.csrf_field = csrf_field
|
||||
|
||||
def _get_readonly(self):
|
||||
return self.fieldset.readonly
|
||||
def _set_readonly(self, val):
|
||||
self.fieldset.readonly = val
|
||||
readonly = property(_get_readonly, _set_readonly)
|
||||
|
||||
@property
|
||||
def successive_create_label(self):
|
||||
return "%s and continue" % self.create_label
|
||||
|
||||
def csrf(self, name=None):
|
||||
"""
|
||||
NOTE: this method was copied from `pyramid_simpleform.FormRenderer`
|
||||
|
||||
Returns the CSRF hidden input. Creates new CSRF token
|
||||
if none has been assigned yet.
|
||||
|
||||
The name of the hidden field is **_csrf** by default.
|
||||
"""
|
||||
name = name or self.csrf_field
|
||||
|
||||
token = self.request.session.get_csrf_token()
|
||||
if token is None:
|
||||
token = self.request.session.new_csrf_token()
|
||||
|
||||
return tags.hidden(name, value=token)
|
||||
|
||||
def csrf_token(self, name=None):
|
||||
"""
|
||||
NOTE: this method was copied from `pyramid_simpleform.FormRenderer`
|
||||
|
||||
Convenience function. Returns CSRF hidden tag inside hidden DIV.
|
||||
"""
|
||||
return HTML.tag("div", self.csrf(name), style="display:none;")
|
||||
|
||||
def render(self, **kwargs):
|
||||
kwargs['form'] = self
|
||||
if self.readonly:
|
||||
template = '/forms/form_readonly.mako'
|
||||
else:
|
||||
template = '/forms/form.mako'
|
||||
return render(template, kwargs)
|
||||
|
||||
def render_fields(self):
|
||||
return self.fieldset.render()
|
||||
|
||||
def save(self):
|
||||
self.fieldset.sync()
|
||||
self.session.flush()
|
||||
|
||||
def validate(self):
|
||||
self.fieldset.rebind(data=self.request.params)
|
||||
return self.fieldset.validate()
|
|
@ -1,119 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Forms Core
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from rattail.util import OrderedDict, prettify
|
||||
|
||||
import formalchemy
|
||||
from formalchemy.helpers import content_tag
|
||||
from pyramid.renderers import render
|
||||
|
||||
|
||||
class Form(object):
|
||||
"""
|
||||
Base class for all forms.
|
||||
"""
|
||||
create_label = "Create"
|
||||
update_label = "Save"
|
||||
|
||||
def __init__(self, request, readonly=False, action_url=None):
|
||||
self.request = request
|
||||
self.readonly = readonly
|
||||
self.action_url = action_url
|
||||
|
||||
def render(self, **kwargs):
|
||||
kwargs.setdefault('form', self)
|
||||
if self.readonly:
|
||||
template = '/forms/form_readonly.mako'
|
||||
else:
|
||||
template = '/forms/form.mako'
|
||||
return render(template, kwargs)
|
||||
|
||||
def render_fields(self, **kwargs):
|
||||
kwargs.setdefault('fieldset', self.fieldset)
|
||||
if self.readonly:
|
||||
template = '/forms/fieldset_readonly.mako'
|
||||
else:
|
||||
template = '/forms/fieldset.mako'
|
||||
return render(template, kwargs)
|
||||
|
||||
|
||||
class Field(object):
|
||||
"""
|
||||
Manually create instances of this class to populate a simple form.
|
||||
"""
|
||||
|
||||
def __init__(self, name, value=None, label=None, requires_label=True):
|
||||
self.name = name
|
||||
self.value = value
|
||||
self._label = label or prettify(self.name)
|
||||
self.requires_label = requires_label
|
||||
|
||||
def is_required(self):
|
||||
return True
|
||||
|
||||
def label(self):
|
||||
return self._label
|
||||
|
||||
def label_tag(self, **html_options):
|
||||
"""
|
||||
Logic stolen from FormAlchemy so all fields can render their own label.
|
||||
Original docstring follows.
|
||||
|
||||
return the <label /> tag for the field.
|
||||
"""
|
||||
html_options.update(for_=self.name)
|
||||
if 'class_' in html_options:
|
||||
html_options['class_'] += self.is_required() and ' field_req' or ' field_opt'
|
||||
else:
|
||||
html_options['class_'] = self.is_required() and 'field_req' or 'field_opt'
|
||||
return content_tag('label', self.label(), **html_options)
|
||||
|
||||
def render_readonly(self):
|
||||
if self.value is None:
|
||||
return ''
|
||||
return unicode(self.value)
|
||||
|
||||
|
||||
class FieldSet(object):
|
||||
"""
|
||||
Generic fieldset for use with manually-created simple forms.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.fields = OrderedDict()
|
||||
self.render_fields = self.fields
|
||||
|
||||
|
||||
class GenericFieldSet(formalchemy.FieldSet):
|
||||
"""
|
||||
FieldSet class based on FormAlchemy, but without the SQLAlchemy magic.
|
||||
"""
|
||||
__sa__ = False
|
||||
_bound_pk = None
|
||||
data = None
|
||||
prettify = staticmethod(prettify)
|
|
@ -1,106 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
FormAlchemy Fields
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import formalchemy as fa
|
||||
|
||||
|
||||
def AssociationProxyField(name, **kwargs):
|
||||
"""
|
||||
Returns a FormAlchemy ``Field`` class which is aware of association
|
||||
proxies.
|
||||
"""
|
||||
|
||||
class ProxyField(fa.Field):
|
||||
|
||||
def sync(self):
|
||||
if not self.is_readonly():
|
||||
setattr(self.parent.model, self.name,
|
||||
self.renderer.deserialize())
|
||||
|
||||
def value(obj):
|
||||
return getattr(obj, name, None)
|
||||
|
||||
kwargs.setdefault('value', value)
|
||||
return ProxyField(name, **kwargs)
|
||||
|
||||
|
||||
class DefaultEmailField(fa.Field):
|
||||
"""
|
||||
Generic field for view/edit of default email address for a contact
|
||||
"""
|
||||
|
||||
def __init__(self, name=None, **kwargs):
|
||||
kwargs.setdefault('value', self.value)
|
||||
if 'renderer' not in kwargs:
|
||||
from tailbone.forms.renderers import EmailFieldRenderer
|
||||
kwargs['renderer'] = EmailFieldRenderer
|
||||
super(DefaultEmailField, self).__init__(name, **kwargs)
|
||||
|
||||
def value(self, contact):
|
||||
if contact.emails:
|
||||
return contact.emails[0].address
|
||||
|
||||
def sync(self):
|
||||
if not self.is_readonly():
|
||||
address = self._deserialize()
|
||||
contact = self.parent.model
|
||||
if contact.emails:
|
||||
if address:
|
||||
email = contact.emails[0]
|
||||
email.address = address
|
||||
else:
|
||||
contact.emails.pop(0)
|
||||
elif address:
|
||||
email = contact.add_email_address(address)
|
||||
|
||||
|
||||
class DefaultPhoneField(fa.Field):
|
||||
"""
|
||||
Generic field for view/edit of default phone number for a contact
|
||||
"""
|
||||
|
||||
def __init__(self, name=None, **kwargs):
|
||||
kwargs.setdefault('value', self.value)
|
||||
super(DefaultPhoneField, self).__init__(name, **kwargs)
|
||||
|
||||
def value(self, contact):
|
||||
if contact.phones:
|
||||
return contact.phones[0].number
|
||||
|
||||
def sync(self):
|
||||
if not self.is_readonly():
|
||||
number = self._deserialize()
|
||||
contact = self.parent.model
|
||||
if contact.phones:
|
||||
if number:
|
||||
phone = contact.phones[0]
|
||||
phone.number = number
|
||||
else:
|
||||
contact.phones.pop(0)
|
||||
elif number:
|
||||
phone = contact.add_phone_number(number)
|
|
@ -1,51 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
FormAlchemy Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from .core import CustomFieldRenderer, DateFieldRenderer
|
||||
|
||||
from .common import (StrippedTextFieldRenderer, CodeTextAreaFieldRenderer, AutocompleteFieldRenderer,
|
||||
DecimalFieldRenderer, CurrencyFieldRenderer, QuantityFieldRenderer,
|
||||
DateTimeFieldRenderer, DateTimePrettyFieldRenderer, LocalDateTimeFieldRenderer, TimeFieldRenderer,
|
||||
EmailFieldRenderer, EnumFieldRenderer, YesNoFieldRenderer)
|
||||
|
||||
from .files import FileFieldRenderer
|
||||
|
||||
from .people import PersonFieldRenderer, PeopleFieldRenderer, CustomerFieldRenderer
|
||||
from .users import UserFieldRenderer, PermissionsFieldRenderer
|
||||
from .employees import EmployeeFieldRenderer
|
||||
|
||||
from .stores import StoreFieldRenderer
|
||||
from .vendors import VendorFieldRenderer, PurchaseFieldRenderer
|
||||
from .products import (GPCFieldRenderer, ScancodeFieldRenderer,
|
||||
DepartmentFieldRenderer, SubdepartmentFieldRenderer, CategoryFieldRenderer,
|
||||
BrandFieldRenderer, ProductFieldRenderer,
|
||||
CostFieldRenderer, PriceFieldRenderer, PriceWithExpirationFieldRenderer)
|
||||
|
||||
from .custorders import CustomerOrderFieldRenderer
|
||||
|
||||
from .batch import BatchIDFieldRenderer, HandheldBatchFieldRenderer, HandheldBatchesFieldRenderer
|
|
@ -1,103 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Batch Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import os
|
||||
import stat
|
||||
import random
|
||||
|
||||
import formalchemy as fa
|
||||
from webhelpers2.html import tags, HTML
|
||||
|
||||
from tailbone.forms.renderers import FileFieldRenderer as BaseFileFieldRenderer
|
||||
|
||||
|
||||
class BatchIDFieldRenderer(fa.FieldRenderer):
|
||||
"""
|
||||
Renderer for batch ID fields.
|
||||
"""
|
||||
def render_readonly(self, **kwargs):
|
||||
try:
|
||||
batch_id = self.raw_value
|
||||
except AttributeError:
|
||||
# this can happen when creating a new batch, b/c the default value
|
||||
# comes from a sequence
|
||||
pass
|
||||
else:
|
||||
if batch_id:
|
||||
return '{:08d}'.format(batch_id)
|
||||
return ''
|
||||
|
||||
|
||||
class FileFieldRenderer(BaseFileFieldRenderer):
|
||||
"""
|
||||
Custom file field renderer for batches based on a single source data file.
|
||||
In edit mode, shows a file upload field. In readonly mode, shows the
|
||||
filename and its size.
|
||||
"""
|
||||
|
||||
def get_size(self):
|
||||
size = super(FileFieldRenderer, self).get_size()
|
||||
if size:
|
||||
return size
|
||||
batch = self.field.parent.model
|
||||
path = batch.filepath(self.request.rattail_config, filename=self.field.value)
|
||||
if os.path.isfile(path):
|
||||
return os.stat(path)[stat.ST_SIZE]
|
||||
return 0
|
||||
|
||||
def render(self, **kwargs):
|
||||
return BaseFileFieldRenderer.render(self, **kwargs)
|
||||
|
||||
|
||||
class HandheldBatchFieldRenderer(fa.FieldRenderer):
|
||||
"""
|
||||
Renderer for inventory batch's "handheld batch" field.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
batch = self.raw_value
|
||||
if batch:
|
||||
return tags.link_to(
|
||||
batch.id_str,
|
||||
self.request.route_url('batch.handheld.view', uuid=batch.uuid))
|
||||
return ''
|
||||
|
||||
|
||||
class HandheldBatchesFieldRenderer(fa.FieldRenderer):
|
||||
"""
|
||||
Renders a list of associated handheld batches, for a given (presumably
|
||||
inventory or labels) batch.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
items = ''
|
||||
for handheld in self.raw_value:
|
||||
text = tags.link_to(handheld.handheld.id_str,
|
||||
self.request.route_url('batch.handheld.view', uuid=handheld.handheld_uuid))
|
||||
items += HTML.tag('li', c=text)
|
||||
return HTML.tag('ul', c=items)
|
|
@ -1,63 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Batch Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import stat
|
||||
import random
|
||||
|
||||
from formalchemy.ext import fsblob
|
||||
|
||||
|
||||
class BounceMessageFieldRenderer(fsblob.FileFieldRenderer):
|
||||
"""
|
||||
Custom file field renderer for email bounce messages. In readonly mode,
|
||||
shows the filename and size.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def new(cls, request, handler):
|
||||
name = 'Configured%s_%s' % (cls.__name__, unicode(random.random())[2:])
|
||||
return type(str(name), (cls,), dict(request=request, handler=handler))
|
||||
|
||||
@property
|
||||
def storage_path(self):
|
||||
return self.handler.root_msgdir
|
||||
|
||||
def get_size(self):
|
||||
size = super(BounceMessageFieldRenderer, self).get_size()
|
||||
if size:
|
||||
return size
|
||||
bounce = self.field.parent.model
|
||||
path = os.path.join(self.handler.msgpath(bounce))
|
||||
if os.path.isfile(path):
|
||||
return os.stat(path)[stat.ST_SIZE]
|
||||
return 0
|
||||
|
||||
def get_url(self, filename):
|
||||
bounce = self.field.parent.model
|
||||
return self.request.route_url('emailbounces.download', uuid=bounce.uuid)
|
|
@ -1,315 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Common Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import datetime
|
||||
|
||||
from rattail.time import localtime, make_utc
|
||||
from rattail.util import pretty_quantity
|
||||
|
||||
import formalchemy as fa
|
||||
from formalchemy import fields as fa_fields, helpers as fa_helpers
|
||||
from pyramid.renderers import render
|
||||
from webhelpers2.html import HTML, tags
|
||||
|
||||
from tailbone.util import pretty_datetime, raw_datetime
|
||||
|
||||
|
||||
class StrippedTextFieldRenderer(fa.TextFieldRenderer):
|
||||
"""
|
||||
Standard text field renderer, which strips whitespace from either end of
|
||||
the input value on deserialization.
|
||||
"""
|
||||
|
||||
def deserialize(self):
|
||||
value = super(StrippedTextFieldRenderer, self).deserialize()
|
||||
if value is not None:
|
||||
return value.strip()
|
||||
|
||||
|
||||
class CodeTextAreaFieldRenderer(fa.TextAreaFieldRenderer):
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
value = self.raw_value
|
||||
if not value:
|
||||
return ''
|
||||
return HTML.tag('pre', c=value)
|
||||
|
||||
def render(self, **kwargs):
|
||||
kwargs.setdefault('size', (80, 8))
|
||||
return super(CodeTextAreaFieldRenderer, self).render(**kwargs)
|
||||
|
||||
|
||||
class AutocompleteFieldRenderer(fa.FieldRenderer):
|
||||
"""
|
||||
Custom renderer for an autocomplete field.
|
||||
"""
|
||||
|
||||
service_route = None
|
||||
width = '300px'
|
||||
|
||||
@property
|
||||
def focus_name(self):
|
||||
return self.name + '-textbox'
|
||||
|
||||
@property
|
||||
def needs_focus(self):
|
||||
return not bool(self.value or self.field_value)
|
||||
|
||||
@property
|
||||
def field_display(self):
|
||||
return self.raw_value
|
||||
|
||||
@property
|
||||
def field_value(self):
|
||||
return self.value
|
||||
|
||||
@property
|
||||
def service_url(self):
|
||||
return self.request.route_url(self.service_route)
|
||||
|
||||
def render(self, options=None, **kwargs):
|
||||
if kwargs.pop('autocomplete', True):
|
||||
return self.render_autocomplete(**kwargs)
|
||||
# 'selected' is a kwarg for autocomplete template *and* select tag
|
||||
kwargs.pop('selected', None)
|
||||
return self.render_dropdown(options, **kwargs)
|
||||
|
||||
def render_autocomplete(self, **kwargs):
|
||||
kwargs.setdefault('field_name', self.name)
|
||||
kwargs.setdefault('field_value', self.field_value)
|
||||
kwargs.setdefault('field_display', self.field_display)
|
||||
kwargs.setdefault('service_url', self.service_url)
|
||||
kwargs.setdefault('width', self.width)
|
||||
return render('/forms/field_autocomplete.mako', kwargs)
|
||||
|
||||
def render_dropdown(self, options, **kwargs):
|
||||
# NOTE: this logic copied from formalchemy.fields.SelectFieldRenderer.render()
|
||||
kwargs.setdefault('auto-enhance', 'true')
|
||||
if callable(options):
|
||||
L = fa_fields._normalized_options(options(self.field.parent))
|
||||
if not self.field.is_required() and not self.field.is_collection:
|
||||
L.insert(0, self.field._null_option)
|
||||
else:
|
||||
L = list(options)
|
||||
if len(L) > 0:
|
||||
if len(L[0]) == 2:
|
||||
L = [(k, self.stringify_value(v)) for k, v in L]
|
||||
else:
|
||||
L = [fa_fields._stringify(k) for k in L]
|
||||
return fa_fields.h.select(self.name, self.value, L, **kwargs)
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
value = self.field_display
|
||||
if value is None:
|
||||
return u''
|
||||
return unicode(value)
|
||||
|
||||
|
||||
class DateTimeFieldRenderer(fa.DateTimeFieldRenderer):
|
||||
"""
|
||||
This renderer assumes the datetime field value is in UTC, and will convert
|
||||
it to the local time zone before rendering it in the standard "raw" format.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
value = self.raw_value
|
||||
if not value:
|
||||
return ''
|
||||
return raw_datetime(self.request.rattail_config, value)
|
||||
|
||||
|
||||
class DateTimePrettyFieldRenderer(fa.DateTimeFieldRenderer):
|
||||
"""
|
||||
Custom date/time field renderer, which displays a "pretty" value in
|
||||
read-only mode, leveraging config to show the correct timezone.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
value = self.raw_value
|
||||
if not value:
|
||||
return ''
|
||||
return pretty_datetime(self.request.rattail_config, value)
|
||||
|
||||
|
||||
class LocalDateTimeFieldRenderer(fa.DateTimeFieldRenderer):
|
||||
"""
|
||||
This renderer assumes the datetime field value is "naive" in local time zone.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
value = self.raw_value
|
||||
if not value:
|
||||
return ''
|
||||
value = localtime(self.request.rattail_config, value)
|
||||
return raw_datetime(self.request.rattail_config, value)
|
||||
|
||||
|
||||
class TimeFieldRenderer(fa.TimeFieldRenderer):
|
||||
"""
|
||||
Custom renderer for time fields. In edit mode, renders a simple text
|
||||
input, which is expected to become a 'timepicker' widget in the UI.
|
||||
However the particular magic required for that lives in 'tailbone.js'.
|
||||
"""
|
||||
format = '%I:%M %p'
|
||||
|
||||
def render(self, **kwargs):
|
||||
kwargs.setdefault('class_', 'timepicker')
|
||||
return fa_helpers.text_field(self.name, value=self.value, **kwargs)
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
return self.render_value(self.raw_value)
|
||||
|
||||
def render_value(self, value):
|
||||
value = self.convert_value(value)
|
||||
if isinstance(value, datetime.time):
|
||||
return value.strftime(self.format)
|
||||
return ''
|
||||
|
||||
def convert_value(self, value):
|
||||
if isinstance(value, datetime.datetime):
|
||||
if not value.tzinfo:
|
||||
value = make_utc(value, tzinfo=True)
|
||||
return localtime(self.request.rattail_config, value).time()
|
||||
return value
|
||||
|
||||
def stringify_value(self, value, as_html=False):
|
||||
if not as_html:
|
||||
return self.render_value(value)
|
||||
return super(TimeFieldRenderer, self).stringify_value(value, as_html=as_html)
|
||||
|
||||
def _serialized_value(self):
|
||||
return self.params.getone(self.name)
|
||||
|
||||
def deserialize(self):
|
||||
value = self._serialized_value()
|
||||
if value:
|
||||
try:
|
||||
return datetime.datetime.strptime(value, self.format).time()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
class EmailFieldRenderer(fa.TextFieldRenderer):
|
||||
"""
|
||||
Renderer for email address fields
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
address = self.raw_value
|
||||
if not address:
|
||||
return ''
|
||||
return tags.link_to(address, 'mailto:{}'.format(address))
|
||||
|
||||
|
||||
class EnumFieldRenderer(fa_fields.SelectFieldRenderer):
|
||||
"""
|
||||
Renderer for simple enumeration fields.
|
||||
"""
|
||||
enumeration = {}
|
||||
render_key = False
|
||||
|
||||
def __init__(self, arg, render_key=False):
|
||||
if isinstance(arg, dict):
|
||||
self.enumeration = arg
|
||||
self.render_key = render_key
|
||||
else:
|
||||
self(arg)
|
||||
|
||||
def __call__(self, field):
|
||||
super(EnumFieldRenderer, self).__init__(field)
|
||||
return self
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
value = self.raw_value
|
||||
if value is None:
|
||||
return ''
|
||||
rendered = self.enumeration.get(value, unicode(value))
|
||||
if self.render_key:
|
||||
rendered = '{} - {}'.format(value, rendered)
|
||||
return rendered
|
||||
|
||||
def render(self, **kwargs):
|
||||
opts = [(self.enumeration[x], x) for x in self.enumeration]
|
||||
if not self.field.is_required():
|
||||
opts.insert(0, self.field._null_option)
|
||||
return fa_fields.SelectFieldRenderer.render(self, opts, **kwargs)
|
||||
|
||||
|
||||
class DecimalFieldRenderer(fa.FieldRenderer):
|
||||
"""
|
||||
Sort of generic field renderer for decimal values. You must provide the
|
||||
number of places after the decimal (scale). Note that this in turn relies
|
||||
on simple string formatting; the renderer does not attempt any mathematics
|
||||
of its own.
|
||||
"""
|
||||
|
||||
def __init__(self, scale):
|
||||
self.scale = scale
|
||||
|
||||
def __call__(self, field):
|
||||
super(DecimalFieldRenderer, self).__init__(field)
|
||||
return self
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
value = self.raw_value
|
||||
if value is None:
|
||||
return ''
|
||||
fmt = '{{0:0.{0}f}}'.format(self.scale)
|
||||
return fmt.format(value)
|
||||
|
||||
|
||||
class CurrencyFieldRenderer(fa_fields.FloatFieldRenderer):
|
||||
"""
|
||||
Sort of generic field renderer for currency values.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
value = self.raw_value
|
||||
if value is None:
|
||||
return ''
|
||||
if value < 0:
|
||||
return "(${:0,.2f})".format(0 - value)
|
||||
return "${:0,.2f}".format(value)
|
||||
|
||||
|
||||
class QuantityFieldRenderer(fa_fields.FloatFieldRenderer):
|
||||
"""
|
||||
Sort of generic field renderer for quantity values.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
return pretty_quantity(self.raw_value)
|
||||
|
||||
|
||||
class YesNoFieldRenderer(fa.CheckBoxFieldRenderer):
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
value = self.raw_value
|
||||
if value is None:
|
||||
return u''
|
||||
return u'Yes' if value else u'No'
|
|
@ -1,100 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Core Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import datetime
|
||||
|
||||
import formalchemy as fa
|
||||
from formalchemy.fields import AbstractField
|
||||
from pyramid.renderers import render
|
||||
|
||||
|
||||
class CustomFieldRenderer(fa.FieldRenderer):
|
||||
"""
|
||||
Base class for renderers which accept customization args, and "fake out"
|
||||
FormAlchemy by pretending to still be a renderer factory when in fact it's
|
||||
already dealing with a renderer instance.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if len(args) == 1 and isinstance(args[0], AbstractField):
|
||||
super(CustomFieldRenderer, self).__init__(args[0])
|
||||
self.init(**kwargs)
|
||||
else:
|
||||
assert len(args) == 0
|
||||
self.init(**kwargs)
|
||||
|
||||
def __call__(self, field):
|
||||
super(CustomFieldRenderer, self).__init__(field)
|
||||
return self
|
||||
|
||||
def init(self, **kwargs):
|
||||
pass
|
||||
|
||||
@property
|
||||
def rattail_config(self):
|
||||
return self.request.rattail_config
|
||||
|
||||
|
||||
class DateFieldRenderer(CustomFieldRenderer, fa.DateFieldRenderer):
|
||||
"""
|
||||
Date field renderer which uses jQuery UI datepicker widget when rendering
|
||||
in edit mode.
|
||||
"""
|
||||
date_format = '%Y-%m-%d'
|
||||
change_year = False
|
||||
|
||||
def init(self, date_format=None, change_year=False):
|
||||
if date_format:
|
||||
self.date_format = date_format
|
||||
self.change_year = change_year
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
value = self.raw_value
|
||||
if value is None:
|
||||
return ''
|
||||
return value.strftime(self.date_format)
|
||||
|
||||
def render(self, **kwargs):
|
||||
kwargs['name'] = self.name
|
||||
kwargs['value'] = self.value
|
||||
kwargs['change_year'] = self.change_year
|
||||
return render('/forms/fields/date.mako', kwargs)
|
||||
|
||||
def deserialize(self):
|
||||
value = self._serialized_value()
|
||||
if not value:
|
||||
return None
|
||||
try:
|
||||
return datetime.datetime.strptime(value, '%Y-%m-%d')
|
||||
except ValueError:
|
||||
raise fa.ValidationError("Date value must be in YYYY-MM-DD format")
|
||||
except Exception as error:
|
||||
raise fa.ValidationError(unicode(error))
|
||||
|
||||
def _serialized_value(self):
|
||||
return self.params.getone(self.name)
|
|
@ -1,42 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Customer order field renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import formalchemy as fa
|
||||
from webhelpers2.html import tags
|
||||
|
||||
|
||||
class CustomerOrderFieldRenderer(fa.fields.SelectFieldRenderer):
|
||||
"""
|
||||
Renders a link to the customer order
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
order = self.raw_value
|
||||
if not order:
|
||||
return ''
|
||||
return tags.link_to(order, self.request.route_url('custorders.view', uuid=order.uuid))
|
|
@ -1,49 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Employee Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import six
|
||||
from webhelpers2.html import tags
|
||||
|
||||
from tailbone.forms.renderers import AutocompleteFieldRenderer
|
||||
|
||||
|
||||
class EmployeeFieldRenderer(AutocompleteFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail.db.model.Employee` instance fields.
|
||||
"""
|
||||
service_route = 'employees.autocomplete'
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
employee = self.raw_value
|
||||
if not employee:
|
||||
return ''
|
||||
render_name = kwargs.get('render_name', six.text_type)
|
||||
title = render_name(employee)
|
||||
if kwargs.get('hyperlink') and self.request.has_perm('employees.view'):
|
||||
return tags.link_to(title, self.request.route_url('employees.view', uuid=employee.uuid))
|
||||
return title
|
|
@ -1,102 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Batch Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import os
|
||||
import stat
|
||||
import random
|
||||
|
||||
from formalchemy.ext import fsblob
|
||||
from formalchemy.fields import FileFieldRenderer as Base
|
||||
|
||||
|
||||
class FileFieldRenderer(fsblob.FileFieldRenderer):
|
||||
"""
|
||||
Custom file field renderer. In readonly mode, shows a filename and its
|
||||
size; in edit mode, supports a single file upload.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def new(cls, view, **kwargs):
|
||||
name = b'Configured{}_{}'.format(cls.__name__, str(random.random())[2:])
|
||||
return type(name, (cls,), dict(view=view, **kwargs))
|
||||
|
||||
@property
|
||||
def request(self):
|
||||
return self.view.request
|
||||
|
||||
@property
|
||||
def storage_path(self):
|
||||
return self.view.upload_dir
|
||||
|
||||
def get_file_path(self):
|
||||
"""
|
||||
Returns the absolute path to the data file.
|
||||
"""
|
||||
if hasattr(self, 'file_path'):
|
||||
return self.file_path
|
||||
return self.field.value
|
||||
|
||||
def get_size(self):
|
||||
"""
|
||||
Returns the size of the data file, in bytes.
|
||||
"""
|
||||
path = self.get_file_path()
|
||||
if path and os.path.isfile(path):
|
||||
return os.stat(path)[stat.ST_SIZE]
|
||||
return 0
|
||||
|
||||
def get_url(self, filename):
|
||||
"""
|
||||
Must return a URL suitable for downloading the file
|
||||
"""
|
||||
url = self.get_download_url()
|
||||
if url:
|
||||
if callable(url):
|
||||
return url(filename)
|
||||
return url
|
||||
return self.view.get_action_url('download', self.field.parent.model)
|
||||
|
||||
def get_download_url(self):
|
||||
if hasattr(self, 'download_url'):
|
||||
return self.download_url
|
||||
|
||||
def render(self, **kwargs):
|
||||
return Base.render(self, **kwargs)
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
"""
|
||||
Render the filename and the binary size in a human readable with a link
|
||||
to the file itself.
|
||||
"""
|
||||
value = self.get_file_path()
|
||||
if value:
|
||||
content = '{} ({})'.format(fsblob.normalized_basename(value),
|
||||
self.readable_size())
|
||||
return fsblob.h.content_tag('a', content,
|
||||
href=self.get_url(value), **kwargs)
|
||||
return ''
|
|
@ -1,81 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
People Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import six
|
||||
import formalchemy as fa
|
||||
from webhelpers2.html import tags, HTML
|
||||
|
||||
from tailbone.forms.renderers.common import AutocompleteFieldRenderer
|
||||
|
||||
|
||||
class PersonFieldRenderer(AutocompleteFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail.db.model.Person` instance fields.
|
||||
"""
|
||||
service_route = 'people.autocomplete'
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
person = self.raw_value
|
||||
if not person:
|
||||
return ''
|
||||
return tags.link_to(person, self.request.route_url('people.view', uuid=person.uuid))
|
||||
|
||||
|
||||
class PeopleFieldRenderer(fa.FieldRenderer):
|
||||
"""
|
||||
Renderer for "people" list relationship
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
html = ''
|
||||
people = self.raw_value
|
||||
if not people:
|
||||
return html
|
||||
for person in people:
|
||||
link = tags.link_to(person, self.request.route_url('people.view', uuid=person.uuid))
|
||||
html += HTML.tag('li', c=link)
|
||||
html = HTML.tag('ul', c=html)
|
||||
return html
|
||||
|
||||
|
||||
class CustomerFieldRenderer(AutocompleteFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail.db.model.Customer` instance fields.
|
||||
"""
|
||||
|
||||
service_route = 'customers.autocomplete'
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
customer = self.raw_value
|
||||
if not customer:
|
||||
return ''
|
||||
text = self.render_value(customer)
|
||||
return tags.link_to(text, self.request.route_url('customers.view', uuid=customer.uuid))
|
||||
|
||||
def render_value(self, customer):
|
||||
return six.text_type(customer)
|
|
@ -1,224 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Product Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import six
|
||||
|
||||
from rattail.gpc import GPC
|
||||
from rattail.db import model
|
||||
from rattail.db.util import maxlen
|
||||
|
||||
import formalchemy as fa
|
||||
from formalchemy import TextFieldRenderer
|
||||
from formalchemy.fields import SelectFieldRenderer
|
||||
from webhelpers2.html import tags, literal
|
||||
|
||||
from tailbone.forms.renderers.common import AutocompleteFieldRenderer
|
||||
from tailbone.util import pretty_datetime
|
||||
|
||||
|
||||
class ProductFieldRenderer(AutocompleteFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail.db.model.Product` instance fields.
|
||||
"""
|
||||
|
||||
service_route = 'products.autocomplete'
|
||||
|
||||
@property
|
||||
def field_display(self):
|
||||
product = self.raw_value
|
||||
if product:
|
||||
return product.full_description
|
||||
return ''
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
product = self.raw_value
|
||||
if not product:
|
||||
return ""
|
||||
render = kwargs.get('render_product', self.render_product)
|
||||
text = render(product)
|
||||
if kwargs.get('hyperlink', True):
|
||||
return tags.link_to(text, self.request.route_url('products.view', uuid=product.uuid))
|
||||
return text
|
||||
|
||||
def render_product(self, product):
|
||||
return six.text_type(product)
|
||||
|
||||
|
||||
class ProductKeyFieldRenderer(TextFieldRenderer):
|
||||
"""
|
||||
Base class for product key field renderers.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
value = self.raw_value
|
||||
if value is None:
|
||||
return ''
|
||||
value = self.render_value(value)
|
||||
if kwargs.get('link'):
|
||||
product = self.field.parent.model
|
||||
value = tags.link_to(value, kwargs['link'](product))
|
||||
return value
|
||||
|
||||
def render_value(self, value):
|
||||
return unicode(value)
|
||||
|
||||
|
||||
class GPCFieldRenderer(ProductKeyFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail.gpc.GPC` fields.
|
||||
"""
|
||||
|
||||
@property
|
||||
def length(self):
|
||||
# Hm, should maybe consider hard-coding this...?
|
||||
return len(unicode(GPC(0)))
|
||||
|
||||
def render_value(self, gpc):
|
||||
return gpc.pretty()
|
||||
|
||||
|
||||
class ScancodeFieldRenderer(ProductKeyFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail.db.model.Product.scancode` field
|
||||
"""
|
||||
|
||||
@property
|
||||
def length(self):
|
||||
return maxlen(model.Product.scancode)
|
||||
|
||||
|
||||
class DepartmentFieldRenderer(SelectFieldRenderer):
|
||||
"""
|
||||
Shows the department number as well as the name.
|
||||
"""
|
||||
|
||||
def render(self, **kwargs):
|
||||
kwargs.setdefault('auto-enhance', 'true')
|
||||
return super(DepartmentFieldRenderer, self).render(**kwargs)
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
department = self.raw_value
|
||||
if not department:
|
||||
return ''
|
||||
if department.number:
|
||||
text = '({}) {}'.format(department.number, department.name)
|
||||
else:
|
||||
text = department.name
|
||||
return tags.link_to(text, self.request.route_url('departments.view', uuid=department.uuid))
|
||||
|
||||
|
||||
class SubdepartmentFieldRenderer(SelectFieldRenderer):
|
||||
"""
|
||||
Shows a link to the subdepartment.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
subdept = self.raw_value
|
||||
if not subdept:
|
||||
return ""
|
||||
if subdept.number:
|
||||
text = "({}) {}".format(subdept.number, subdept.name)
|
||||
else:
|
||||
text = subdept.name
|
||||
return tags.link_to(text, self.request.route_url('subdepartments.view', uuid=subdept.uuid))
|
||||
|
||||
|
||||
class CategoryFieldRenderer(SelectFieldRenderer):
|
||||
"""
|
||||
Shows a link to the category.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
category = self.raw_value
|
||||
if not category:
|
||||
return ""
|
||||
if category.code:
|
||||
text = "({}) {}".format(category.code, category.name)
|
||||
else:
|
||||
text = category.name
|
||||
return tags.link_to(text, self.request.route_url('categories.view', uuid=category.uuid))
|
||||
|
||||
|
||||
class BrandFieldRenderer(AutocompleteFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail.db.model.Brand` instance fields.
|
||||
"""
|
||||
|
||||
service_route = 'brands.autocomplete'
|
||||
|
||||
|
||||
class CostFieldRenderer(fa.FieldRenderer):
|
||||
"""
|
||||
Renders fields which reference a ProductCost object
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
cost = self.raw_value
|
||||
if not cost:
|
||||
return ''
|
||||
return '${:0.2f}'.format(cost.unit_cost)
|
||||
|
||||
|
||||
class PriceFieldRenderer(TextFieldRenderer):
|
||||
"""
|
||||
Renderer for fields which reference a :class:`ProductPrice` instance.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
price = self.field.raw_value
|
||||
if price:
|
||||
if not price.product.not_for_sale:
|
||||
if price.price is not None and price.pack_price is not None:
|
||||
if price.multiple > 1:
|
||||
return literal('$ %0.2f / %u ($ %0.2f / %u)' % (
|
||||
price.price, price.multiple,
|
||||
price.pack_price, price.pack_multiple))
|
||||
return literal('$ %0.2f ($ %0.2f / %u)' % (
|
||||
price.price, price.pack_price, price.pack_multiple))
|
||||
if price.price is not None:
|
||||
if price.multiple > 1:
|
||||
return '$ %0.2f / %u' % (price.price, price.multiple)
|
||||
return '$ %0.2f' % price.price
|
||||
if price.pack_price is not None:
|
||||
return '$ %0.2f / %u' % (price.pack_price, price.pack_multiple)
|
||||
return ''
|
||||
|
||||
|
||||
class PriceWithExpirationFieldRenderer(PriceFieldRenderer):
|
||||
"""
|
||||
Price field renderer which also displays the expiration date, if present.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
result = super(PriceWithExpirationFieldRenderer, self).render_readonly(**kwargs)
|
||||
if result:
|
||||
price = self.field.raw_value
|
||||
if price.ends:
|
||||
result = '{0} ({1})'.format(
|
||||
result, pretty_datetime(self.request.rattail_config, price.ends))
|
||||
return result
|
|
@ -1,49 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Store Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from formalchemy.fields import SelectFieldRenderer
|
||||
from webhelpers2.html import tags
|
||||
|
||||
|
||||
class StoreFieldRenderer(SelectFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail.db.model.Store` instance fields.
|
||||
"""
|
||||
|
||||
def render(self, **kwargs):
|
||||
kwargs.setdefault('auto-enhance', 'true')
|
||||
return super(StoreFieldRenderer, self).render(**kwargs)
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
store = self.raw_value
|
||||
if not store:
|
||||
return ""
|
||||
text = "({}) {}".format(store.id, store.name)
|
||||
if kwargs.get('hyperlink', True):
|
||||
return tags.link_to(text, self.request.route_url('stores.view', uuid=store.uuid))
|
||||
return text
|
|
@ -1,97 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
User Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import six
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.auth import has_permission, administrator_role
|
||||
|
||||
import formalchemy
|
||||
from webhelpers2.html import HTML, tags
|
||||
|
||||
from tailbone.db import Session
|
||||
|
||||
|
||||
class UserFieldRenderer(formalchemy.TextFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail:rattail.db.model.User` instance fields.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
user = self.raw_value
|
||||
if not user:
|
||||
return ''
|
||||
title = six.text_type(user)
|
||||
if kwargs.get('hyperlink') and self.request.has_perm('users.view'):
|
||||
return tags.link_to(title, self.request.route_url('users.view', uuid=user.uuid))
|
||||
return title
|
||||
|
||||
|
||||
def PermissionsFieldRenderer(permissions, include_guest=False, include_authenticated=False):
|
||||
|
||||
class PermissionsFieldRenderer(formalchemy.FieldRenderer):
|
||||
|
||||
def deserialize(self):
|
||||
perms = []
|
||||
i = len(self.name) + 1
|
||||
for key in self.params:
|
||||
if key.startswith(self.name):
|
||||
perms.append(key[i:])
|
||||
return perms
|
||||
|
||||
def _render(self, readonly=False, **kwargs):
|
||||
principal = self.field.model
|
||||
html = ''
|
||||
for groupkey in sorted(permissions, key=lambda k: permissions[k]['label'].lower()):
|
||||
inner = HTML.tag('p', c=permissions[groupkey]['label'])
|
||||
perms = permissions[groupkey]['perms']
|
||||
rendered = False
|
||||
for key in sorted(perms, key=lambda p: perms[p]['label'].lower()):
|
||||
checked = has_permission(Session(), principal, key,
|
||||
include_guest=include_guest,
|
||||
include_authenticated=include_authenticated)
|
||||
if checked or not readonly:
|
||||
label = perms[key]['label']
|
||||
if readonly:
|
||||
span = HTML.tag('span', c="[X]" if checked else "[ ]")
|
||||
inner += HTML.tag('p', class_='perm', c=span + ' ' + label)
|
||||
else:
|
||||
inner += tags.checkbox(self.name + '-' + key,
|
||||
checked=checked, label=label)
|
||||
rendered = True
|
||||
if rendered:
|
||||
html += HTML.tag('div', class_='group', c=inner)
|
||||
return html or "(none granted)"
|
||||
|
||||
def render(self, **kwargs):
|
||||
return self._render(**kwargs)
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
return self._render(readonly=True, **kwargs)
|
||||
|
||||
return PermissionsFieldRenderer
|
|
@ -1,60 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Vendor Field Renderers
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from formalchemy.fields import SelectFieldRenderer
|
||||
from webhelpers2.html import tags
|
||||
|
||||
from tailbone.forms.renderers.common import AutocompleteFieldRenderer
|
||||
|
||||
|
||||
class VendorFieldRenderer(AutocompleteFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail.db.model.Vendor` instance fields.
|
||||
"""
|
||||
service_route = 'vendors.autocomplete'
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
vendor = self.raw_value
|
||||
if not vendor:
|
||||
return ""
|
||||
text = "({}) {}".format(vendor.id, vendor.name)
|
||||
if kwargs.get('hyperlink', True):
|
||||
return tags.link_to(text, self.request.route_url('vendors.view', uuid=vendor.uuid))
|
||||
return text
|
||||
|
||||
|
||||
class PurchaseFieldRenderer(SelectFieldRenderer):
|
||||
"""
|
||||
Renderer for :class:`rattail.db.model.Purchase` relation fields.
|
||||
"""
|
||||
|
||||
def render_readonly(self, **kwargs):
|
||||
purchase = self.raw_value
|
||||
if not purchase:
|
||||
return ''
|
||||
return tags.link_to(purchase, self.request.route_url('purchases.view', uuid=purchase.uuid))
|
|
@ -1,82 +0,0 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Simple Forms
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
from rattail.util import prettify
|
||||
|
||||
import pyramid_simpleform
|
||||
from pyramid_simpleform import renderers
|
||||
from webhelpers2.html import tags, HTML
|
||||
|
||||
from tailbone.forms import Form
|
||||
|
||||
|
||||
class SimpleForm(Form):
|
||||
"""
|
||||
Customized simple form.
|
||||
"""
|
||||
|
||||
def __init__(self, request, schema, obj=None, **kwargs):
|
||||
super(SimpleForm, self).__init__(request, **kwargs)
|
||||
self._form = pyramid_simpleform.Form(request, schema=schema, obj=obj)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self._form, attr)
|
||||
|
||||
def render(self, **kwargs):
|
||||
kwargs['form'] = FormRenderer(self)
|
||||
return super(SimpleForm, self).render(**kwargs)
|
||||
|
||||
def validate(self):
|
||||
return self._form.validate()
|
||||
|
||||
|
||||
class FormRenderer(renderers.FormRenderer):
|
||||
"""
|
||||
Customized form renderer. Provides some extra methods for convenience.
|
||||
"""
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self.form, attr)
|
||||
|
||||
def field_div(self, name, field, label=None):
|
||||
errors = self.errors_for(name)
|
||||
if errors:
|
||||
errors = [HTML.tag('div', class_='field-error', c=x) for x in errors]
|
||||
errors = tags.literal('').join(errors)
|
||||
|
||||
label = HTML.tag('label', for_=name, c=label or prettify(name))
|
||||
inner = HTML.tag('div', class_='field', c=field)
|
||||
|
||||
outer_class = 'field-wrapper {}'.format(name)
|
||||
if errors:
|
||||
outer_class += ' error'
|
||||
outer = HTML.tag('div', class_=outer_class, c=(errors or '') + label + inner)
|
||||
return outer
|
||||
|
||||
def referrer_field(self):
|
||||
return self.hidden('referrer', value=self.form.request.get_referrer())
|
|
@ -1,153 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2017 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
# Rattail is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# Rattail is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# Rattail. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Custom Form Validators
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
import re
|
||||
|
||||
from rattail.db import model
|
||||
from rattail.db.util import validate_email_address, validate_phone_number
|
||||
from rattail.gpc import GPC
|
||||
|
||||
import formencode as fe
|
||||
import formalchemy as fa
|
||||
|
||||
from tailbone.db import Session
|
||||
|
||||
|
||||
class ValidGPC(fe.validators.FancyValidator):
|
||||
"""
|
||||
Validator for fields which should contain GPC value.
|
||||
"""
|
||||
|
||||
def _to_python(self, value, state):
|
||||
if value is not None:
|
||||
digits = re.sub(r'\D', '', value)
|
||||
if digits:
|
||||
try:
|
||||
return GPC(digits)
|
||||
except ValueError as error:
|
||||
raise fe.Invalid("Invalid UPC: {}".format(error), value, state)
|
||||
|
||||
def _from_python(self, upc, state):
|
||||
if upc is None:
|
||||
return ''
|
||||
return upc.pretty()
|
||||
|
||||
|
||||
class ModelValidator(fe.validators.FancyValidator):
|
||||
"""
|
||||
Generic validator for data model reference fields.
|
||||
"""
|
||||
model_class = None
|
||||
|
||||
@property
|
||||
def model_name(self):
|
||||
self.model_class.__name__
|
||||
|
||||
def _to_python(self, value, state):
|
||||
if value:
|
||||
obj = Session.query(self.model_class).get(value)
|
||||
if obj:
|
||||
return obj
|
||||
raise fe.Invalid("{} not found".format(self.model_name), value, state)
|
||||
|
||||
def _from_python(self, value, state):
|
||||
obj = value
|
||||
if not obj:
|
||||
return ''
|
||||
return obj.uuid
|
||||
|
||||
def validate_python(self, value, state):
|
||||
obj = value
|
||||
if obj is not None and not isinstance(obj, self.model_class):
|
||||
raise fe.Invalid("Value must be a valid {} object".format(self.model_name), value, state)
|
||||
|
||||
|
||||
class ValidStore(ModelValidator):
|
||||
"""
|
||||
Validator for store field.
|
||||
"""
|
||||
model_class = model.Store
|
||||
|
||||
|
||||
class ValidCustomer(ModelValidator):
|
||||
"""
|
||||
Validator for customer field.
|
||||
"""
|
||||
model_class = model.Customer
|
||||
|
||||
|
||||
class ValidDepartment(ModelValidator):
|
||||
"""
|
||||
Validator for department field.
|
||||
"""
|
||||
model_class = model.Department
|
||||
|
||||
|
||||
class ValidEmployee(ModelValidator):
|
||||
"""
|
||||
Validator for employee field.
|
||||
"""
|
||||
model_class = model.Employee
|
||||
|
||||
|
||||
class ValidProduct(ModelValidator):
|
||||
"""
|
||||
Validator for product field.
|
||||
"""
|
||||
model_class = model.Product
|
||||
|
||||
|
||||
class ValidUser(ModelValidator):
|
||||
"""
|
||||
Validator for user field.
|
||||
"""
|
||||
model_class = model.User
|
||||
|
||||
|
||||
def valid_email_address(value, field=None):
|
||||
"""
|
||||
FormAlchemy-compatible validation function, which leverages FormEncode
|
||||
under the hood.
|
||||
"""
|
||||
if value:
|
||||
try:
|
||||
return validate_email_address(value, error=True)
|
||||
except Exception as error:
|
||||
raise fa.ValidationError(unicode(error))
|
||||
|
||||
|
||||
def valid_phone_number(value, field=None):
|
||||
"""
|
||||
FormAlchemy-compatible validation function, which leverages FormEncode
|
||||
under the hood.
|
||||
"""
|
||||
if value:
|
||||
try:
|
||||
return validate_phone_number(value, error=True)
|
||||
except Exception as error:
|
||||
raise fa.ValidationError(unicode(error))
|
|
@ -1,4 +0,0 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%namespace file="/autocomplete.mako" import="autocomplete" />
|
||||
|
||||
${autocomplete(field_name, service_url, field_value, field_display, width=width, selected=selected, cleared=cleared)}
|
|
@ -1,10 +0,0 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
${h.text(name, value=value)}
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
$('input[name="${name}"]').datepicker({
|
||||
changeYear: ${'true' if change_year else 'false'},
|
||||
dateFormat: 'yy-mm-dd'
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -1,40 +0,0 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<% _focus_rendered = False %>
|
||||
|
||||
% for error in fieldset.errors.get(None, []):
|
||||
<div class="fieldset-error">${error}</div>
|
||||
% endfor
|
||||
|
||||
% for field in fieldset.render_fields.itervalues():
|
||||
|
||||
% if field.requires_label:
|
||||
<div class="field-wrapper ${field.name}">
|
||||
% for error in field.errors:
|
||||
<div class="field-error">${error}</div>
|
||||
% endfor
|
||||
${field.label_tag()|n}
|
||||
<div class="field">${field.render()|n}</div>
|
||||
% if 'instructions' in field.metadata:
|
||||
<span class="instructions">${field.metadata['instructions']}</span>
|
||||
% endif
|
||||
</div>
|
||||
|
||||
% if not _focus_rendered and (fieldset.focus is True or fieldset.focus is field):
|
||||
% if not field.is_readonly() and getattr(field.renderer, 'needs_focus', True):
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
% if hasattr(field.renderer, 'focus_name'):
|
||||
$('#${field.renderer.focus_name}').focus();
|
||||
% else:
|
||||
$('#${field.renderer.name}').focus();
|
||||
% endif
|
||||
});
|
||||
</script>
|
||||
<% _focus_rendered = True %>
|
||||
% endif
|
||||
% endif
|
||||
% else:
|
||||
${field.render()|n}
|
||||
% endif
|
||||
|
||||
% endfor
|
|
@ -1,7 +0,0 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%namespace file="/forms/lib.mako" import="render_field_readonly" />
|
||||
<div class="fieldset">
|
||||
% for field in fieldset.render_fields.itervalues():
|
||||
${render_field_readonly(field)}
|
||||
% endfor
|
||||
</div>
|
|
@ -1,21 +0,0 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<div class="form">
|
||||
${h.form(form.action_url, id=form.id or None, method='post', enctype='multipart/form-data')}
|
||||
${form.csrf_token()}
|
||||
|
||||
${form.render_fields()|n}
|
||||
|
||||
% if buttons:
|
||||
${buttons|n}
|
||||
% else:
|
||||
<div class="buttons">
|
||||
${h.submit('create', form.create_label if form.creating else form.update_label)}
|
||||
% if form.creating and form.allow_successive_creates:
|
||||
${h.submit('create_and_continue', form.successive_create_label)}
|
||||
% endif
|
||||
<a href="${form.cancel_url}" class="button">Cancel</a>
|
||||
</div>
|
||||
% endif
|
||||
|
||||
${h.end_form()}
|
||||
</div>
|
|
@ -1,7 +0,0 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<div class="form">
|
||||
${form.render_fields()|n}
|
||||
% if buttons:
|
||||
${buttons|n}
|
||||
% endif
|
||||
</div>
|
|
@ -1,10 +0,0 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
|
||||
<%def name="render_field_readonly(field)">
|
||||
% if field.requires_label:
|
||||
<div class="field-wrapper ${field.name}">
|
||||
${field.label_tag()|n}
|
||||
<div class="field">${field.render_readonly()}</div>
|
||||
</div>
|
||||
% endif
|
||||
</%def>
|
Loading…
Reference in a new issue