diff --git a/tailbone/forms/core.py b/tailbone/forms/core.py index 18c6a8c7..6762b79b 100644 --- a/tailbone/forms/core.py +++ b/tailbone/forms/core.py @@ -37,6 +37,7 @@ from sqlalchemy.ext.associationproxy import AssociationProxy, ASSOCIATION_PROXY from rattail.time import localtime from rattail.util import prettify, pretty_boolean, pretty_hours, pretty_quantity +from rattail.core import UNSPECIFIED import colander import deform @@ -338,7 +339,7 @@ class Form(object): auto_disable_cancel = True def __init__(self, fields=None, schema=None, request=None, mobile=False, readonly=False, readonly_fields=[], - model_instance=None, model_class=None, nodes={}, enums={}, labels={}, renderers=None, + model_instance=None, model_class=None, appstruct=UNSPECIFIED, nodes={}, enums={}, labels={}, renderers=None, hidden={}, widgets={}, defaults={}, validators={}, required={}, helptext={}, focus_spec=None, action_url=None, cancel_url=None, use_buefy=None): @@ -358,6 +359,7 @@ class Form(object): self.model_class = type(self.model_instance) if self.model_class and self.fields is None: self.set_fields(self.make_fields()) + self.appstruct = appstruct self.nodes = nodes or {} self.enums = enums or {} self.labels = labels or {} @@ -706,7 +708,12 @@ class Form(object): # get initial form values from model instance kwargs = {} - if self.model_instance: + # TODO: ugh, this is necessary to avoid some logic + # which assumes a ColanderAlchemy schema i think? + if self.appstruct is not UNSPECIFIED: + if self.appstruct: + kwargs['appstruct'] = self.appstruct + elif self.model_instance: if self.model_class: kwargs['appstruct'] = schema.dictify(self.model_instance) else: diff --git a/tailbone/templates/labels/profiles/printer.mako b/tailbone/templates/labels/profiles/printer.mako index da557b61..8d70534e 100644 --- a/tailbone/templates/labels/profiles/printer.mako +++ b/tailbone/templates/labels/profiles/printer.mako @@ -1,5 +1,5 @@ -## -*- coding: utf-8 -*- -<%inherit file="/base.mako" /> +## -*- coding: utf-8; -*- +<%inherit file="/form.mako" /> <%def name="title()">Printer Settings @@ -9,42 +9,5 @@
  • ${h.link_to("Edit this Label Profile", url('labelprofiles.edit', uuid=profile.uuid))}
  • -
    - - -
    - -
    - -
    ${profile.description}
    -
    - -
    - -
    ${profile.printer_spec}
    -
    - - ${h.form(request.current_route_url())} - ${h.csrf_token(request)} - - % for name, display in printer.required_settings.items(): -
    - -
    - ${h.text(name, value=profile.get_printer_setting(name))} -
    -
    - % endfor - -
    - ${h.submit('update', "Update")} - -
    - - ${h.end_form()} -
    - -
    +${parent.body()} diff --git a/tailbone/views/labels/profiles.py b/tailbone/views/labels/profiles.py index a3f051f5..d1b3fea4 100644 --- a/tailbone/views/labels/profiles.py +++ b/tailbone/views/labels/profiles.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2018 Lance Edgar +# Copyright © 2010-2019 Lance Edgar # # This file is part of Rattail. # @@ -28,9 +28,9 @@ from __future__ import unicode_literals, absolute_import from rattail.db import model -from pyramid.httpexceptions import HTTPFound +import colander -from tailbone.db import Session +from tailbone import forms from tailbone.views import MasterView @@ -87,40 +87,83 @@ class ProfilesView(MasterView): except NotImplementedError: pass + def make_printer_settings_form(self, profile, printer): + schema = colander.Schema() -def printer_settings(request): - uuid = request.matchdict['uuid'] - profile = Session.query(model.LabelProfile).get(uuid) if uuid else None - if not profile: - return HTTPFound(location=request.route_url('labelprofiles')) + for name, label in printer.required_settings.items(): + node = colander.SchemaNode(colander.String(), + name=name, + title=label, + default=profile.get_printer_setting(name)) + schema.add(node) - read_profile = HTTPFound(location=request.route_url( - 'labelprofiles.view', uuid=profile.uuid)) + form = forms.Form(schema=schema, request=self.request, + model_instance=profile, + # TODO: ugh, this is necessary to avoid some logic + # which assumes a ColanderAlchemy schema i think? + appstruct=None) + form.cancel_url = self.get_action_url('view', profile) - printer = profile.get_printer(request.rattail_config) - if not printer: - request.session.flash("Label profile \"%s\" does not have a functional " - "printer spec." % profile) - return read_profile - if not printer.required_settings: - request.session.flash("Printer class for label profile \"%s\" does not " - "require any settings." % profile) - return read_profile + form.insert_before(schema.children[0].name, 'label_profile') + form.set_readonly('label_profile') + form.set_renderer('label_profile', lambda p, f: p.description) - if request.method == 'POST': - for setting in printer.required_settings: - if setting in request.POST: - profile.save_printer_setting(setting, request.POST[setting]) - return read_profile + form.insert_after('label_profile', 'printer_spec') + form.set_readonly('printer_spec') + form.set_renderer('printer_spec', lambda p, f: p.printer_spec) - return {'profile': profile, 'printer': printer} + return form + + def printer_settings(self): + """ + View for editing extended Printer Settings, for a given Label Profile. + """ + profile = self.get_instance() + read_profile = self.redirect(self.get_action_url('view', profile)) + + printer = profile.get_printer(self.rattail_config) + if not printer: + msg = "Label profile \"{}\" does not have a functional printer spec.".format(profile) + self.request.session.flash(msg) + return read_profile + if not printer.required_settings: + msg = "Printer class for label profile \"{}\" does not require any settings.".format(profile) + self.request.session.flash(msg) + return read_profile + + form = self.make_printer_settings_form(profile, printer) + + # TODO: should use form.validate() here + if self.request.method == 'POST': + for setting in printer.required_settings: + if setting in self.request.POST: + profile.save_printer_setting(setting, self.request.POST[setting]) + return read_profile + + return self.render_to_response('printer', { + 'form': form, + 'dform': form.make_deform_form(), + 'profile': profile, + 'printer': printer, + }) + + @classmethod + def defaults(cls, config): + cls._defaults(config) + cls._labelprofile_defaults(config) + + @classmethod + def _labelprofile_defaults(cls, config): + route_prefix = cls.get_route_prefix() + url_prefix = cls.get_url_prefix() + permission_prefix = cls.get_permission_prefix() + model_key = cls.get_model_key() + + # edit printer settings + config.add_route('{}.printer_settings'.format(route_prefix), '{}/{{{}}}/printer'.format(url_prefix, model_key)) + config.add_view(cls, attr='printer_settings', route_name='{}.printer_settings'.format(route_prefix), + permission='{}.edit'.format(permission_prefix)) def includeme(config): ProfilesView.defaults(config) - - # edit printer settings - config.add_route('labelprofiles.printer_settings', '/labels/profiles/{uuid}/printer') - config.add_view(printer_settings, route_name='labelprofiles.printer_settings', - renderer='/labels/profiles/printer.mako', - permission='labelprofiles.edit')