Remove legacy 'forms' package and templates
yay!
This commit is contained in:
		
							parent
							
								
									66769ab34b
								
							
						
					
					
						commit
						d0b78babd2
					
				
					 26 changed files with 0 additions and 2051 deletions
				
			
		| 
						 | 
				
			
			@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue