Remove all deprecated use_buefy logic

also remove some static files no longer used, etc.
This commit is contained in:
Lance Edgar 2023-02-03 12:05:17 -06:00
parent 01e5eee981
commit 9faaea881d
112 changed files with 2079 additions and 7039 deletions

View file

@ -24,12 +24,9 @@
Forms Core
"""
from __future__ import unicode_literals, absolute_import
import json
import logging
import six
import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.ext.associationproxy import AssociationProxy, ASSOCIATION_PROXY
@ -338,7 +335,7 @@ class Form(object):
model_instance=None, model_class=None, appstruct=UNSPECIFIED, nodes={}, enums={}, labels={},
assume_local_times=False, renderers=None, renderer_kwargs={},
hidden={}, widgets={}, defaults={}, validators={}, required={}, helptext={}, focus_spec=None,
action_url=None, cancel_url=None, use_buefy=True, component='tailbone-form',
action_url=None, cancel_url=None, component='tailbone-form',
vuejs_field_converters={},
# TODO: ugh this is getting out hand!
can_edit_help=False, edit_help_url=None, route_prefix=None,
@ -377,7 +374,6 @@ class Form(object):
self.focus_spec = focus_spec
self.action_url = action_url
self.cancel_url = cancel_url
self.use_buefy = use_buefy
self.component = component
self.vuejs_field_converters = vuejs_field_converters or {}
self.can_edit_help = can_edit_help
@ -758,10 +754,7 @@ class Form(object):
def render(self, template=None, **kwargs):
if not template:
if self.readonly and not self.use_buefy:
template = '/forms/form_readonly.mako'
else:
template = '/forms/form.mako'
template = '/forms/form.mako'
context = kwargs
context['form'] = self
return render(template, context)
@ -806,10 +799,7 @@ class Form(object):
def render_deform(self, dform=None, template=None, **kwargs):
if not template:
if self.use_buefy:
template = '/forms/deform_buefy.mako'
else:
template = '/forms/deform.mako'
template = '/forms/deform_buefy.mako'
if dform is None:
dform = self.make_deform_form()
@ -829,11 +819,8 @@ class Form(object):
context.setdefault('form_kwargs', {})
# TODO: deprecate / remove the latter option here
if self.auto_disable_save or self.auto_disable:
if self.use_buefy:
context['form_kwargs'].setdefault('ref', self.component_studly)
context['form_kwargs']['@submit'] = 'submit{}'.format(self.component_studly)
else:
context['form_kwargs']['class_'] = 'autodisable'
context['form_kwargs'].setdefault('ref', self.component_studly)
context['form_kwargs']['@submit'] = 'submit{}'.format(self.component_studly)
if self.focus_spec:
context['form_kwargs']['data-focus'] = self.focus_spec
context['request'] = self.request
@ -975,8 +962,7 @@ class Form(object):
if self.readonly or fieldname in self.readonly_fields:
html = self.render_field_value(fieldname) or HTML.tag('span')
elif field:
html = field.serialize(use_buefy=True,
**self.get_renderer_kwargs(fieldname))
html = field.serialize(**self.get_renderer_kwargs(fieldname))
html = HTML.literal(html)
# may need a complex label
@ -1064,7 +1050,7 @@ class Form(object):
value = self.obtain_value(record, field_name)
if value is None:
return ""
return six.text_type(value)
return str(value)
def render_datetime(self, record, field_name):
value = self.obtain_value(record, field_name)
@ -1099,7 +1085,7 @@ class Form(object):
return "(${:0,.2f})".format(0 - value)
return "${:0,.2f}".format(value)
except ValueError:
return six.text_type(value)
return str(value)
def render_quantity(self, obj, field):
value = self.obtain_value(obj, field)
@ -1124,8 +1110,8 @@ class Form(object):
return ""
enum = self.enums.get(field_name)
if enum and value in enum:
return six.text_type(enum[value])
return six.text_type(value)
return str(enum[value])
return str(value)
def render_codeblock(self, record, field_name):
value = self.obtain_value(record, field_name)
@ -1193,8 +1179,8 @@ class Form(object):
controls[i][1] = 'true'
elif value is False:
controls[i][1] = 'false'
elif not isinstance(value, six.string_types):
controls[i][1] = six.text_type(value)
elif not isinstance(value, str):
controls[i][1] = str(value)
dform = self.make_deform_form()
try:

View file

@ -1,69 +0,0 @@
ul.tagit {
padding: 1px 5px;
overflow: auto;
margin-left: inherit; /* usually we don't want the regular ul margins. */
margin-right: inherit;
}
ul.tagit li {
display: block;
float: left;
margin: 2px 5px 2px 0;
}
ul.tagit li.tagit-choice {
position: relative;
line-height: inherit;
}
input.tagit-hidden-field {
display: none;
}
ul.tagit li.tagit-choice-read-only {
padding: .2em .5em .2em .5em;
}
ul.tagit li.tagit-choice-editable {
padding: .2em 18px .2em .5em;
}
ul.tagit li.tagit-new {
padding: .25em 4px .25em 0;
}
ul.tagit li.tagit-choice a.tagit-label {
cursor: pointer;
text-decoration: none;
}
ul.tagit li.tagit-choice .tagit-close {
cursor: pointer;
position: absolute;
right: .1em;
top: 50%;
margin-top: -8px;
line-height: 17px;
}
/* used for some custom themes that don't need image icons */
ul.tagit li.tagit-choice .tagit-close .text-icon {
display: none;
}
ul.tagit li.tagit-choice input {
display: block;
float: left;
margin: 2px 5px 2px 0;
}
ul.tagit input[type="text"] {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
border: none;
margin: 0;
padding: 0;
width: inherit;
background-color: inherit;
outline: none;
}

View file

@ -1,48 +0,0 @@
/******************************
* login.css
******************************/
.logo img,
#logo {
display: block;
margin: 40px auto;
max-height: 350px;
max-width: 800px;
}
div.form {
margin: auto;
float: none;
text-align: center;
}
div.field-wrapper {
margin: 10px auto;
width: 300px;
}
div.field-wrapper label {
text-align: right;
width: auto;
}
div.field-wrapper div.field input[type="text"],
div.field-wrapper div.field input[type="password"] {
margin-left: 1em;
width: 150px;
}
div.buttons {
display: block;
}
div.buttons input {
margin: auto 5px;
}
/* this is for "login as chuck" tip in demo mode */
.tips {
margin-top: 2em;
text-align: center;
}

View file

@ -1,17 +0,0 @@
(function(b){b.widget("ui.tagit",{options:{allowDuplicates:!1,caseSensitive:!0,fieldName:"tags",placeholderText:null,readOnly:!1,removeConfirmation:!1,tagLimit:null,availableTags:[],autocomplete:{},showAutocompleteOnFocus:!1,allowSpaces:!1,singleField:!1,singleFieldDelimiter:",",singleFieldNode:null,animate:!0,tabIndex:null,beforeTagAdded:null,afterTagAdded:null,beforeTagRemoved:null,afterTagRemoved:null,onTagClicked:null,onTagLimitExceeded:null,onTagAdded:null,onTagRemoved:null,tagSource:null},_create:function(){var a=
this;this.element.is("input")?(this.tagList=b("<ul></ul>").insertAfter(this.element),this.options.singleField=!0,this.options.singleFieldNode=this.element,this.element.addClass("tagit-hidden-field")):this.tagList=this.element.find("ul, ol").andSelf().last();this.tagInput=b('<input type="text" />').addClass("ui-widget-content");this.options.readOnly&&this.tagInput.attr("disabled","disabled");this.options.tabIndex&&this.tagInput.attr("tabindex",this.options.tabIndex);this.options.placeholderText&&this.tagInput.attr("placeholder",
this.options.placeholderText);this.options.autocomplete.source||(this.options.autocomplete.source=function(a,e){var d=a.term.toLowerCase(),c=b.grep(this.options.availableTags,function(a){return 0===a.toLowerCase().indexOf(d)});this.options.allowDuplicates||(c=this._subtractArray(c,this.assignedTags()));e(c)});this.options.showAutocompleteOnFocus&&(this.tagInput.focus(function(b,d){a._showAutocomplete()}),"undefined"===typeof this.options.autocomplete.minLength&&(this.options.autocomplete.minLength=
0));b.isFunction(this.options.autocomplete.source)&&(this.options.autocomplete.source=b.proxy(this.options.autocomplete.source,this));b.isFunction(this.options.tagSource)&&(this.options.tagSource=b.proxy(this.options.tagSource,this));this.tagList.addClass("tagit").addClass("ui-widget ui-widget-content ui-corner-all").append(b('<li class="tagit-new"></li>').append(this.tagInput)).click(function(d){var c=b(d.target);c.hasClass("tagit-label")?(c=c.closest(".tagit-choice"),c.hasClass("removed")||a._trigger("onTagClicked",
d,{tag:c,tagLabel:a.tagLabel(c)})):a.tagInput.focus()});var c=!1;if(this.options.singleField)if(this.options.singleFieldNode){var d=b(this.options.singleFieldNode),f=d.val().split(this.options.singleFieldDelimiter);d.val("");b.each(f,function(b,d){a.createTag(d,null,!0);c=!0})}else this.options.singleFieldNode=b('<input type="hidden" style="display:none;" value="" name="'+this.options.fieldName+'" />'),this.tagList.after(this.options.singleFieldNode);c||this.tagList.children("li").each(function(){b(this).hasClass("tagit-new")||
(a.createTag(b(this).text(),b(this).attr("class"),!0),b(this).remove())});this.tagInput.keydown(function(c){if(c.which==b.ui.keyCode.BACKSPACE&&""===a.tagInput.val()){var d=a._lastTag();!a.options.removeConfirmation||d.hasClass("remove")?a.removeTag(d):a.options.removeConfirmation&&d.addClass("remove ui-state-highlight")}else a.options.removeConfirmation&&a._lastTag().removeClass("remove ui-state-highlight");if(c.which===b.ui.keyCode.COMMA&&!1===c.shiftKey||c.which===b.ui.keyCode.ENTER||c.which==
b.ui.keyCode.TAB&&""!==a.tagInput.val()||c.which==b.ui.keyCode.SPACE&&!0!==a.options.allowSpaces&&('"'!=b.trim(a.tagInput.val()).replace(/^s*/,"").charAt(0)||'"'==b.trim(a.tagInput.val()).charAt(0)&&'"'==b.trim(a.tagInput.val()).charAt(b.trim(a.tagInput.val()).length-1)&&0!==b.trim(a.tagInput.val()).length-1))c.which===b.ui.keyCode.ENTER&&""===a.tagInput.val()||c.preventDefault(),a.options.autocomplete.autoFocus&&a.tagInput.data("autocomplete-open")||(a.tagInput.autocomplete("close"),a.createTag(a._cleanedInput()))}).blur(function(b){a.tagInput.data("autocomplete-open")||
a.createTag(a._cleanedInput())});if(this.options.availableTags||this.options.tagSource||this.options.autocomplete.source)d={select:function(b,c){a.createTag(c.item.value);return!1}},b.extend(d,this.options.autocomplete),d.source=this.options.tagSource||d.source,this.tagInput.autocomplete(d).bind("autocompleteopen.tagit",function(b,c){a.tagInput.data("autocomplete-open",!0)}).bind("autocompleteclose.tagit",function(b,c){a.tagInput.data("autocomplete-open",!1)}),this.tagInput.autocomplete("widget").addClass("tagit-autocomplete")},
destroy:function(){b.Widget.prototype.destroy.call(this);this.element.unbind(".tagit");this.tagList.unbind(".tagit");this.tagInput.removeData("autocomplete-open");this.tagList.removeClass("tagit ui-widget ui-widget-content ui-corner-all tagit-hidden-field");this.element.is("input")?(this.element.removeClass("tagit-hidden-field"),this.tagList.remove()):(this.element.children("li").each(function(){b(this).hasClass("tagit-new")?b(this).remove():(b(this).removeClass("tagit-choice ui-widget-content ui-state-default ui-state-highlight ui-corner-all remove tagit-choice-editable tagit-choice-read-only"),
b(this).text(b(this).children(".tagit-label").text()))}),this.singleFieldNode&&this.singleFieldNode.remove());return this},_cleanedInput:function(){return b.trim(this.tagInput.val().replace(/^"(.*)"$/,"$1"))},_lastTag:function(){return this.tagList.find(".tagit-choice:last:not(.removed)")},_tags:function(){return this.tagList.find(".tagit-choice:not(.removed)")},assignedTags:function(){var a=this,c=[];this.options.singleField?(c=b(this.options.singleFieldNode).val().split(this.options.singleFieldDelimiter),
""===c[0]&&(c=[])):this._tags().each(function(){c.push(a.tagLabel(this))});return c},_updateSingleTagsField:function(a){b(this.options.singleFieldNode).val(a.join(this.options.singleFieldDelimiter)).trigger("change")},_subtractArray:function(a,c){for(var d=[],f=0;f<a.length;f++)-1==b.inArray(a[f],c)&&d.push(a[f]);return d},tagLabel:function(a){return this.options.singleField?b(a).find(".tagit-label:first").text():b(a).find("input:first").val()},_showAutocomplete:function(){this.tagInput.autocomplete("search",
"")},_findTagByLabel:function(a){var c=this,d=null;this._tags().each(function(f){if(c._formatStr(a)==c._formatStr(c.tagLabel(this)))return d=b(this),!1});return d},_isNew:function(a){return!this._findTagByLabel(a)},_formatStr:function(a){return this.options.caseSensitive?a:b.trim(a.toLowerCase())},_effectExists:function(a){return Boolean(b.effects&&(b.effects[a]||b.effects.effect&&b.effects.effect[a]))},createTag:function(a,c,d){var f=this;a=b.trim(a);this.options.preprocessTag&&(a=this.options.preprocessTag(a));
if(""===a)return!1;if(!this.options.allowDuplicates&&!this._isNew(a))return a=this._findTagByLabel(a),!1!==this._trigger("onTagExists",null,{existingTag:a,duringInitialization:d})&&this._effectExists("highlight")&&a.effect("highlight"),!1;if(this.options.tagLimit&&this._tags().length>=this.options.tagLimit)return this._trigger("onTagLimitExceeded",null,{duringInitialization:d}),!1;var g=b(this.options.onTagClicked?'<a class="tagit-label"></a>':'<span class="tagit-label"></span>').text(a),e=b("<li></li>").addClass("tagit-choice ui-widget-content ui-state-default ui-corner-all").addClass(c).append(g);
this.options.readOnly?e.addClass("tagit-choice-read-only"):(e.addClass("tagit-choice-editable"),c=b("<span></span>").addClass("ui-icon ui-icon-close"),c=b('<a><span class="text-icon">\u00d7</span></a>').addClass("tagit-close").append(c).click(function(a){f.removeTag(e)}),e.append(c));this.options.singleField||(g=g.html(),e.append('<input type="hidden" value="'+g+'" name="'+this.options.fieldName+'" class="tagit-hidden-field" />'));!1!==this._trigger("beforeTagAdded",null,{tag:e,tagLabel:this.tagLabel(e),
duringInitialization:d})&&(this.options.singleField&&(g=this.assignedTags(),g.push(a),this._updateSingleTagsField(g)),this._trigger("onTagAdded",null,e),this.tagInput.val(""),this.tagInput.parent().before(e),this._trigger("afterTagAdded",null,{tag:e,tagLabel:this.tagLabel(e),duringInitialization:d}),this.options.showAutocompleteOnFocus&&!d&&setTimeout(function(){f._showAutocomplete()},0))},removeTag:function(a,c){c="undefined"===typeof c?this.options.animate:c;a=b(a);this._trigger("onTagRemoved",
null,a);if(!1!==this._trigger("beforeTagRemoved",null,{tag:a,tagLabel:this.tagLabel(a)})){if(this.options.singleField){var d=this.assignedTags(),f=this.tagLabel(a),d=b.grep(d,function(a){return a!=f});this._updateSingleTagsField(d)}if(c){a.addClass("removed");var d=this._effectExists("blind")?["blind",{direction:"horizontal"},"fast"]:["fast"],g=this;d.push(function(){a.remove();g._trigger("afterTagRemoved",null,{tag:a,tagLabel:g.tagLabel(a)})});a.fadeOut("fast").hide.apply(a,d).dequeue()}else a.remove(),
this._trigger("afterTagRemoved",null,{tag:a,tagLabel:this.tagLabel(a)})}},removeTagByLabel:function(a,b){var d=this._findTagByLabel(a);if(!d)throw"No such tag exists with the name '"+a+"'";this.removeTag(d,b)},removeAll:function(){var a=this;this._tags().each(function(b,d){a.removeTag(d,!1)})}})})(jQuery);

View file

@ -1,32 +0,0 @@
$(function() {
$('input[name="username"]').keydown(function(event) {
if (event.which == 13) {
$('input[name="password"]').focus().select();
return false;
}
return true;
});
$('form').submit(function() {
if (! $('input[name="username"]').val()) {
with ($('input[name="username"]').get(0)) {
select();
focus();
}
return false;
}
if (! $('input[name="password"]').val()) {
with ($('input[name="password"]').get(0)) {
select();
focus();
}
return false;
}
return true;
});
$('input[name="username"]').focus();
});

View file

@ -1,29 +0,0 @@
/************************************************************
*
* tailbone.appsettings.js
*
* Logic for App Settings page.
*
************************************************************/
function show_group(group) {
if (group == "(All)") {
$('.panel').show();
} else {
$('.panel').hide();
$('.panel[data-groupname="' + group + '"]').show();
}
}
$(function() {
$('#settings-group').on('selectmenuchange', function(event, ui) {
show_group(ui.item.value);
});
show_group($('#settings-group').val());
});

View file

@ -1,41 +0,0 @@
/************************************************************
*
* tailbone.batch.js
*
* Common logic for view/edit batch pages
*
************************************************************/
$(function() {
$('#execute-batch').click(function() {
if (has_execution_options) {
$('#execution-options-dialog').dialog({
title: "Execution Options",
width: 600,
modal: true,
buttons: [
{
text: "Execute",
click: function(event) {
dialog_button(event).button('option', 'label', "Executing, please wait...").button('disable');
$('form[name="batch-execution"]').submit();
}
},
{
text: "Cancel",
click: function() {
$(this).dialog('close');
}
}
]
});
} else {
$(this).button('option', 'label', "Executing, please wait...").button('disable');
$('form[name="batch-execution"]').submit();
}
});
});

View file

@ -24,8 +24,6 @@
Event Subscribers
"""
from __future__ import unicode_literals, absolute_import
import six
import json
import datetime
@ -42,7 +40,7 @@ from tailbone import helpers
from tailbone.db import Session
from tailbone.config import csrf_header_name, should_expose_websockets
from tailbone.menus import make_simple_menus
from tailbone.util import should_use_buefy, get_global_search_options
from tailbone.util import get_global_search_options
def new_request(event):
@ -156,23 +154,20 @@ def before_render(event):
renderer_globals['background_color'] = request.rattail_config.get(
'tailbone', 'background_color')
# buefy themes get some extra treatment
if should_use_buefy(request):
# TODO: remove this hack once nothing references it
renderer_globals['buefy_0_8'] = False
# TODO: remove this hack once nothing references it
renderer_globals['buefy_0_8'] = False
# maybe set custom stylesheet
css = None
if request.user:
css = request.rattail_config.get('tailbone.{}'.format(request.user.uuid),
'buefy_css')
if not css:
css = request.rattail_config.get('tailbone', 'theme.falafel.buefy_css')
renderer_globals['buefy_css'] = css
# maybe set custom stylesheet
css = None
if request.user:
css = request.rattail_config.get('tailbone.{}'.format(request.user.uuid),
'buefy_css')
if not css:
css = request.rattail_config.get('tailbone', 'theme.falafel.buefy_css')
renderer_globals['buefy_css'] = css
# add global search data for quick access
renderer_globals['global_search_data'] = get_global_search_options(request)
# add global search data for quick access
renderer_globals['global_search_data'] = get_global_search_options(request)
# here we globally declare widths for grid filter pseudo-columns
widths = request.rattail_config.get('tailbone', 'grids.filters.column_widths')

View file

@ -5,34 +5,6 @@
<%def name="content_title()"></%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.appsettings.js') + '?ver={}'.format(tailbone.__version__))}
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if not use_buefy:
<style type="text/css">
div.form {
float: none;
}
div.panel {
width: 85%;
}
.field-wrapper {
margin-bottom: 2em;
}
.panel .field-wrapper label {
font-family: monospace;
width: 50em;
}
</style>
% endif
</%def>
<%def name="context_menu_items()">
% if request.has_perm('settings.list'):
<li>${h.link_to("View Raw Settings", url('settings'))}</li>
@ -223,76 +195,4 @@
</%def>
% if use_buefy:
${parent.body()}
% else:
## legacy / not buefy
<div class="form">
${h.form(form.action_url, id=dform.formid, method='post', class_='autodisable')}
${h.csrf_token(request)}
% if dform.error:
<div class="error-messages">
<div class="ui-state-error ui-corner-all">
<span style="float: left; margin-right: .3em;" class="ui-icon ui-icon-alert"></span>
Please see errors below.
</div>
<div class="ui-state-error ui-corner-all">
<span style="float: left; margin-right: .3em;" class="ui-icon ui-icon-alert"></span>
${dform.error}
</div>
</div>
% endif
<div class="group-picker">
<div class="field-wrapper">
<label for="settings-group">Showing Group</label>
<div class="field select">
${h.select('settings-group', current_group, group_options, **{'auto-enhance': 'true'})}
</div>
</div>
</div>
% for group in groups:
<div class="panel" data-groupname="${group}">
<h2>${group}</h2>
<div class="panel-body">
% for setting in settings:
% if setting.group == group:
<% field = dform[setting.node_name] %>
<div class="field-wrapper ${field.name} ${'with-error' if field.error else ''}">
% if field.error:
<div class="field-error">
% for msg in field.error.messages():
<span class="error-msg">${msg}</span>
% endfor
</div>
% endif
<div class="field-row">
<label for="${field.oid}">${form.get_label(field.name)}</label>
<div class="field">
${field.serialize()|n}
</div>
</div>
% if form.has_helptext(field.name):
<span class="instructions">${form.render_helptext(field.name)}</span>
% endif
</div>
% endif
% endfor
</div><!-- panel-body -->
</div><! -- panel -->
% endfor
<div class="buttons">
${h.submit('save', getattr(form, 'submit_label', getattr(form, 'save_label', "Submit")), class_='button is-primary')}
${h.link_to("Cancel", form.cancel_url, class_='cancel button{}'.format(' autodisable' if form.auto_disable_cancel else ''))}
</div>
${h.end_form()}
</div>
% endif
${parent.body()}

View file

@ -76,12 +76,5 @@
</div>
</%def>
<%def name="render_form()">
${parent.render_form()}
% if not use_buefy:
${self.field_diff_table()}
% endif
</%def>
${parent.body()}

View file

@ -1,150 +1,66 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/index.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
% if master.results_executable and master.has_perm('execute_multiple'):
<script type="text/javascript">
var has_execution_options = ${'true' if master.has_execution_options(batch) else 'false'};
var dialog_opened = false;
$(function() {
$('#refresh-results-button').click(function() {
var count = $('.grid-wrapper').gridwrapper('results_count');
if (!count) {
alert("There are no batch results to refresh.");
return;
}
var form = $('form[name="refresh-results"]');
$(this).button('option', 'label', "Refreshing, please wait...").button('disable');
form.submit();
});
$('#execute-results-button').click(function() {
var count = $('.grid-wrapper').gridwrapper('results_count');
if (!count) {
alert("There are no batch results to execute.");
return;
}
var form = $('form[name="execute-results"]');
if (has_execution_options) {
$('#execution-options-dialog').dialog({
title: "Execution Options",
width: 550,
height: 300,
modal: true,
buttons: [
{
text: "Execute",
click: function(event) {
dialog_button(event).button('option', 'label', "Executing, please wait...").button('disable');
form.submit();
}
},
{
text: "Cancel",
click: function() {
$(this).dialog('close');
}
}
],
open: function() {
if (! dialog_opened) {
$('#execution-options-dialog select[auto-enhance="true"]').selectmenu();
$('#execution-options-dialog select[auto-enhance="true"]').on('selectmenuopen', function(event, ui) {
show_all_options($(this));
});
dialog_opened = true;
}
}
});
} else {
$(this).button('option', 'label', "Executing, please wait...").button('disable');
form.submit();
}
});
});
</script>
% endif
% endif
</%def>
<%def name="grid_tools()">
${parent.grid_tools()}
## Refresh Results
% if master.results_refreshable and master.has_perm('refresh'):
% if use_buefy:
<b-button type="is-primary"
:disabled="refreshResultsButtonDisabled"
icon-pack="fas"
icon-left="fas fa-redo"
@click="refreshResults()">
{{ refreshResultsButtonText }}
</b-button>
${h.form(url('{}.refresh_results'.format(route_prefix)), ref='refreshResultsForm')}
${h.csrf_token(request)}
${h.end_form()}
% else:
<button type="button" id="refresh-results-button">
Refresh Results
</button>
% endif
<b-button type="is-primary"
:disabled="refreshResultsButtonDisabled"
icon-pack="fas"
icon-left="fas fa-redo"
@click="refreshResults()">
{{ refreshResultsButtonText }}
</b-button>
${h.form(url('{}.refresh_results'.format(route_prefix)), ref='refreshResultsForm')}
${h.csrf_token(request)}
${h.end_form()}
% endif
## Execute Results
% if master.results_executable and master.has_perm('execute_multiple'):
% if use_buefy:
<b-button type="is-primary"
@click="executeResults()"
icon-pack="fas"
icon-left="arrow-circle-right"
:disabled="!total">
Execute Results
</b-button>
<b-button type="is-primary"
@click="executeResults()"
icon-pack="fas"
icon-left="arrow-circle-right"
:disabled="!total">
Execute Results
</b-button>
<b-modal has-modal-card
:active.sync="showExecutionOptions">
<div class="modal-card">
<b-modal has-modal-card
:active.sync="showExecutionOptions">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Execution Options</p>
</header>
<section class="modal-card-body">
<p>
Please be advised, you are about to execute {{ total }} batches!
</p>
<br />
<div class="form-wrapper">
<div class="form">
<${execute_form.component} ref="executeResultsForm"></${execute_form.component}>
</div>
</div>
</section>
<footer class="modal-card-foot">
<b-button @click="showExecutionOptions = false">
Cancel
</b-button>
<once-button type="is-primary"
@click="submitExecuteResults()"
icon-left="arrow-circle-right"
:text="'Execute ' + total + ' Batches'">
</once-button>
</footer>
<header class="modal-card-head">
<p class="modal-card-title">Execution Options</p>
</header>
<section class="modal-card-body">
<p>
Please be advised, you are about to execute {{ total }} batches!
</p>
<br />
<div class="form-wrapper">
<div class="form">
<${execute_form.component} ref="executeResultsForm"></${execute_form.component}>
</div>
</div>
</b-modal>
</section>
% else:
<button type="button" id="execute-results-button">Execute Results</button>
% endif
<footer class="modal-card-foot">
<b-button @click="showExecutionOptions = false">
Cancel
</b-button>
<once-button type="is-primary"
@click="submitExecuteResults()"
icon-left="arrow-circle-right"
:text="'Execute ' + total + ' Batches'">
</once-button>
</footer>
</div>
</b-modal>
% endif
</%def>
@ -224,24 +140,3 @@
${parent.body()}
% if not use_buefy:
## Refresh Results
% if master.results_refreshable and master.has_perm('refresh'):
${h.form(url('{}.refresh_results'.format(route_prefix)), name='refresh-results')}
${h.csrf_token(request)}
${h.end_form()}
% endif
% if master.results_executable and master.has_perm('execute_multiple'):
<div id="execution-options-dialog" style="display: none;">
<br />
<p>
Please be advised, you are about to execute multiple batches!
</p>
<br />
${execute_form.render_deform(form_kwargs={'name': 'execute-results'}, buttons=False)|n}
</div>
% endif
% endif

View file

@ -3,298 +3,67 @@
<%def name="title()">Inventory Form</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
${h.javascript_link(request.static_url('tailbone:static/js/numeric.js'))}
<script type="text/javascript">
function assert_quantity() {
% if allow_cases:
var cases = parseFloat($('#cases').val());
if (!isNaN(cases)) {
if (cases > 999999) {
alert("Case amount is invalid!");
$('#cases').select().focus();
return false;
}
return true;
}
% endif
var units = parseFloat($('#units').val());
if (!isNaN(units)) {
if (units > 999999) {
alert("Unit amount is invalid!");
$('#units').select().focus();
return false;
}
return true;
}
alert("Please provide case and/or unit quantity");
% if allow_cases:
$('#cases').select().focus();
% else:
$('#units').select().focus();
% endif
return false;
}
function invalid_product(msg) {
$('#product-info p').text(msg);
$('#product-info img').hide();
$('#upc').focus().select();
% if allow_cases:
$('.field-wrapper.cases input').prop('disabled', true);
% endif
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
}
function pretty_quantity(cases, units) {
if (cases && units) {
return cases + " cases, " + units + " units";
} else if (cases) {
return cases + " cases";
} else if (units) {
return units + " units";
}
return '';
}
function show_quantity(name, cases, units) {
var quantity = pretty_quantity(cases, units);
var field = $('.field-wrapper.quantity_' + name);
field.find('.field').text(quantity);
if (quantity || name == 'ordered') {
field.show();
} else {
field.hide();
}
}
$(function() {
$('#upc').keydown(function(event) {
if (key_allowed(event)) {
return true;
}
if (key_modifies(event)) {
$('#product').val('');
$('#product-info p').html("please ENTER a scancode");
$('#product-info img').hide();
$('#product-info .warning').hide();
$('.product-fields').hide();
// $('.receiving-fields').hide();
% if allow_cases:
$('.field-wrapper.cases input').prop('disabled', true);
% endif
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
return true;
}
// when user presses ENTER, do product lookup
if (event.which == 13) {
var upc = $(this).val();
var data = {'upc': upc};
$.get('${url('batch.inventory.desktop_lookup', uuid=batch.uuid)}', data, function(data) {
if (data.error) {
alert(data.error);
if (data.redirect) {
$('#inventory-form').mask("Redirecting...");
location.href = data.redirect;
}
} else if (data.product) {
$('#upc').val(data.product.upc_pretty);
$('#product').val(data.product.uuid);
$('#brand_name').val(data.product.brand_name);
$('#description').val(data.product.description);
$('#size').val(data.product.size);
$('#case_quantity').val(data.product.case_quantity);
if (data.force_unit_item) {
$('#product-info .warning.force-unit').show();
}
if (data.already_present_in_batch) {
$('#product-info .warning.present').show();
$('#cases').val(data.cases);
$('#units').val(data.units);
} else if (data.product.type2) {
$('#units').val(data.product.units);
}
$('#product-info p').text(data.product.full_description);
$('#product-info img').attr('src', data.product.image_url).show();
if (! data.product.uuid) {
// $('#product-info .warning.notfound').show();
$('.product-fields').show();
}
$('#product-info .warning.notordered').show();
% if allow_cases:
$('.field-wrapper.cases input').prop('disabled', false);
% endif
$('.field-wrapper.units input').prop('disabled', false);
$('.buttons button').button('enable');
if (data.product.type2) {
$('#units').focus().select();
} else {
% if allow_cases and prefer_cases:
if ($('#cases').val()) {
$('#cases').focus().select();
} else if ($('#units').val()) {
$('#units').focus().select();
} else {
$('#cases').focus().select();
}
% else:
$('#units').focus().select();
% endif
}
// TODO: this is maybe useful if "new products" may be added via inventory batch
// } else if (data.upc) {
// $('#upc').val(data.upc_pretty);
// $('#product-info p').text("product not found in our system");
// $('#product-info img').attr('src', data.image_url).show();
// $('#product').val('');
// $('#brand_name').val('');
// $('#description').val('');
// $('#size').val('');
// $('#case_quantity').val('');
// $('#product-info .warning.notfound').show();
// $('.product-fields').show();
// $('#brand_name').focus();
// $('.field-wrapper.cases input').prop('disabled', false);
// $('.field-wrapper.units input').prop('disabled', false);
// $('.buttons button').button('enable');
} else {
invalid_product('product not found');
}
});
}
return false;
});
$('#inventory-form').submit(function() {
if (! assert_quantity()) {
return false;
}
disable_submit_button(this);
$(this).mask("Working...");
});
$('#upc').focus();
% if allow_cases:
$('.field-wrapper.cases input').prop('disabled', true);
% endif
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if not use_buefy:
<style type="text/css">
#product-info {
margin-top: 0.5em;
text-align: center;
}
#product-info p {
margin-left: 0.5em;
}
#product-info .img-wrapper {
height: 150px;
margin: 0.5em 0;
}
#product-info .warning {
background: #f66;
display: none;
}
</style>
% endif
</%def>
<%def name="context_menu_items()">
${parent.context_menu_items()}
<li>${h.link_to("Back to Inventory Batch", url('batch.inventory.view', uuid=batch.uuid))}</li>
</%def>
<%def name="render_form()">
% if use_buefy:
<script type="text/x-template" id="${form.component}-template">
<div class="product-info">
<script type="text/x-template" id="${form.component}-template">
<div class="product-info">
${h.form(form.action_url, **{'@submit': 'handleSubmit'})}
${h.csrf_token(request)}
${h.form(form.action_url, **{'@submit': 'handleSubmit'})}
${h.csrf_token(request)}
${h.hidden('product', **{':value': 'productInfo.uuid'})}
${h.hidden('upc', **{':value': 'productInfo.upc'})}
${h.hidden('brand_name', **{':value': 'productInfo.brand_name'})}
${h.hidden('description', **{':value': 'productInfo.description'})}
${h.hidden('size', **{':value': 'productInfo.size'})}
${h.hidden('case_quantity', **{':value': 'productInfo.case_quantity'})}
${h.hidden('product', **{':value': 'productInfo.uuid'})}
${h.hidden('upc', **{':value': 'productInfo.upc'})}
${h.hidden('brand_name', **{':value': 'productInfo.brand_name'})}
${h.hidden('description', **{':value': 'productInfo.description'})}
${h.hidden('size', **{':value': 'productInfo.size'})}
${h.hidden('case_quantity', **{':value': 'productInfo.case_quantity'})}
<b-field label="Product UPC" horizontal>
<div style="display: flex; flex-direction: column;">
<b-input v-model="productUPC"
ref="productUPC"
@input="productChanged"
@keydown.native="productKeydown">
</b-input>
<div class="has-text-centered block">
<b-field label="Product UPC" horizontal>
<div style="display: flex; flex-direction: column;">
<b-input v-model="productUPC"
ref="productUPC"
@input="productChanged"
@keydown.native="productKeydown">
</b-input>
<div class="has-text-centered block">
<p v-if="!productInfo.uuid"
class="block">
please ENTER a scancode
</p>
<p v-if="!productInfo.uuid"
class="block">
please ENTER a scancode
</p>
<p v-if="productInfo.uuid"
class="block">
{{ productInfo.full_description }}
</p>
<p v-if="productInfo.uuid"
class="block">
{{ productInfo.full_description }}
</p>
<div style="min-height: 150px; margin: 0.5rem 0;">
<img v-if="productInfo.uuid"
:src="productInfo.image_url" />
</div>
<div style="min-height: 150px; margin: 0.5rem 0;">
<img v-if="productInfo.uuid"
:src="productInfo.image_url" />
</div>
<div v-if="alreadyPresentInBatch"
class="has-background-danger">
product already exists in batch, please confirm count
</div>
<div v-if="alreadyPresentInBatch"
class="has-background-danger">
product already exists in batch, please confirm count
</div>
<div v-if="forceUnitItem"
class="has-background-danger">
pack item scanned, but must count units instead
</div>
<div v-if="forceUnitItem"
class="has-background-danger">
pack item scanned, but must count units instead
</div>
## <div v-if="productNotFound"
## class="has-background-danger">
## please confirm UPC and provide more details
## </div>
</div>
</div>
</b-field>
</div>
</div>
</b-field>
## <div v-if="productNotFound"
## ## class="product-fields"
@ -322,243 +91,176 @@
##
## </div>
% if allow_cases:
<b-field label="Cases" horizontal>
<b-input name="cases"
v-model="productCases"
ref="productCases"
:disabled="!productInfo.uuid">
</b-input>
</b-field>
% endif
<b-field label="Units" horizontal>
<b-input name="units"
v-model="productUnits"
ref="productUnits"
% if allow_cases:
<b-field label="Cases" horizontal>
<b-input name="cases"
v-model="productCases"
ref="productCases"
:disabled="!productInfo.uuid">
</b-input>
</b-field>
% endif
<b-button type="is-primary"
native-type="submit"
:disabled="submitting">
{{ submitting ? "Working, please wait..." : "Submit" }}
</b-button>
<b-field label="Units" horizontal>
<b-input name="units"
v-model="productUnits"
ref="productUnits"
:disabled="!productInfo.uuid">
</b-input>
</b-field>
${h.end_form()}
</div>
</script>
<b-button type="is-primary"
native-type="submit"
:disabled="submitting">
{{ submitting ? "Working, please wait..." : "Submit" }}
</b-button>
<script type="text/javascript">
${h.end_form()}
</div>
</script>
let ${form.component_studly} = {
template: '#${form.component}-template',
<script type="text/javascript">
mounted() {
this.$refs.productUPC.focus()
let ${form.component_studly} = {
template: '#${form.component}-template',
mounted() {
this.$refs.productUPC.focus()
},
methods: {
clearProduct() {
this.productInfo = {}
## this.productNotFound = false
this.alreadyPresentInBatch = false
this.forceUnitItem = false
this.productCases = null
this.productUnits = null
},
methods: {
assertQuantity() {
clearProduct() {
this.productInfo = {}
## this.productNotFound = false
this.alreadyPresentInBatch = false
this.forceUnitItem = false
this.productCases = null
this.productUnits = null
},
assertQuantity() {
% if allow_cases:
let cases = parseFloat(this.productCases)
if (!isNaN(cases)) {
if (cases > 999999) {
alert("Case amount is invalid!")
this.$refs.productCases.focus()
return false
}
return true
}
% endif
let units = parseFloat(this.productUnits)
if (!isNaN(units)) {
if (units > 999999) {
alert("Unit amount is invalid!")
this.$refs.productUnits.focus()
% if allow_cases:
let cases = parseFloat(this.productCases)
if (!isNaN(cases)) {
if (cases > 999999) {
alert("Case amount is invalid!")
this.$refs.productCases.focus()
return false
}
return true
}
% endif
alert("Please provide case and/or unit quantity")
% if allow_cases:
this.$refs.productCases.focus()
% else:
let units = parseFloat(this.productUnits)
if (!isNaN(units)) {
if (units > 999999) {
alert("Unit amount is invalid!")
this.$refs.productUnits.focus()
% endif
},
handleSubmit(event) {
if (!this.assertQuantity()) {
event.preventDefault()
return
return false
}
this.submitting = true
},
return true
}
productChanged() {
this.clearProduct()
},
productKeydown(event) {
if (event.which == 13) { // ENTER
this.productLookup()
event.preventDefault()
}
},
productLookup() {
let url = '${url('batch.inventory.desktop_lookup', uuid=batch.uuid)}'
let params = {
upc: this.productUPC,
}
this.$http.get(url, {params: params}).then(response => {
if (response.data.error) {
alert(response.data.error)
if (response.data.redirect) {
location.href = response.data.redirect
}
} else if (response.data.product.uuid) {
this.productUPC = response.data.product.upc_pretty
this.productInfo = response.data.product
this.forceUnitItem = response.data.force_unit_item
this.alreadyPresentInBatch = response.data.already_present_in_batch
if (this.alreadyPresentInBatch) {
this.productCases = response.data.cases
this.productUnits = response.data.units
} else if (this.productInfo.type2) {
this.productUnits = this.productInfo.units
}
this.$nextTick(() => {
if (this.productInfo.type2) {
this.$refs.productUnits.focus()
} else {
% if allow_cases and prefer_cases:
if (this.productCases) {
this.$refs.productCases.focus()
} else if (this.productUnits) {
this.$refs.productUnits.focus()
} else {
this.$refs.productCases.focus()
}
% else:
this.$refs.productUnits.focus()
% endif
}
})
} else {
## this.productNotFound = true
alert("Product not found!")
}
})
},
alert("Please provide case and/or unit quantity")
% if allow_cases:
this.$refs.productCases.focus()
% else:
this.$refs.productUnits.focus()
% endif
},
}
let ${form.component_studly}Data = {
submitting: false,
handleSubmit(event) {
if (!this.assertQuantity()) {
event.preventDefault()
return
}
this.submitting = true
},
productUPC: null,
## productNotFound: false,
productInfo: {},
productChanged() {
this.clearProduct()
},
% if allow_cases:
productCases: null,
% endif
productUnits: null,
productKeydown(event) {
if (event.which == 13) { // ENTER
this.productLookup()
event.preventDefault()
}
},
alreadyPresentInBatch: false,
forceUnitItem: false,
}
productLookup() {
let url = '${url('batch.inventory.desktop_lookup', uuid=batch.uuid)}'
let params = {
upc: this.productUPC,
}
this.$http.get(url, {params: params}).then(response => {
</script>
if (response.data.error) {
alert(response.data.error)
if (response.data.redirect) {
location.href = response.data.redirect
}
% else:
## not buefy
} else if (response.data.product.uuid) {
<div class="form-wrapper">
${h.form(form.action_url, id='inventory-form')}
${h.csrf_token(request)}
this.productUPC = response.data.product.upc_pretty
this.productInfo = response.data.product
this.forceUnitItem = response.data.force_unit_item
this.alreadyPresentInBatch = response.data.already_present_in_batch
<div class="field-wrapper">
<label for="upc">Product UPC</label>
<div class="field">
${h.hidden('product')}
<div>${h.text('upc', autocomplete='off')}</div>
<div id="product-info">
<p>please ENTER a scancode</p>
<div class="img-wrapper"><img /></div>
<div class="warning notfound">please confirm UPC and provide more details</div>
<div class="warning present">product already exists in batch, please confirm count</div>
<div class="warning force-unit">pack item scanned, but must count units instead</div>
</div>
</div>
</div>
if (this.alreadyPresentInBatch) {
this.productCases = response.data.cases
this.productUnits = response.data.units
} else if (this.productInfo.type2) {
this.productUnits = this.productInfo.units
}
<div class="product-fields" style="display: none;">
this.$nextTick(() => {
if (this.productInfo.type2) {
this.$refs.productUnits.focus()
} else {
% if allow_cases and prefer_cases:
if (this.productCases) {
this.$refs.productCases.focus()
} else if (this.productUnits) {
this.$refs.productUnits.focus()
} else {
this.$refs.productCases.focus()
}
% else:
this.$refs.productUnits.focus()
% endif
}
})
<div class="field-wrapper brand_name">
<label for="brand_name">Brand Name</label>
<div class="field">${h.text('brand_name')}</div>
</div>
} else {
## this.productNotFound = true
alert("Product not found!")
}
})
},
},
}
<div class="field-wrapper description">
<label for="description">Description</label>
<div class="field">${h.text('description')}</div>
</div>
let ${form.component_studly}Data = {
submitting: false,
<div class="field-wrapper size">
<label for="size">Size</label>
<div class="field">${h.text('size')}</div>
</div>
<div class="field-wrapper case_quantity">
<label for="case_quantity">Units in Case</label>
<div class="field">${h.text('case_quantity')}</div>
</div>
</div>
productUPC: null,
## productNotFound: false,
productInfo: {},
% if allow_cases:
<div class="field-wrapper cases">
<label for="cases">Cases</label>
<div class="field">${h.text('cases', autocomplete='off')}</div>
</div>
productCases: null,
% endif
productUnits: null,
<div class="field-wrapper units">
<label for="units">Units</label>
<div class="field">${h.text('units', autocomplete='off')}</div>
</div>
alreadyPresentInBatch: false,
forceUnitItem: false,
}
<div class="buttons">
${h.submit('submit', "Submit")}
</div>
${h.end_form()}
</div>
% endif
</script>
</%def>

View file

@ -1,59 +1,6 @@
## -*- coding: utf-8; -*-
<%inherit file="/batch/create.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
var vendormap = {
% for i, parser in enumerate(parsers, 1):
'${parser.key}': ${parser.vendormap_value|n}${',' if i < len(parsers) else ''}
% endfor
};
$(function() {
if ($('select[name="parser_key"] option:first').is(':selected')) {
$('.vendor_uuid .autocomplete-container').hide();
} else {
$('.vendor_uuid input[name="vendor_uuid"]').val('');
$('.vendor_uuid .autocomplete-display').hide();
$('.vendor_uuid .autocomplete-display button').show();
$('.vendor_uuid .autocomplete-textbox').val('');
$('.vendor_uuid .autocomplete-textbox').show();
$('.vendor_uuid .autocomplete-container').show();
}
$('select[name="parser_key"]').on('selectmenuchange', function() {
if ($(this).find('option:first').is(':selected')) {
$('.vendor_uuid .autocomplete-container').hide();
} else {
var vendor = vendormap[$(this).val()];
if (vendor) {
$('.vendor_uuid input[name="vendor_uuid"]').val(vendor.uuid);
$('.vendor_uuid .autocomplete-textbox').hide();
$('.vendor_uuid .autocomplete-display span:first').text(vendor.name);
$('.vendor_uuid .autocomplete-display button').hide();
$('.vendor_uuid .autocomplete-display').show();
$('.vendor_uuid .autocomplete-container').show();
} else {
$('.vendor_uuid input[name="vendor_uuid"]').val('');
$('.vendor_uuid .autocomplete-display').hide();
$('.vendor_uuid .autocomplete-display button').show();
$('.vendor_uuid .autocomplete-textbox').val('');
$('.vendor_uuid .autocomplete-textbox').show();
$('.vendor_uuid .autocomplete-container').show();
$('.vendor_uuid .autocomplete-textbox').focus();
}
}
});
});
</script>
% endif
</%def>
<%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()}
<script type="text/javascript">

View file

@ -1,68 +1,8 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.batch.js') + '?ver={}'.format(tailbone.__version__))}
<script type="text/javascript">
var has_execution_options = ${'true' if master.has_execution_options(batch) else 'false'};
$(function() {
% if master.has_worksheet and master.allow_worksheet(batch) and master.has_perm('worksheet'):
$('.load-worksheet').click(function() {
disable_button(this);
location.href = '${url('{}.worksheet'.format(route_prefix), uuid=batch.uuid)}';
});
% endif
% if master.batch_refreshable(batch) and master.has_perm('refresh'):
$('#refresh-data').click(function() {
$(this)
.button('option', 'disabled', true)
.button('option', 'label', "Working, please wait...");
location.href = '${url('{}.refresh'.format(route_prefix), uuid=batch.uuid)}';
});
% endif
% if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'):
$('.upload-worksheet').click(function() {
$('#upload-worksheet-dialog').dialog({
title: "Upload Worksheet",
width: 600,
modal: true,
buttons: [
{
text: "Upload & Update Batch",
click: function(event) {
var form = $('form[name="upload-worksheet"]');
var field = form.find('input[type="file"]').get(0);
if (!field.value) {
alert("Please choose a file to upload.");
return
}
disable_button(dialog_button(event));
form.submit();
}
},
{
text: "Cancel",
click: function() {
$(this).dialog('close');
}
}
]
});
});
% endif
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if use_buefy:
<style type="text/css">
.modal-card-body label {
@ -74,19 +14,6 @@
}
</style>
% else:
<style type="text/css">
.grid-wrapper {
margin-top: 10px;
}
.complete form {
display: inline;
}
</style>
% endif
</%def>
<%def name="buttons()">
@ -99,52 +26,39 @@
<%def name="leading_buttons()">
% if master.has_worksheet and master.allow_worksheet(batch) and master.has_perm('worksheet'):
% if use_buefy:
<once-button type="is-primary"
tag="a" href="${url('{}.worksheet'.format(route_prefix), uuid=batch.uuid)}"
icon-left="edit"
text="Edit as Worksheet">
</once-button>
% else:
<button type="button" class="load-worksheet">Edit as Worksheet</button>
% endif
<once-button type="is-primary"
tag="a" href="${url('{}.worksheet'.format(route_prefix), uuid=batch.uuid)}"
icon-left="edit"
text="Edit as Worksheet">
</once-button>
% endif
</%def>
<%def name="refresh_button()">
% if master.batch_refreshable(batch) and master.has_perm('refresh'):
% if use_buefy:
## TODO: this should surely use a POST request?
<once-button type="is-primary"
tag="a" href="${url('{}.refresh'.format(route_prefix), uuid=batch.uuid)}"
text="Refresh Data"
icon-left="redo">
</once-button>
% else:
<button type="button" class="button" id="refresh-data">Refresh Data</button>
% endif
## TODO: this should surely use a POST request?
<once-button type="is-primary"
tag="a" href="${url('{}.refresh'.format(route_prefix), uuid=batch.uuid)}"
text="Refresh Data"
icon-left="redo">
</once-button>
% endif
</%def>
<%def name="trailing_buttons()">
% if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'):
% if use_buefy:
<b-button tag="a"
href="${master.get_action_url('download_worksheet', batch)}"
icon-pack="fas"
icon-left="fas fa-download">
Download Worksheet
</b-button>
<b-button type="is-primary"
icon-pack="fas"
icon-left="fas fa-upload"
@click="$emit('show-upload')">
Upload Worksheet
</b-button>
% else:
${h.link_to("Download Worksheet", master.get_action_url('download_worksheet', batch), class_='button')}
<button type="button" class="upload-worksheet">Upload Worksheet</button>
% endif
<b-button tag="a"
href="${master.get_action_url('download_worksheet', batch)}"
icon-pack="fas"
icon-left="fas fa-download">
Download Worksheet
</b-button>
<b-button type="is-primary"
icon-pack="fas"
icon-left="fas fa-upload"
@click="$emit('show-upload')">
Upload Worksheet
</b-button>
% endif
</%def>
@ -154,34 +68,12 @@
</%def>
<%def name="render_status_breakdown()">
% if use_buefy:
<div class="object-helper">
<h3>Row Status Breakdown</h3>
<div class="object-helper-content">
${status_breakdown_grid}
</div>
</div>
% elif status_breakdown is not Undefined and status_breakdown is not None:
<div class="object-helper">
<h3>Row Status Breakdown</h3>
<div class="object-helper-content">
% if status_breakdown:
<div class="grid full">
<table>
% for i, (status, count) in enumerate(status_breakdown):
<tr class="${'even' if i % 2 == 0 else 'odd'}">
<td>${status}</td>
<td>${count}</td>
</tr>
% endfor
</table>
</div>
% else:
<p>Nothing to report yet.</p>
% endif
</div>
</div>
% endif
<div class="object-helper">
<h3>Row Status Breakdown</h3>
<div class="object-helper-content">
${status_breakdown_grid}
</div>
</div>
</%def>
<%def name="render_execute_helper()">
@ -197,22 +89,21 @@
% elif master.handler.executable(batch):
% if master.has_perm('execute'):
<p>Batch has not yet been executed.</p>
% if use_buefy:
<br />
<b-button type="is-primary"
% if not execute_enabled:
disabled
% if why_not_execute:
title="${why_not_execute}"
% endif
% endif
@click="showExecutionDialog = true"
icon-pack="fas"
icon-left="arrow-circle-right">
${execute_title}
</b-button>
<br />
<b-button type="is-primary"
% if not execute_enabled:
disabled
% if why_not_execute:
title="${why_not_execute}"
% endif
% endif
@click="showExecutionDialog = true"
icon-pack="fas"
icon-left="arrow-circle-right">
${execute_title}
</b-button>
% if execute_enabled:
% if execute_enabled:
<b-modal has-modal-card
:active.sync="showExecutionDialog">
<div class="modal-card">
@ -245,22 +136,8 @@
</div>
</b-modal>
% endif
% else:
## no buefy, do legacy thing
<button type="button"
% if not execute_enabled:
disabled="disabled"
% endif
% if why_not_execute:
title="${why_not_execute}"
% endif
class="button is-primary"
id="execute-batch">
${execute_title}
</button>
% endif
% else:
<p>TODO: batch *may* be executed, but not by *you*</p>
% endif
@ -281,71 +158,51 @@
${parent.render_this_page()}
% if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'):
% if use_buefy:
<b-modal has-modal-card
:active.sync="showUploadDialog">
<div class="modal-card">
<b-modal has-modal-card
:active.sync="showUploadDialog">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Upload Worksheet</p>
</header>
<header class="modal-card-head">
<p class="modal-card-title">Upload Worksheet</p>
</header>
<section class="modal-card-body">
<p>
This will <span class="has-text-weight-bold">update</span>
the batch data with the worksheet file you provide.&nbsp;
Please be certain to use the right one!
</p>
<br />
<${upload_worksheet_form.component} ref="uploadForm">
</${upload_worksheet_form.component}>
</section>
<footer class="modal-card-foot">
<b-button @click="showUploadDialog = false">
Cancel
</b-button>
<b-button type="is-primary"
@click="submitUpload()"
icon-pack="fas"
icon-left="fas fa-upload"
:disabled="uploadButtonDisabled">
{{ uploadButtonText }}
</b-button>
</footer>
</div>
</b-modal>
% else:
<div id="upload-worksheet-dialog" style="display: none;">
<section class="modal-card-body">
<p>
This will <strong>update</strong> the batch data with the worksheet
file you provide.&nbsp; Please be certain to use the right one!
This will <span class="has-text-weight-bold">update</span>
the batch data with the worksheet file you provide.&nbsp;
Please be certain to use the right one!
</p>
${upload_worksheet_form.render_deform(buttons=False, form_kwargs={'name': 'upload-worksheet'})|n}
</div>
% endif
% endif
<br />
<${upload_worksheet_form.component} ref="uploadForm">
</${upload_worksheet_form.component}>
</section>
% if not use_buefy:
% if master.handler.executable(batch) and master.has_perm('execute'):
<div id="execution-options-dialog" style="display: none;">
${execute_form.render_deform(form_kwargs={'name': 'batch-execution'}, buttons=False)|n}
</div>
% endif
<footer class="modal-card-foot">
<b-button @click="showUploadDialog = false">
Cancel
</b-button>
<b-button type="is-primary"
@click="submitUpload()"
icon-pack="fas"
icon-left="fas fa-upload"
:disabled="uploadButtonDisabled">
{{ uploadButtonText }}
</b-button>
</footer>
</div>
</b-modal>
% endif
</%def>
<%def name="render_this_page_template()">
${parent.render_this_page_template()}
% if use_buefy:
% if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'):
${upload_worksheet_form.render_deform(buttons=False, form_kwargs={'ref': 'actualUploadForm'})|n}
% endif
% if master.handler.executable(batch) and master.has_perm('execute'):
${execute_form.render_deform(form_kwargs={'ref': 'actualExecuteForm'}, buttons=False)|n}
% endif
% if master.has_worksheet_file and master.allow_worksheet(batch) and master.has_perm('worksheet'):
${upload_worksheet_form.render_deform(buttons=False, form_kwargs={'ref': 'actualUploadForm'})|n}
% endif
% if master.handler.executable(batch) and master.has_perm('execute'):
${execute_form.render_deform(form_kwargs={'ref': 'actualExecuteForm'}, buttons=False)|n}
% endif
</%def>
@ -358,7 +215,7 @@
<%def name="render_row_grid_tools()">
${parent.render_row_grid_tools()}
% if use_buefy and master.rows_bulk_deletable and not batch.executed and master.has_perm('delete_rows'):
% if master.rows_bulk_deletable and not batch.executed and master.has_perm('delete_rows'):
<b-button type="is-danger"
@click="deleteResultsInit()"
:disabled="!total"

View file

@ -1,26 +1,6 @@
## -*- coding: utf-8; -*-
<%inherit file="/page.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('.worksheet .current-entry input').focus(function(event) {
$(this).parents('tr:first').addClass('active');
});
$('.worksheet .current-entry input').blur(function(event) {
$(this).parents('tr:first').removeClass('active');
});
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
<style type="text/css">

View file

@ -4,22 +4,16 @@
<%def name="extra_styles()">
${parent.extra_styles()}
% if use_buefy:
<style type="text/css">
.this-page-content {
flex-grow: 1;
}
</style>
% endif
<style type="text/css">
.this-page-content {
flex-grow: 1;
}
</style>
</%def>
<%def name="page_content()">
<br />
% if use_buefy:
<customer-order-creator></customer-order-creator>
% else:
<p>Sorry, but this page is not supported by your current theme configuration.</p>
% endif
<customer-order-creator></customer-order-creator>
</%def>
<%def name="order_form_buttons()">

View file

@ -12,38 +12,22 @@
${parent.grid_tools()}
% if request.has_perm('datasync.restart'):
% if use_buefy:
${h.form(url('datasync.restart'), name='restart-datasync', class_='control', **{'@submit': 'submitRestartDatasyncForm'})}
% else:
${h.form(url('datasync.restart'), name='restart-datasync', class_='autodisable')}
% endif
${h.csrf_token(request)}
% if use_buefy:
<b-button native-type="submit"
:disabled="restartDatasyncFormSubmitting">
{{ restartDatasyncFormButtonText }}
</b-button>
% else:
${h.submit('submit', "Restart DataSync", data_working_label="Restarting DataSync", class_='button')}
% endif
${h.end_form()}
% endif
% if allow_filemon_restart and request.has_perm('filemon.restart'):
% if use_buefy:
${h.form(url('filemon.restart'), name='restart-filemon', class_='control', **{'@submit': 'submitRestartFilemonForm'})}
% else:
${h.form(url('filemon.restart'), name='restart-filemon', class_='autodisable')}
% endif
${h.csrf_token(request)}
% if use_buefy:
<b-button native-type="submit"
:disabled="restartFilemonFormSubmitting">
{{ restartFilemonFormButtonText }}
</b-button>
% else:
${h.submit('submit', "Restart FileMon", data_working_label="Restarting FileMon", class_='button')}
% endif
${h.end_form()}
% endif

View file

@ -3,109 +3,10 @@
oid oid|field.oid;
field_display field_display;
style style|field.widget.style;
url url|field.widget.service_url;
use_buefy use_buefy|0;"
url url|field.widget.service_url;"
tal:omit-tag="">
<div tal:condition="not use_buefy"
id="${oid}-container"
class="autocomplete-container">
<input type="hidden"
name="${name}"
id="${oid}"
value="${cstruct}" />
<input type="text"
name="${oid}-textbox"
id="${oid}-textbox"
value="${field_display}"
class="autocomplete-textbox"
style="display: none;" />
<div id="${oid}-display"
class="autocomplete-display"
style="display: none;">
<span>${field_display or ''}</span>
<button type="button" id="${oid}-change" class="autocomplete-change">Change</button>
</div>
<script type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid + '-textbox').autocomplete(${options});
$('#' + oid + '-textbox').on('autocompleteselect', function (event, ui) {
$('#' + oid).val(ui.item.value);
$('#' + oid + '-display span:first').text(ui.item.label);
$('#' + oid + '-textbox').hide();
$('#' + oid + '-display').show();
$('#' + oid + '-textbox').trigger('autocompletevalueselected',
[ui.item.value, ui.item.label]);
return false;
});
$('#' + oid + '-change').click(function() {
$('#' + oid).val('');
$('#' + oid + '-display').hide();
with ($('#' + oid + '-textbox')) {
val('');
show();
focus();
}
$('#' + oid + '-textbox').trigger('autocompletevaluecleared');
});
}
);
</script>
<script tal:condition="cleared_callback" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid + '-textbox').on('autocompletevaluecleared', function() {
${cleared_callback}();
});
}
);
</script>
<script tal:condition="selected_callback" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid + '-textbox').on('autocompletevalueselected', function(event, uuid, label) {
${selected_callback}(uuid, label);
});
}
);
</script>
<script tal:condition="cstruct" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid + '-display').show();
}
);
</script>
<script tal:condition="not cstruct" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid + '-textbox').show();
}
);
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
<div tal:define="vmodel vmodel|'field_model_' + name;"
tal:omit-tag="">
<tailbone-autocomplete name="${name}"
ref="${ref}"

View file

@ -2,38 +2,11 @@
<div tal:define="oid oid|field.oid;
name name|field.name;
css_class css_class|field.widget.css_class;
style style|field.widget.style;
use_buefy use_buefy|0;"
style style|field.widget.style;"
i18n:domain="deform"
tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag="">
${field.start_mapping()}
<div>
<input type="text" name="cases" value="${cases}"
tal:attributes="style style;
class string: form-control ${css_class or ''};
cases_attributes|field.widget.cases_attributes|{};"
placeholder="cases"
autocomplete="off"
id="${oid}-cases"/>
Cases
</div>
<div>
<input type="text" name="units" value="${units}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
units_attributes|field.widget.units_attributes|{};"
placeholder="units"
autocomplete="off"
id="${oid}-units"/>
Units
</div>
${field.end_mapping()}
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
<div tal:define="vmodel vmodel|'field_model_' + name;"
tal:omit-tag="">
${field.start_mapping()}

View file

@ -2,21 +2,10 @@
true_val true_val|field.widget.true_val;
css_class css_class|field.widget.css_class;
style style|field.widget.style;
oid oid|field.oid;
use_buefy use_buefy|0;"
oid oid|field.oid;"
tal:omit-tag="">
<div tal:condition="not use_buefy" class="checkbox">
<input type="checkbox"
name="${name}" value="${true_val}"
id="${oid}"
tal:attributes="checked cstruct == true_val;
class css_class;
style style;" />
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;">
<div tal:define="vmodel vmodel|'field_model_' + name;">
<b-checkbox name="${name}"
v-model="${vmodel}"
native-value="${true_val}">

View file

@ -2,37 +2,9 @@
tal:define="oid oid|field.oid;
name name|field.name;
css_class css_class|field.widget.css_class;
style style|field.widget.style;
use_buefy use_buefy|0;">
style style|field.widget.style;">
<div tal:condition="not use_buefy" tal:omit-tag="">
${field.start_mapping()}
<div>
<input type="password"
name="${name}"
value="${field.widget.redisplay and cstruct or ''}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
id="${oid}"
i18n:attributes="placeholder"
placeholder="Password"/>
</div>
<div>
<input type="password"
name="${name}-confirm"
value="${field.widget.redisplay and confirm or ''}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
confirm_attributes|field.widget.confirm_attributes|{};"
id="${oid}-confirm"
i18n:attributes="placeholder"
placeholder="Confirm Password"/>
</div>
${field.end_mapping()}
</div>
<div tal:condition="use_buefy">
<div>
${field.start_mapping()}
<b-input type="password"
name="${name}"

View file

@ -3,40 +3,10 @@
oid oid|field.oid;
field_name field_name|field.name;
style style|field.widget.style;
type_name type_name|field.widget.type_name;
use_buefy use_buefy|0;"
type_name type_name|field.widget.type_name;"
tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag="">
${field.start_mapping()}
<input type="${type_name}"
name="date"
value="${cstruct}"
tal:attributes="class string: ${css_class or ''} form-control;
style style"
id="${oid}"/>
${field.end_mapping()}
<script type="text/javascript">
deform.addCallback(
'${oid}',
function deform_cb(oid) {
$('#' + oid).datepicker(${options_json});
}
);
</script>
<script tal:condition="selected_callback" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$('#' + oid).datepicker('option', 'onSelect', ${selected_callback});
}
);
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + field_name;">
<div tal:define="vmodel vmodel|'field_model_' + field_name;">
${field.start_mapping()}
<tailbone-datepicker name="date"
id="${oid}"

View file

@ -2,29 +2,9 @@
<tal:block tal:define="oid oid|field.oid;
css_class css_class|field.widget.css_class;
style style|field.widget.style;
field_name field_name|field.name;
use_buefy use_buefy|0;">
field_name field_name|field.name;">
<div tal:condition="not use_buefy" tal:omit-tag="">
${field.start_mapping()}
<input type="file" name="upload" id="${oid}"
tal:attributes="style style;
accept accept|field.widget.accept;
data-filename cstruct.get('filename');
attributes|field.widget.attributes|{};"/>
<input tal:define="uid cstruct.get('uid')"
tal:condition="uid"
type="hidden" name="uid" value="${uid}"/>
${field.end_mapping()}
<script type="text/javascript">
deform.addCallback('${oid}', function (oid) {
$('#' + oid).upload();
});
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + field_name;">
<div tal:define="vmodel vmodel|'field_model_' + field_name;">
${field.start_mapping()}
<b-field class="file">
<b-upload name="upload"

View file

@ -3,21 +3,9 @@
oid oid|field.oid;
mask mask|field.widget.mask;
mask_placeholder mask_placeholder|field.widget.mask_placeholder;
style style|field.widget.style;
use_buefy use_buefy|0;"
style style|field.widget.style;"
tal:omit-tag="">
<input tal:condition="not use_buefy"
type="password"
name="${name}"
value="${field.widget.redisplay and cstruct or ''}"
tal:attributes="style style;
class string: form-control ${css_class or ''};
attributes|field.widget.attributes|{};"
id="${oid}" />
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
<div tal:define="vmodel vmodel|'field_model_' + name;"
tal:omit-tag="">
<b-input name="${name}"
v-model="${vmodel}"

View file

@ -8,26 +8,7 @@
autocomplete autocomplete|field.widget.autocomplete|'off';"
tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag="">
<input type="text" name="${name}" value="${cstruct}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
autocomplete autocomplete;
"
id="${oid}"/>
%
<script tal:condition="mask" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$("#" + oid).mask("${mask}",
{placeholder:"${mask_placeholder}"});
});
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + field_name;">
<div tal:define="vmodel vmodel|'field_model_' + field_name;">
<!-- TODO: need to handle mask somehow? -->
<b-input name="${field_name}"
id="${oid}"

View file

@ -1,41 +1,8 @@
<div tal:define="oid oid|field.oid;
true_val true_val|field.widget.true_val;
use_buefy use_buefy|0;"
true_val true_val|field.widget.true_val;"
tal:omit-tag="">
<div tal:condition="not use_buefy"
tal:omit-tag="">
${field.start_mapping()}
<div class="permissions-outer">
<tal:loop tal:repeat="groupkey sorted(permissions, key=lambda k: permissions[k]['label'].lower())">
<div tal:define="perms permissions[groupkey]['perms'];"
class="permissions-group">
<p class="group-label">${permissions[groupkey]['label']}</p>
<tal:loop tal:repeat="key sorted(perms, key=lambda p: perms[p]['label'].lower())">
<div class="perm">
<label>
<input type="checkbox"
name="${key}"
id="${oid}-${key}"
value="${true_val}"
tal:attributes="checked python:field.widget.get_checked_value(cstruct, key);" />
${perms[key]['label']}
</label>
</div>
</tal:loop>
</div>
</tal:loop>
</div>
${field.end_mapping()}
</div>
<div tal:condition="use_buefy">
<div>
${field.start_mapping()}
<div class="level">

View file

@ -7,58 +7,10 @@
unicode unicode|str;
optgroup_class optgroup_class|field.widget.optgroup_class;
multiple multiple|field.widget.multiple;
use_buefy use_buefy|0;
input_handler input_handler|'';"
tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag="">
<input type="hidden" name="__start__" value="${name}:sequence"
tal:condition="multiple" />
<div class="select">
<select tal:attributes="
name name;
id oid;
class string: form-control ${css_class or ''};
multiple multiple;
size size;
style style;">
<tal:loop tal:repeat="item values">
<optgroup tal:condition="isinstance(item, optgroup_class)"
tal:attributes="label item.label">
<option tal:repeat="(value, description) item.options"
tal:attributes="
selected python:field.widget.get_select_value(cstruct, value);
class css_class;
label field.widget.long_label_generator and description;
value value"
tal:content="field.widget.long_label_generator and field.widget.long_label_generator(item.label, description) or description"/>
</optgroup>
<option tal:condition="not isinstance(item, optgroup_class)"
tal:attributes="
selected python:field.widget.get_select_value(cstruct, item[0]);
class css_class;
value item[0]">${item[1]}</option>
</tal:loop>
</select>
</div>
<input type="hidden" name="__end__" value="${name}:sequence"
tal:condition="multiple" />
<script tal:condition="not multiple" type="text/javascript">
deform.addCallback(
'${oid}',
function(oid) {
$('#' + oid).selectmenu();
$('#' + oid).on('selectmenuopen', function(event, ui) {
show_all_options($(this));
});
}
);
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
>
<div tal:define="vmodel vmodel|'field_model_' + name;">
<input type="hidden" name="__start__" value="${name}:sequence"
tal:condition="multiple" />
<b-select tal:attributes="name name;

View file

@ -3,22 +3,10 @@
css_class css_class|field.widget.css_class;
oid oid|field.oid;
name name|field.name;
style style|field.widget.style;
use_buefy use_buefy|0;"
style style|field.widget.style;"
tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag="">
<textarea tal:attributes="rows rows;
cols cols;
class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
id="${oid}"
name="${name}">${cstruct}</textarea>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;">
<div tal:define="vmodel vmodel|'field_model_' + name;">
<b-input type="textarea"
name="${name}"
v-model="${vmodel}">

View file

@ -4,29 +4,10 @@
mask mask|field.widget.mask;
mask_placeholder mask_placeholder|field.widget.mask_placeholder;
style style|field.widget.style;
use_buefy use_buefy|0;
placeholder placeholder|getattr(field.widget, 'placeholder', '');
autocomplete autocomplete|getattr(field.widget, 'autocomplete', 'on');"
tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag="">
<input type="text" name="${name}" value="${cstruct}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
autocomplete="${autocomplete}"
id="${oid}"/>
<script tal:condition="mask" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$("#" + oid).mask("${mask}",
{placeholder:"${mask_placeholder}"});
});
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + name;"
<div tal:define="vmodel vmodel|'field_model_' + name;"
tal:omit-tag="">
<b-input tal:attributes="name name;
v-model vmodel;

View file

@ -4,32 +4,10 @@
oid oid|field.oid;
style style|field.widget.style|None;
type_name type_name|field.widget.type_name;
field_name field_name|field.name;
use_buefy use_buefy|0;"
field_name field_name|field.name;"
tal:omit-tag="">
<div tal:condition="not use_buefy" tal:omit-tag="">
${field.start_mapping()}
<input type="${type_name}"
name="time"
value="${cstruct}"
tal:attributes="size size;
class string: ${css_class or ''} form-control;
style style"
id="${oid}"/>
${field.end_mapping()}
<script type="text/javascript">
deform.addCallback(
'${oid}',
function(oid) {
$('#' + oid).timepicker(${options_json});
}
);
</script>
</div>
<div tal:condition="use_buefy"
tal:define="vmodel vmodel|'field_model_' + field_name;">
<div tal:define="vmodel vmodel|'field_model_' + field_name;">
${field.start_mapping()}
<tailbone-timepicker name="time"
id="${oid}"

View file

@ -1,20 +1,6 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" />
<%def name="page_content()">
${parent.page_content()}
% if not use_buefy:
<h2>Employees</h2>
% if employees:
<p>The following employees are assigned to this department:</p>
${employees.render_grid()|n}
% else:
<p>No employees are assigned to this department.</p>
% endif
% endif
</%def>
<%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()}
<script type="text/javascript">

View file

@ -3,36 +3,8 @@
## TODO: this page still uses jQuery but should use Vue.js
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
function autosize_message(scrolldown) {
var msg = $('#message');
var height = $(window).height() - msg.offset().top - 50;
msg.height(height);
if (scrolldown) {
msg.animate({scrollTop: msg.get(0).scrollHeight - height}, 250);
}
}
$(function () {
autosize_message(true);
$('#message').focus();
});
$(window).resize(function() {
autosize_message(false);
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if use_buefy:
<style type="text/css">
.email-message-body {
border: 1px solid #000000;
@ -40,81 +12,48 @@
height: 500px;
}
</style>
% else:
<style type="text/css">
#message {
border: 1px solid #000000;
height: 400px;
overflow: auto;
padding: 4px;
}
</style>
% endif
</%def>
<%def name="object_helpers()">
${parent.object_helpers()}
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Processing</p>
<div class="panel-block">
<div class="display: flex; flex-align: column;">
% if bounce.processed:
<p class="block">
This bounce was processed
${h.pretty_datetime(request.rattail_config, bounce.processed)}
by ${bounce.processed_by}
</p>
% if master.has_perm('unprocess'):
<once-button type="is-warning"
tag="a" href="${url('emailbounces.unprocess', uuid=bounce.uuid)}"
text="Mark this bounce as UN-processed">
</once-button>
% endif
% else:
<p class="block">
This bounce has NOT yet been processed.
</p>
% if master.has_perm('process'):
<once-button type="is-primary"
tag="a" href="${url('emailbounces.process', uuid=bounce.uuid)}"
text="Mark this bounce as Processed">
</once-button>
% endif
<nav class="panel">
<p class="panel-heading">Processing</p>
<div class="panel-block">
<div class="display: flex; flex-align: column;">
% if bounce.processed:
<p class="block">
This bounce was processed
${h.pretty_datetime(request.rattail_config, bounce.processed)}
by ${bounce.processed_by}
</p>
% if master.has_perm('unprocess'):
<once-button type="is-warning"
tag="a" href="${url('emailbounces.unprocess', uuid=bounce.uuid)}"
text="Mark this bounce as UN-processed">
</once-button>
% endif
</div>
</div>
</nav>
% endif
</%def>
<%def name="context_menu_items()">
${parent.context_menu_items()}
% if not use_buefy:
% if not bounce.processed and request.has_perm('emailbounces.process'):
<li>${h.link_to("Mark this Email Bounce as Processed", url('emailbounces.process', uuid=bounce.uuid))}</li>
% elif bounce.processed and request.has_perm('emailbounces.unprocess'):
<li>${h.link_to("Mark this Email Bounce as UN-processed", url('emailbounces.unprocess', uuid=bounce.uuid))}</li>
% endif
% endif
</%def>
<%def name="page_content()">
${parent.page_content()}
% if not use_buefy:
<pre id="message">
${message}
</pre>
% endif
% else:
<p class="block">
This bounce has NOT yet been processed.
</p>
% if master.has_perm('process'):
<once-button type="is-primary"
tag="a" href="${url('emailbounces.process', uuid=bounce.uuid)}"
text="Mark this bounce as Processed">
</once-button>
% endif
% endif
</div>
</div>
</nav>
</%def>
<%def name="render_this_page()">
${parent.render_this_page()}
% if use_buefy:
<pre class="email-message-body">
${message}
</pre>
% endif
<pre class="email-message-body">
${message}
</pre>
</%def>
${parent.body()}

View file

@ -22,12 +22,8 @@
<%def name="page_content()">
<div class="form-wrapper">
% if use_buefy:
<br />
${self.render_buefy_form()}
% else:
${self.render_form()}
% endif
<br />
${self.render_buefy_form()}
</div>
</%def>

View file

@ -1,8 +1,2 @@
## -*- coding: utf-8; -*-
% if form.use_buefy:
${form.render_deform(buttons=buttons)|n}
% else:
<div class="form">
${form.render_deform(buttons=buttons)|n}
</div>
% endif
${form.render_deform(buttons=buttons)|n}

View file

@ -4,36 +4,27 @@
<%def name="title()">Login</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
${h.javascript_link(request.static_url('tailbone:static/js/login.js'))}
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if use_buefy:
<style type="text/css">
.logo img {
display: block;
margin: 3rem auto;
max-height: 350px;
max-width: 800px;
}
<style type="text/css">
.logo img {
display: block;
margin: 3rem auto;
max-height: 350px;
max-width: 800px;
}
/* must force a particular label with, in order to make sure */
/* the username and password inputs are the same size */
.field.is-horizontal .field-label .label {
text-align: left;
width: 6rem;
}
/* must force a particular label with, in order to make sure */
/* the username and password inputs are the same size */
.field.is-horizontal .field-label .label {
text-align: left;
width: 6rem;
}
.buttons {
justify-content: right;
}
</style>
% else:
${h.stylesheet_link(request.static_url('tailbone:static/css/login.css'))}
% endif
.buttons {
justify-content: right;
}
</style>
</%def>
<%def name="logo()">
@ -55,21 +46,15 @@
${self.logo()}
</div>
% if use_buefy:
<div class="columns is-centered">
<div class="column is-narrow">
<div class="card">
<div class="card-content">
<tailbone-form></tailbone-form>
</div>
</div>
<div class="columns is-centered">
<div class="column is-narrow">
<div class="card">
<div class="card-content">
<tailbone-form></tailbone-form>
</div>
</div>
% else:
${self.login_form()}
% endif
</div>
</div>
</%def>

View file

@ -5,49 +5,31 @@
<%def name="render_buefy_form()">
<br />
% if use_buefy:
<b-notification :closable="false">
You are about to clone the following ${model_title} as a new record:
</b-notification>
% else:
<p>You are about to clone the following ${model_title} as a new record:</p>
% endif
<b-notification :closable="false">
You are about to clone the following ${model_title} as a new record:
</b-notification>
${parent.render_buefy_form()}
</%def>
<%def name="render_form_buttons()">
<br />
% if use_buefy:
<b-notification :closable="false">
Are you sure about this?
</b-notification>
% else:
<p>Are you sure about this?</p>
% endif
<b-notification :closable="false">
Are you sure about this?
</b-notification>
<br />
% if use_buefy:
${h.form(request.current_route_url(), **{'@submit': 'submitForm'})}
% else:
${h.form(request.current_route_url(), class_='autodisable')}
% endif
${h.csrf_token(request)}
${h.hidden('clone', value='clone')}
<div class="buttons">
% if use_buefy:
<once-button tag="a" href="${form.cancel_url}"
text="Whoops, nevermind...">
</once-button>
<b-button type="is-primary"
native-type="submit"
:disabled="formSubmitting">
{{ submitButtonText }}
</b-button>
% else:
${h.link_to("Whoops, nevermind...", form.cancel_url, class_='button autodisable')}
${h.submit('submit', "Yes, please clone away")}
% endif
<once-button tag="a" href="${form.cancel_url}"
text="Whoops, nevermind...">
</once-button>
<b-button type="is-primary"
native-type="submit"
:disabled="formSubmitting">
{{ submitButtonText }}
</b-button>
</div>
${h.end_form()}
</%def>

View file

@ -3,66 +3,32 @@
<%def name="title()">Delete ${model_title}: ${instance_title}</%def>
<%def name="context_menu_items()">
% if not use_buefy and master.viewable and master.has_perm('view'):
<li>${h.link_to("View this {}".format(model_title), action_url('view', instance))}</li>
% endif
% if not use_buefy and master.editable and master.has_perm('edit'):
<li>${h.link_to("Edit this {}".format(model_title), action_url('edit', instance))}</li>
% endif
% if not use_buefy and master.creatable and master.show_create_link and master.has_perm('create'):
% if master.creates_multiple:
<li>${h.link_to("Create new {}".format(model_title_plural), url('{}.create'.format(route_prefix)))}</li>
% else:
<li>${h.link_to("Create a new {}".format(model_title), url('{}.create'.format(route_prefix)))}</li>
% endif
% endif
</%def>
<%def name="render_buefy_form()">
<br />
% if use_buefy:
<b-notification type="is-danger" :closable="false">
You are about to delete the following ${model_title} and all associated data:
</b-notification>
% else:
<p>You are about to delete the following ${model_title} and all associated data:</p>
% endif
<b-notification type="is-danger" :closable="false">
You are about to delete the following ${model_title} and all associated data:
</b-notification>
${parent.render_buefy_form()}
</%def>
<%def name="render_form_buttons()">
<br />
% if use_buefy:
<b-notification type="is-danger" :closable="false">
Are you sure about this?
</b-notification>
% else:
<p>Are you sure about this?</p>
% endif
<b-notification type="is-danger" :closable="false">
Are you sure about this?
</b-notification>
<br />
% if use_buefy:
${h.form(request.current_route_url(), **{'@submit': 'submitForm'})}
% else:
${h.form(request.current_route_url(), class_='autodisable')}
% endif
${h.csrf_token(request)}
<div class="buttons">
% if use_buefy:
<once-button tag="a" href="${form.cancel_url}"
text="Whoops, nevermind...">
</once-button>
<b-button type="is-primary is-danger"
native-type="submit"
:disabled="formSubmitting">
{{ formButtonText }}
</b-button>
% else:
<a class="button" href="${form.cancel_url}">Whoops, nevermind...</a>
${h.submit('submit', "Yes, please DELETE this data forever!", class_='button is-primary')}
% endif
<once-button tag="a" href="${form.cancel_url}"
text="Whoops, nevermind...">
</once-button>
<b-button type="is-primary is-danger"
native-type="submit"
:disabled="formSubmitting">
{{ formButtonText }}
</b-button>
</div>
${h.end_form()}
</%def>

View file

@ -3,38 +3,5 @@
<%def name="title()">Edit: ${instance_title}</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('form').submit(function() {
var submit = $(this).find('input[type="submit"]');
if (submit.length) {
submit.button('disable').button('option', 'label', "Saving, please wait...");
}
});
});
</script>
% endif
</%def>
<%def name="context_menu_items()">
% if not use_buefy and master.viewable and master.has_perm('view'):
<li>${h.link_to("View this {}".format(model_title), action_url('view', instance))}</li>
% endif
${self.context_menu_item_delete()}
% if not use_buefy and master.creatable and master.show_create_link and master.has_perm('create'):
% if master.creates_multiple:
<li>${h.link_to("Create new {}".format(model_title_plural), url('{}.create'.format(route_prefix)))}</li>
% else:
<li>${h.link_to("Create a new {}".format(model_title), url('{}.create'.format(route_prefix)))}</li>
% endif
% endif
</%def>
${parent.body()}

View file

@ -1,31 +1,6 @@
## -*- coding: utf-8; -*-
<%inherit file="/form.mako" />
<%def name="context_menu_item_delete()">
% if not use_buefy and master.deletable and instance_deletable and master.has_perm('delete'):
% if master.delete_confirm == 'simple':
<li>
## note, the `ref` here is for buefy only
${h.form(action_url('delete', instance), ref='deleteObjectForm')}
${h.csrf_token(request)}
<a href="${action_url('delete', instance)}"
% if use_buefy:
@click.prevent="deleteObject"
% else:
class="delete-instance"
% endif
>
Delete this ${model_title}
</a>
${h.end_form()}
</li>
% else:
## assuming here that: delete_confirm == 'full'
<li>${h.link_to("Delete this {}".format(model_title), action_url('delete', instance))}</li>
% endif
% endif
</%def>
<%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()}
% if master.deletable and instance_deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':

View file

@ -12,142 +12,6 @@
<%def name="content_title()"></%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
% if download_results_rows_path:
function downloadResultsRowsRedirect() {
location.href = '${url('{}.download_results_rows'.format(route_prefix))}?filename=${h.os.path.basename(download_results_rows_path)}';
}
// we give this 1 second before attempting the redirect; so this
// way the page should fully render before redirecting
window.setTimeout(downloadResultsRowsRedirect, 1000);
% endif
$('.grid-wrapper').gridwrapper();
% if master.deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':
$('.grid-wrapper').on('click', '.grid .actions a.delete', function() {
if (confirm("Are you sure you wish to delete this ${model_title}?")) {
var link = $(this).get(0);
var form = $('#delete-object-form').get(0);
form.action = link.href;
form.submit();
}
return false;
});
% endif
% if master.mergeable and master.has_perm('merge'):
$('form[name="merge-things"] button').button('option', 'disabled', $('.grid').gridcore('count_selected') != 2);
$('.grid-wrapper').on('gridchecked', '.grid', function(event, count) {
$('form[name="merge-things"] button').button('option', 'disabled', count != 2);
});
$('form[name="merge-things"]').submit(function() {
var uuids = $('.grid').gridcore('selected_uuids');
if (uuids.length != 2) {
return false;
}
$(this).find('[name="uuids"]').val(uuids.toString());
$(this).find('button')
.button('option', 'label', "Preparing to Merge...")
.button('disable');
});
% endif
% if master.has_rows and master.results_rows_downloadable:
$('#download-row-results-button').click(function() {
if (confirm("This will generate an Excel file which contains "
+ "not the results themselves, but the *rows* for "
+ "each.\n\nAre you sure you want this?")) {
disable_button(this);
var form = $(this).parents('form');
form.submit();
}
});
% endif
% if master.bulk_deletable and request.has_perm('{}.bulk_delete'.format(permission_prefix)):
$('form[name="bulk-delete"] button').click(function() {
var count = $('.grid-wrapper').gridwrapper('results_count', true);
if (count === null) {
alert("There don't seem to be any results to delete!");
return;
}
if (! confirm("You are about to delete " + count + " ${model_title_plural}.\n\nAre you sure?")) {
return
}
$(this).button('disable').button('option', 'label', "Deleting Results...");
$('form[name="bulk-delete"]').submit();
});
% endif
% if master.supports_set_enabled_toggle and request.has_perm('{}.enable_disable_set'.format(permission_prefix)):
$('form[name="enable-set"] button').click(function() {
var form = $(this).parents('form');
var uuids = $('.grid').gridcore('selected_uuids');
if (! uuids.length) {
alert("You must first select one or more objects to enable.");
return false;
}
if (! confirm("Are you sure you wish to ENABLE the " + uuids.length + " selected objects?")) {
return false;
}
form.find('[name="uuids"]').val(uuids.toString());
disable_button(this);
form.submit();
});
$('form[name="disable-set"] button').click(function() {
var form = $(this).parents('form');
var uuids = $('.grid').gridcore('selected_uuids');
if (! uuids.length) {
alert("You must first select one or more objects to disable.");
return false;
}
if (! confirm("Are you sure you wish to DISABLE the " + uuids.length + " selected objects?")) {
return false;
}
form.find('[name="uuids"]').val(uuids.toString());
disable_button(this);
form.submit();
});
% endif
% if master.set_deletable and request.has_perm('{}.delete_set'.format(permission_prefix)):
$('form[name="delete-set"] button').click(function() {
var form = $(this).parents('form');
var uuids = $('.grid').gridcore('selected_uuids');
if (! uuids.length) {
alert("You must first select one or more objects to delete.");
return false;
}
if (! confirm("Are you sure you wish to DELETE the " + uuids.length + " selected objects?")) {
return false;
}
form.find('[name="uuids"]').val(uuids.toString());
disable_button(this);
form.submit();
});
% endif
});
</script>
% endif
</%def>
<%def name="context_menu_items()">
% if master.results_downloadable_csv and request.has_perm('{}.results_csv'.format(permission_prefix)):
<li>${h.link_to("Download results as CSV", url('{}.results_csv'.format(route_prefix)))}</li>
@ -155,13 +19,6 @@
% if master.results_downloadable_xlsx and request.has_perm('{}.results_xlsx'.format(permission_prefix)):
<li>${h.link_to("Download results as XLSX", url('{}.results_xlsx'.format(route_prefix)))}</li>
% endif
% if not use_buefy and master.creatable and master.show_create_link and master.has_perm('create'):
% if master.creates_multiple:
<li>${h.link_to("Create new {}".format(model_title_plural), url('{}.create'.format(route_prefix)))}</li>
% else:
<li>${h.link_to("Create a new {}".format(model_title), url('{}.create'.format(route_prefix)))}</li>
% endif
% endif
% if master.has_input_file_templates and master.has_perm('create'):
% for template in six.itervalues(input_file_templates):
<li>${h.link_to("Download {} Template".format(template['label']), template['effective_url'])}</li>
@ -173,284 +30,233 @@
## download search results
% if master.results_downloadable and master.has_perm('download_results'):
% if use_buefy:
<b-button type="is-primary"
icon-pack="fas"
icon-left="fas fa-download"
@click="showDownloadResultsDialog = true"
:disabled="!total">
Download Results
</b-button>
<b-button type="is-primary"
icon-pack="fas"
icon-left="fas fa-download"
@click="showDownloadResultsDialog = true"
:disabled="!total">
Download Results
</b-button>
${h.form(url('{}.download_results'.format(route_prefix)), ref='download_results_form')}
${h.csrf_token(request)}
<input type="hidden" name="fmt" :value="downloadResultsFormat" />
<input type="hidden" name="fields" :value="downloadResultsFieldsIncluded" />
${h.end_form()}
${h.form(url('{}.download_results'.format(route_prefix)), ref='download_results_form')}
${h.csrf_token(request)}
<input type="hidden" name="fmt" :value="downloadResultsFormat" />
<input type="hidden" name="fields" :value="downloadResultsFieldsIncluded" />
${h.end_form()}
<b-modal :active.sync="showDownloadResultsDialog">
<div class="card">
<b-modal :active.sync="showDownloadResultsDialog">
<div class="card">
<div class="card-content">
<p>
There are
<span class="is-size-4 has-text-weight-bold">
{{ total.toLocaleString('en') }} ${model_title_plural}
</span>
matching your current filters.
</p>
<p>
You may download this set as a single data file if you like.
</p>
<br />
<div class="card-content">
<p>
There are
<span class="is-size-4 has-text-weight-bold">
{{ total.toLocaleString('en') }} ${model_title_plural}
</span>
matching your current filters.
</p>
<p>
You may download this set as a single data file if you like.
</p>
<br />
<b-notification type="is-warning" :closable="false"
v-if="downloadResultsFormat == 'xlsx' && total >= 1000">
Excel downloads for large data sets can take a long time to
generate, and bog down the server in the meantime. You are
encouraged to choose CSV for a large data set, even though
the end result (file size) may be larger with CSV.
</b-notification>
<b-notification type="is-warning" :closable="false"
v-if="downloadResultsFormat == 'xlsx' && total >= 1000">
Excel downloads for large data sets can take a long time to
generate, and bog down the server in the meantime. You are
encouraged to choose CSV for a large data set, even though
the end result (file size) may be larger with CSV.
</b-notification>
<div style="display: flex; justify-content: space-between">
<div style="display: flex; justify-content: space-between">
<div>
<b-field horizontal label="Format">
<b-select v-model="downloadResultsFormat">
% for key, label in six.iteritems(master.download_results_supported_formats()):
<option value="${key}">${label}</option>
% endfor
</b-select>
</b-field>
</div>
<div>
<b-field horizontal label="Format">
<b-select v-model="downloadResultsFormat">
% for key, label in six.iteritems(master.download_results_supported_formats()):
<option value="${key}">${label}</option>
% endfor
</b-select>
</b-field>
</div>
<div>
<div>
<div v-show="downloadResultsFieldsMode != 'choose'"
class="has-text-right">
<p v-if="downloadResultsFieldsMode == 'default'">
Will use DEFAULT fields.
</p>
<p v-if="downloadResultsFieldsMode == 'all'">
Will use ALL fields.
</p>
<div v-show="downloadResultsFieldsMode != 'choose'"
class="has-text-right">
<p v-if="downloadResultsFieldsMode == 'default'">
Will use DEFAULT fields.
</p>
<p v-if="downloadResultsFieldsMode == 'all'">
Will use ALL fields.
</p>
<br />
</div>
<div class="buttons is-right">
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'default'"
@click="downloadResultsUseDefaultFields()">
Use Default Fields
</b-button>
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'all'"
@click="downloadResultsUseAllFields()">
Use All Fields
</b-button>
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'choose'"
@click="downloadResultsFieldsMode = 'choose'">
Choose Fields
</b-button>
</div>
<div v-show="downloadResultsFieldsMode == 'choose'">
<div style="display: flex;">
<div>
<b-field label="Excluded Fields">
<b-select multiple native-size="8"
expanded
ref="downloadResultsExcludedFields">
<option v-for="field in downloadResultsFieldsAvailable"
v-if="!downloadResultsFieldsIncluded.includes(field)"
:key="field"
:value="field">
{{ field }}
</option>
</b-select>
</b-field>
</div>
<div>
<br /><br />
<b-button style="margin: 0.5rem;"
@click="downloadResultsExcludeFields()">
&lt;
</b-button>
<br />
</div>
<div class="buttons is-right">
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'default'"
@click="downloadResultsUseDefaultFields()">
Use Default Fields
</b-button>
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'all'"
@click="downloadResultsUseAllFields()">
Use All Fields
</b-button>
<b-button type="is-primary"
v-show="downloadResultsFieldsMode != 'choose'"
@click="downloadResultsFieldsMode = 'choose'">
Choose Fields
<b-button style="margin: 0.5rem;"
@click="downloadResultsIncludeFields()">
&gt;
</b-button>
</div>
<div v-show="downloadResultsFieldsMode == 'choose'">
<div style="display: flex;">
<div>
<b-field label="Excluded Fields">
<b-select multiple native-size="8"
expanded
ref="downloadResultsExcludedFields">
<option v-for="field in downloadResultsFieldsAvailable"
v-if="!downloadResultsFieldsIncluded.includes(field)"
:key="field"
:value="field">
{{ field }}
</option>
</b-select>
</b-field>
</div>
<div>
<br /><br />
<b-button style="margin: 0.5rem;"
@click="downloadResultsExcludeFields()">
&lt;
</b-button>
<br />
<b-button style="margin: 0.5rem;"
@click="downloadResultsIncludeFields()">
&gt;
</b-button>
</div>
<div>
<b-field label="Included Fields">
<b-select multiple native-size="8"
expanded
ref="downloadResultsIncludedFields">
<option v-for="field in downloadResultsFieldsIncluded"
:key="field"
:value="field">
{{ field }}
</option>
</b-select>
</b-field>
</div>
</div>
<div>
<b-field label="Included Fields">
<b-select multiple native-size="8"
expanded
ref="downloadResultsIncludedFields">
<option v-for="field in downloadResultsFieldsIncluded"
:key="field"
:value="field">
{{ field }}
</option>
</b-select>
</b-field>
</div>
</div>
</div>
</div> <!-- card-content -->
<footer class="modal-card-foot">
<b-button @click="showDownloadResultsDialog = false">
Cancel
</b-button>
<once-button type="is-primary"
@click="downloadResultsSubmit()"
icon-pack="fas"
icon-left="fas fa-download"
:disabled="!downloadResultsFieldsIncluded.length"
text="Download Results">
</once-button>
</footer>
</div>
</div>
</b-modal>
% endif
</div> <!-- card-content -->
<footer class="modal-card-foot">
<b-button @click="showDownloadResultsDialog = false">
Cancel
</b-button>
<once-button type="is-primary"
@click="downloadResultsSubmit()"
icon-pack="fas"
icon-left="fas fa-download"
:disabled="!downloadResultsFieldsIncluded.length"
text="Download Results">
</once-button>
</footer>
</div>
</b-modal>
% endif
## download rows for search results
% if master.has_rows and master.results_rows_downloadable and master.has_perm('download_results_rows'):
% if use_buefy:
<b-button type="is-primary"
icon-pack="fas"
icon-left="fas fa-download"
@click="downloadResultsRows()"
:disabled="downloadResultsRowsButtonDisabled">
{{ downloadResultsRowsButtonText }}
</b-button>
${h.form(url('{}.download_results_rows'.format(route_prefix)), ref='downloadResultsRowsForm')}
${h.csrf_token(request)}
${h.end_form()}
% else:
${h.form(url('{}.download_results_rows'.format(route_prefix)))}
${h.csrf_token(request)}
<button type="button" id="download-row-results-button">
Download Rows for Results
</button>
${h.end_form()}
% endif
<b-button type="is-primary"
icon-pack="fas"
icon-left="fas fa-download"
@click="downloadResultsRows()"
:disabled="downloadResultsRowsButtonDisabled">
{{ downloadResultsRowsButtonText }}
</b-button>
${h.form(url('{}.download_results_rows'.format(route_prefix)), ref='downloadResultsRowsForm')}
${h.csrf_token(request)}
${h.end_form()}
% endif
## merge 2 objects
% if master.mergeable and request.has_perm('{}.merge'.format(permission_prefix)):
% if use_buefy:
${h.form(url('{}.merge'.format(route_prefix)), class_='control', **{'@submit': 'submitMergeForm'})}
% else:
${h.form(url('{}.merge'.format(route_prefix)), name='merge-things')}
% endif
${h.csrf_token(request)}
% if use_buefy:
<input type="hidden"
name="uuids"
:value="checkedRowUUIDs()" />
<b-button type="is-primary"
native-type="submit"
icon-pack="fas"
icon-left="object-ungroup"
:disabled="mergeFormSubmitting || checkedRows.length != 2">
{{ mergeFormButtonText }}
</b-button>
% else:
${h.hidden('uuids')}
<button type="submit" class="button">Merge 2 ${model_title_plural}</button>
% endif
<input type="hidden"
name="uuids"
:value="checkedRowUUIDs()" />
<b-button type="is-primary"
native-type="submit"
icon-pack="fas"
icon-left="object-ungroup"
:disabled="mergeFormSubmitting || checkedRows.length != 2">
{{ mergeFormButtonText }}
</b-button>
${h.end_form()}
% endif
## enable / disable selected objects
% if master.supports_set_enabled_toggle and master.has_perm('enable_disable_set'):
% if use_buefy:
${h.form(url('{}.enable_set'.format(route_prefix)), class_='control', ref='enable_selected_form')}
${h.csrf_token(request)}
${h.hidden('uuids', v_model='selected_uuids')}
<b-button :disabled="enableSelectedDisabled"
@click="enableSelectedSubmit()">
{{ enableSelectedText }}
</b-button>
${h.end_form()}
% else:
${h.form(url('{}.enable_set'.format(route_prefix)), name='enable-set', class_='control')}
${h.csrf_token(request)}
${h.hidden('uuids')}
<button type="button" class="button">Enable Selected</button>
${h.end_form()}
% endif
${h.form(url('{}.enable_set'.format(route_prefix)), class_='control', ref='enable_selected_form')}
${h.csrf_token(request)}
${h.hidden('uuids', v_model='selected_uuids')}
<b-button :disabled="enableSelectedDisabled"
@click="enableSelectedSubmit()">
{{ enableSelectedText }}
</b-button>
${h.end_form()}
% if use_buefy:
${h.form(url('{}.disable_set'.format(route_prefix)), ref='disable_selected_form', class_='control')}
${h.csrf_token(request)}
${h.hidden('uuids', v_model='selected_uuids')}
<b-button :disabled="disableSelectedDisabled"
@click="disableSelectedSubmit()">
{{ disableSelectedText }}
</b-button>
${h.end_form()}
% else:
${h.form(url('{}.disable_set'.format(route_prefix)), name='disable-set', class_='control')}
${h.csrf_token(request)}
${h.hidden('uuids')}
<button type="button" class="button">Disable Selected</button>
${h.end_form()}
% endif
${h.form(url('{}.disable_set'.format(route_prefix)), ref='disable_selected_form', class_='control')}
${h.csrf_token(request)}
${h.hidden('uuids', v_model='selected_uuids')}
<b-button :disabled="disableSelectedDisabled"
@click="disableSelectedSubmit()">
{{ disableSelectedText }}
</b-button>
${h.end_form()}
% endif
## delete selected objects
% if master.set_deletable and master.has_perm('delete_set'):
% if use_buefy:
${h.form(url('{}.delete_set'.format(route_prefix)), ref='delete_selected_form', class_='control')}
${h.csrf_token(request)}
${h.hidden('uuids', v_model='selected_uuids')}
<b-button type="is-danger"
:disabled="deleteSelectedDisabled"
@click="deleteSelectedSubmit()"
icon-pack="fas"
icon-left="trash">
{{ deleteSelectedText }}
</b-button>
${h.end_form()}
% else:
${h.form(url('{}.delete_set'.format(route_prefix)), name='delete-set', class_='control')}
${h.csrf_token(request)}
${h.hidden('uuids')}
<button type="button" class="button">Delete Selected</button>
${h.end_form()}
% endif
${h.form(url('{}.delete_set'.format(route_prefix)), ref='delete_selected_form', class_='control')}
${h.csrf_token(request)}
${h.hidden('uuids', v_model='selected_uuids')}
<b-button type="is-danger"
:disabled="deleteSelectedDisabled"
@click="deleteSelectedSubmit()"
icon-pack="fas"
icon-left="trash">
{{ deleteSelectedText }}
</b-button>
${h.end_form()}
% endif
## delete search results
% if master.bulk_deletable and request.has_perm('{}.bulk_delete'.format(permission_prefix)):
% if use_buefy:
${h.form(url('{}.bulk_delete'.format(route_prefix)), ref='delete_results_form', class_='control')}
${h.csrf_token(request)}
<b-button type="is-danger"
:disabled="deleteResultsDisabled"
:title="total ? null : 'There are no results to delete'"
@click="deleteResultsSubmit()"
icon-pack="fas"
icon-left="trash">
{{ deleteResultsText }}
</b-button>
${h.end_form()}
% else:
${h.form(url('{}.bulk_delete'.format(route_prefix)), name='bulk-delete', class_='control')}
${h.csrf_token(request)}
<button type="button">Delete Results</button>
${h.end_form()}
% endif
${h.form(url('{}.bulk_delete'.format(route_prefix)), ref='delete_results_form', class_='control')}
${h.csrf_token(request)}
<b-button type="is-danger"
:disabled="deleteResultsDisabled"
:title="total ? null : 'There are no results to delete'"
@click="deleteResultsSubmit()"
icon-pack="fas"
icon-left="trash">
{{ deleteResultsText }}
</b-button>
${h.end_form()}
% endif
</%def>
@ -516,7 +322,7 @@
<script type="text/javascript">
## maybe auto-redirect to download latest results file
% if download_results_path and use_buefy:
% if download_results_path:
ThisPage.methods.downloadResultsRedirect = function() {
location.href = '${url('{}.download_results'.format(route_prefix))}?filename=${h.os.path.basename(download_results_path)}';
}
@ -529,7 +335,7 @@
% endif
## maybe auto-redirect to download latest "rows for results" file
% if download_results_rows_path and use_buefy:
% if download_results_rows_path:
ThisPage.methods.downloadResultsRowsRedirect = function() {
location.href = '${url('{}.download_results_rows'.format(route_prefix))}?filename=${h.os.path.basename(download_results_rows_path)}';
}
@ -541,13 +347,12 @@
}
% endif
## TODO: stop checking for buefy here once we only have the one session.pop()
% if use_buefy and request.session.pop('{}.results_csv.generated'.format(route_prefix), False):
% if request.session.pop('{}.results_csv.generated'.format(route_prefix), False):
ThisPage.mounted = function() {
location.href = '${url('{}.results_csv_download'.format(route_prefix))}';
}
% endif
% if use_buefy and request.session.pop('{}.results_xlsx.generated'.format(route_prefix), False):
% if request.session.pop('{}.results_xlsx.generated'.format(route_prefix), False):
ThisPage.mounted = function() {
location.href = '${url('{}.results_xlsx_download'.format(route_prefix))}';
}
@ -793,44 +598,4 @@
</%def>
% if use_buefy:
${parent.body()}
% else:
## no buefy, so do the traditional thing
% if download_results_rows_path:
<div class="flash-messages">
<div class="ui-state-highlight ui-corner-all">
<span style="float: left; margin-right: .3em;" class="ui-icon ui-icon-info"></span>
Your download should start automatically, or you can
${h.link_to("click here", '{}?filename={}'.format(url('{}.download_results_rows'.format(route_prefix)), h.os.path.basename(download_results_rows_path)))}
</div>
</div>
% endif
${grid.render_complete(tools=capture(self.grid_tools).strip(), context_menu=capture(self.context_menu_items).strip())|n}
% if master.deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':
${h.form('#', id='delete-object-form')}
${h.csrf_token(request)}
${h.end_form()}
% endif
## TODO: can stop checking for buefy above once this legacy chunk is gone
% if request.session.pop('{}.results_csv.generated'.format(route_prefix), False):
<script type="text/javascript">
$(function() {
location.href = '${url('{}.results_csv_download'.format(route_prefix))}';
});
</script>
% endif
% if request.session.pop('{}.results_xlsx.generated'.format(route_prefix), False):
<script type="text/javascript">
$(function() {
location.href = '${url('{}.results_xlsx_download'.format(route_prefix))}';
});
</script>
% endif
% endif
${parent.body()}

View file

@ -3,36 +3,6 @@
<%def name="title()">Merge 2 ${model_title_plural}</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('button.swap').click(function() {
$(this).button('disable').button('option', 'label', "Swapping, please wait...");
var form = $(this).parents('form');
var input = form.find('input[name="uuids"]');
var uuids = input.val().split(',');
uuids.reverse();
input.val(uuids.join(','));
form.submit();
});
$('form.merge input[type="submit"]').click(function() {
$(this).button('disable').button('option', 'label', "Merging, please wait...");
var form = $(this).parents('form');
form.append($('<input type="hidden" name="commit-merge" value="yes" />'));
form.submit();
});
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
<style type="text/css">
@ -92,66 +62,51 @@
</%def>
<%def name="page_content()">
<p>
You are about to <strong>merge</strong> two ${model_title} records,
(possibly) along with various related data.&nbsp; The tool you are using now
is somewhat generic and is not able to give you the full picture of the
implications of this merge.&nbsp; You are urged to proceed with caution!&nbsp;
</p>
<p>
You are about to <strong>merge</strong> two ${model_title} records,
(possibly) along with various related data.&nbsp; The tool you are using now
is somewhat generic and is not able to give you the full picture of the
implications of this merge.&nbsp; You are urged to proceed with caution!&nbsp;
</p>
<p class="warning">
<strong>Unless you know what you're doing, a good rule of thumb (though still no
guarantee) is to merge <em>only</em> if the "resulting" column is all-white.</strong>&nbsp;
(You may be able to swap kept/removed in order to achieve this.)
</p>
<p class="warning">
<strong>Unless you know what you're doing, a good rule of thumb (though still no
guarantee) is to merge <em>only</em> if the "resulting" column is all-white.</strong>&nbsp;
(You may be able to swap kept/removed in order to achieve this.)
</p>
<p>
The ${h.link_to("{} on the left".format(model_title), view_url(object_to_remove), target='_blank', class_='merge-object')}
will be <strong>deleted</strong>
and the ${h.link_to("{} on the right".format(model_title), view_url(object_to_keep), target='_blank', class_='merge-object')}
will be <strong>kept</strong>.&nbsp; The one which is to be kept may also
be updated to reflect certain aspects of the one being deleted; however again
the details are up to the app logic for this type of merge and aren't fully
known to the generic tool which you're using now.
</p>
<p>
The ${h.link_to("{} on the left".format(model_title), view_url(object_to_remove), target='_blank', class_='merge-object')}
will be <strong>deleted</strong>
and the ${h.link_to("{} on the right".format(model_title), view_url(object_to_keep), target='_blank', class_='merge-object')}
will be <strong>kept</strong>.&nbsp; The one which is to be kept may also
be updated to reflect certain aspects of the one being deleted; however again
the details are up to the app logic for this type of merge and aren't fully
known to the generic tool which you're using now.
</p>
<table class="diff">
<thead>
<tr>
<th>field name</th>
<th>deleting ${model_title}</th>
<th>keeping ${model_title}</th>
<th>resulting ${model_title}</th>
</tr>
</thead>
<tbody>
% for field in sorted(merge_fields):
<tr${' class="diff"' if keep_data[field] != remove_data[field] else ''|n}>
<td class="field">${field}</td>
<td class="value remove-value">${repr(remove_data[field])}</td>
<td class="value keep-value">${repr(keep_data[field])}</td>
<td class="value result-value${' diff' if resulting_data[field] != keep_data[field] else ''}">${repr(resulting_data[field])}</td>
</tr>
% endfor
</tbody>
</table>
<table class="diff">
<thead>
<tr>
<th>field name</th>
<th>deleting ${model_title}</th>
<th>keeping ${model_title}</th>
<th>resulting ${model_title}</th>
</tr>
</thead>
<tbody>
% for field in sorted(merge_fields):
<tr${' class="diff"' if keep_data[field] != remove_data[field] else ''|n}>
<td class="field">${field}</td>
<td class="value remove-value">${repr(remove_data[field])}</td>
<td class="value keep-value">${repr(keep_data[field])}</td>
<td class="value result-value${' diff' if resulting_data[field] != keep_data[field] else ''}">${repr(resulting_data[field])}</td>
</tr>
% endfor
</tbody>
</table>
% if use_buefy:
<merge-buttons></merge-buttons>
% else:
## no buefy; do legacy stuff
${h.form(request.current_route_url(), class_='merge')}
${h.csrf_token(request)}
<div class="buttons">
${h.hidden('uuids', value='{},{}'.format(object_to_remove.uuid, object_to_keep.uuid))}
<a class="button" href="${index_url}">Whoops, nevermind</a>
<button type="button" class="swap">Swap which ${model_title} is kept/removed</button>
${h.submit('merge', "Yes, perform this merge")}
</div>
${h.end_form()}
% endif
<merge-buttons></merge-buttons>
</%def>
<%def name="render_this_page_template()">
@ -177,11 +132,7 @@ ${h.end_form()}
</div>
<div class="level-item">
% if use_buefy:
${h.form(request.current_route_url(), **{'@submit': 'submitMergeForm'})}
% else:
${h.form(request.current_route_url())}
% endif
${h.csrf_token(request)}
${h.hidden('uuids', value='{},{}'.format(object_to_remove.uuid, object_to_keep.uuid))}
${h.hidden('commit-merge', value='yes')}

View file

@ -46,12 +46,8 @@
</%def>
<%def name="page_content()">
% if use_buefy:
<tailbone-grid :csrftoken="csrftoken">
</tailbone-grid>
% else:
${grid.render_complete()|n}
% endif
<tailbone-grid :csrftoken="csrftoken">
</tailbone-grid>
</%def>
${parent.body()}

View file

@ -3,46 +3,6 @@
<%def name="title()">${index_title} &raquo; ${instance_title}</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
% if master.deletable and instance_deletable and request.has_perm('{}.delete'.format(permission_prefix)) and master.delete_confirm == 'simple':
<script type="text/javascript">
$(function () {
$('#context-menu a.delete-instance').on('click', function() {
if (confirm("Are you sure you wish to delete this ${model_title}?")) {
$(this).parents('form').submit();
}
return false;
});
});
</script>
% endif
% if master.has_rows:
<script type="text/javascript">
$(function() {
$('.grid-wrapper').gridwrapper();
});
</script>
% endif
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if master.has_rows and not use_buefy:
<style type="text/css">
.grid-wrapper {
margin-top: 10px;
}
</style>
% endif
</%def>
<%def name="content_title()">
${instance_title}
</%def>
@ -54,33 +14,19 @@
<%def name="render_xref_helper()">
% if xref_buttons or xref_links:
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Cross-Reference</p>
<div class="panel-block buttons">
<div style="display: flex; flex-direction: column;">
% for button in xref_buttons:
${button}
% endfor
% for link in xref_links:
${link}
% endfor
</div>
</div>
</nav>
% else:
<div class="object-helper">
<h3>Cross-Reference</h3>
<div class="object-helper-content">
% for button in xref_buttons:
${button}
% endfor
% for link in xref_links:
${link}
% endfor
</div>
<nav class="panel">
<p class="panel-heading">Cross-Reference</p>
<div class="panel-block buttons">
<div style="display: flex; flex-direction: column;">
% for button in xref_buttons:
${button}
% endfor
% for link in xref_links:
${link}
% endfor
</div>
% endif
</div>
</nav>
% endif
</%def>
@ -91,63 +37,37 @@
% if master.has_versions and request.rattail_config.versioning_enabled() and request.has_perm('{}.versions'.format(permission_prefix)):
<li>${h.link_to("Version History", action_url('versions', instance))}</li>
% endif
% if not use_buefy and master.editable and instance_editable and master.has_perm('edit'):
<li>${h.link_to("Edit this {}".format(model_title), action_url('edit', instance))}</li>
% endif
${self.context_menu_item_delete()}
% if not use_buefy and master.creatable and master.show_create_link and master.has_perm('create'):
% if master.creates_multiple:
<li>${h.link_to("Create new {}".format(model_title_plural), url('{}.create'.format(route_prefix)))}</li>
% else:
<li>${h.link_to("Create a new {}".format(model_title), url('{}.create'.format(route_prefix)))}</li>
% endif
% endif
% if not use_buefy and master.cloneable and master.has_perm('clone'):
<li>${h.link_to("Clone this as new {}".format(model_title), url('{}.clone'.format(route_prefix), uuid=instance.uuid))}</li>
% endif
% if master.touchable and request.has_perm('{}.touch'.format(permission_prefix)):
<li>${h.link_to("\"Touch\" this {}".format(model_title), master.get_action_url('touch', instance))}</li>
% endif
% if not use_buefy and master.has_rows and master.rows_downloadable_csv and master.has_perm('row_results_csv'):
<li>${h.link_to("Download row results as CSV", master.get_action_url('row_results_csv', instance))}</li>
% endif
% if not use_buefy and master.has_rows and master.rows_downloadable_xlsx and master.has_perm('row_results_xlsx'):
<li>${h.link_to("Download row results as XLSX", master.get_action_url('row_results_xlsx', instance))}</li>
% endif
</%def>
<%def name="render_row_grid_tools()">
${rows_grid_tools}
% if use_buefy:
% if master.rows_downloadable_xlsx and master.has_perm('row_results_xlsx'):
<b-button tag="a" href="${master.get_action_url('row_results_xlsx', instance)}"
icon-pack="fas"
icon-left="download">
Download Results XLSX
</b-button>
% endif
% if master.rows_downloadable_csv and master.has_perm('row_results_csv'):
<b-button tag="a" href="${master.get_action_url('row_results_csv', instance)}"
icon-pack="fas"
icon-left="download">
Download Results CSV
</b-button>
% endif
% if master.rows_downloadable_xlsx and master.has_perm('row_results_xlsx'):
<b-button tag="a" href="${master.get_action_url('row_results_xlsx', instance)}"
icon-pack="fas"
icon-left="download">
Download Results XLSX
</b-button>
% endif
% if master.rows_downloadable_csv and master.has_perm('row_results_csv'):
<b-button tag="a" href="${master.get_action_url('row_results_csv', instance)}"
icon-pack="fas"
icon-left="download">
Download Results CSV
</b-button>
% endif
</%def>
<%def name="render_this_page()">
${parent.render_this_page()}
% if master.has_rows:
% if use_buefy:
<br />
% if rows_title:
<h4 class="block is-size-4">${rows_title}</h4>
% endif
${self.render_row_grid_component()}
% else:
${rows_grid|n}
<br />
% if rows_title:
<h4 class="block is-size-4">${rows_title}</h4>
% endif
${self.render_row_grid_component()}
% endif
</%def>

View file

@ -12,9 +12,6 @@
% if master.rows_editable and instance_editable and request.has_perm('{}.edit'.format(permission_prefix)):
<li>${h.link_to("Edit this {}".format(model_title), action_url('edit', instance))}</li>
% endif
% if not use_buefy and instance_deletable and master.has_perm('delete_row'):
<li>${h.link_to("Delete this {}".format(model_title), action_url('delete', instance))}</li>
% endif
% if rows_creatable and request.has_perm('{}.create'.format(permission_prefix)):
<li>${h.link_to("Create a new {}".format(model_title), url('{}.create'.format(route_prefix)))}</li>
% endif

View file

@ -3,15 +3,6 @@
<%def name="title()">Message Archive</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
destination = "Inbox";
</script>
% endif
</%def>
<%def name="context_menu_items()">
${parent.context_menu_items()}
<li>${h.link_to("Go to my Message Inbox", url('messages.inbox'))}</li>

View file

@ -2,148 +2,26 @@
<%inherit file="/master/create.mako" />
<%namespace file="/messages/recipients.mako" import="message_recipients_template" />
<%def name="content_title()">${parent.content_title() if not use_buefy else ''}</%def>
<%def name="content_title()"></%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if use_buefy:
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.message_recipients.js'))}
% else:
${h.javascript_link(request.static_url('tailbone:static/js/lib/tag-it.min.js'))}
<script type="text/javascript">
var recipient_mappings = new Map([
<% last = len(available_recipients) %>
% for i, recip in enumerate(available_recipients, 1):
<% uuid, entry = recip %>
['${uuid}', ${json.dumps(entry)|n}]${',' if i < last else ''}
% endfor
]);
// validate message before sending
function validate_message_form() {
var form = $('#deform');
if (! form.find('input[name="set_recipients"]').val()) {
alert("You must specify some recipient(s) for the message.");
$('.set_recipients input').data('ui-tagit').tagInput.focus();
return false;
}
if (! form.find('input[name="subject"]').val()) {
alert("You must provide a subject for the message.");
form.find('input[name="subject"]').focus();
return false;
}
return true;
}
$(function() {
var recipients = $('.set_recipients input');
recipients.tagit({
autocomplete: {
delay: 0,
minLength: 2,
autoFocus: true,
removeConfirmation: true,
source: function(request, response) {
var term = request.term.toLowerCase();
var data = [];
recipient_mappings.forEach(function(name, uuid) {
if (!name.toLowerCase && name.name) {
name = name.name;
}
if (name.toLowerCase().indexOf(term) >= 0) {
data.push({value: uuid, label: name});
}
});
response(data);
}
},
beforeTagAdded: ${self.before_tag_added()},
beforeTagRemoved: function(event, ui) {
// Unfortunately we're responsible for cleaning up the hidden
// field, since the values there do not match the tag labels.
var tags = recipients.tagit('assignedTags');
var uuid = ui.tag.data('uuid');
tags = tags.filter(function(element) {
return element != uuid;
});
recipients.data('ui-tagit')._updateSingleTagsField(tags);
}
});
// set focus to recipients field
recipients.data('ui-tagit').tagInput.focus();
});
</script>
${self.validate_message_js()}
% endif
</%def>
<%def name="validate_message_js()">
<script type="text/javascript">
$(function() {
$('#new-message').submit(function() {
return validate_message_form();
});
});
</script>
${h.javascript_link(request.static_url('tailbone:static/js/tailbone.buefy.message_recipients.js'))}
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if use_buefy:
<style type="text/css">
.this-page-content {
width: 100%;
}
.this-page-content .buttons {
margin-left: 20rem;
}
</style>
% else:
${h.stylesheet_link(request.static_url('tailbone:static/css/jquery.tagit.css'))}
<style type="text/css">
.recipients input {
min-width: 525px;
.this-page-content {
width: 100%;
}
.subject input {
min-width: 540px;
}
.body textarea {
min-width: 540px;
.this-page-content .buttons {
margin-left: 20rem;
}
</style>
% endif
</%def>
<%def name="before_tag_added()">
function(event, ui) {
// Lookup the name in cached mapping, and show that on the tag, instead
// of the UUID. The tagit widget should take care of keeping the
// hidden field in sync for us, still using the UUID.
var uuid = ui.tagLabel;
var name = recipient_mappings.get(uuid);
ui.tag.find('.tagit-label').html(name);
}
</%def>
<%def name="context_menu_items()">

View file

@ -3,15 +3,6 @@
<%def name="title()">Message Inbox</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
destination = "Archive";
</script>
% endif
</%def>
<%def name="context_menu_items()">
${parent.context_menu_items()}
<li>${h.link_to("Go to my Message Archive", url('messages.archive'))}</li>

View file

@ -1,52 +1,6 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/index.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
var destination = null;
function update_move_button() {
var count = $('.grid tr:not(.header) td.checkbox input:checked').length;
$('form[name="move-selected"] button')
.button('option', 'label', "Move " + count + " selected to " + destination)
.button('option', 'disabled', count < 1);
}
$(function() {
update_move_button();
$('.grid-wrapper').on('change', 'tr.header td.checkbox input', function() {
update_move_button();
});
$('.grid-wrapper').on('click', 'tr:not(.header) td.checkbox input', function() {
update_move_button();
});
$('form[name="move-selected"]').submit(function() {
var uuids = [];
$('.grid tr:not(.header) td.checkbox input:checked').each(function() {
uuids.push($(this).parents('tr:first').data('uuid'));
});
if (! uuids.length) {
return false;
}
$(this).find('[name="uuids"]').val(uuids.toString());
$(this).find('button')
.button('option', 'label', "Moving " + uuids.length + " messages to " + destination + "...")
.button('disable');
});
});
</script>
% endif
</%def>
<%def name="context_menu_items()">
% if request.has_perm('messages.create'):
<li>${h.link_to("Send a new Message", url('messages.create'))}</li>
@ -55,25 +9,16 @@
<%def name="grid_tools()">
% if request.matched_route.name in ('messages.inbox', 'messages.archive'):
% if use_buefy:
${h.form(url('messages.move_bulk'), **{'@submit': 'moveMessagesSubmit'})}
${h.csrf_token(request)}
${h.hidden('destination', value='archive' if request.matched_route.name == 'messages.inbox' else 'inbox')}
${h.hidden('uuids', v_model='selected_uuids')}
<b-button type="is-primary"
native-type="submit"
:disabled="moveMessagesSubmitting || !checkedRows.length">
{{ moveMessagesTextCurrent }}
</b-button>
${h.end_form()}
% else:
${h.form(url('messages.move_bulk'), name='move-selected')}
${h.csrf_token(request)}
${h.hidden('destination', value='archive' if request.matched_route.name == 'messages.inbox' else 'inbox')}
${h.hidden('uuids')}
<button type="submit">Move 0 selected to ${'Archive' if request.matched_route.name == 'messages.inbox' else 'Inbox'}</button>
${h.end_form()}
% endif
${h.form(url('messages.move_bulk'), **{'@submit': 'moveMessagesSubmit'})}
${h.csrf_token(request)}
${h.hidden('destination', value='archive' if request.matched_route.name == 'messages.inbox' else 'inbox')}
${h.hidden('uuids', v_model='selected_uuids')}
<b-button type="is-primary"
native-type="submit"
:disabled="moveMessagesSubmitting || !checkedRows.length">
{{ moveMessagesTextCurrent }}
</b-button>
${h.end_form()}
% endif
</%def>

View file

@ -1,66 +1,20 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('.field-wrapper.recipients .more').click(function() {
$(this).hide();
$(this).siblings('.everyone').css('display', 'inline-block');
return false;
});
$('.field-wrapper.recipients .everyone').click(function() {
$(this).hide();
$(this).siblings('.more').show();
});
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if use_buefy:
<style type="text/css">
.everyone {
cursor: pointer;
}
.tailbone-message-body {
margin: 1rem auto;
min-height: 10rem;
}
.tailbone-message-body p {
margin-bottom: 1rem;
}
</style>
% else:
<style type="text/css">
.recipients .everyone {
.everyone {
cursor: pointer;
display: none;
}
.message-tools {
margin-bottom: 15px;
.tailbone-message-body {
margin: 1rem auto;
min-height: 10rem;
}
.message-body {
border-top: 1px solid black;
border-bottom: 1px solid black;
margin-bottom: 15px;
padding: 0 5em;
white-space: pre-line;
}
.message-body p {
margin-bottom: 15px;
.tailbone-message-body p {
margin-bottom: 1rem;
}
</style>
% endif
</%def>
<%def name="context_menu_items()">
@ -86,43 +40,29 @@
<%def name="message_tools()">
% if recipient:
% if use_buefy:
<div class="buttons">
% if request.has_perm('messages.create'):
<once-button type="is-primary"
tag="a" href="${url('messages.reply', uuid=instance.uuid)}"
text="Reply">
</once-button>
<once-button type="is-primary"
tag="a" href="${url('messages.reply_all', uuid=instance.uuid)}"
text="Reply to All">
</once-button>
% endif
% if recipient.status == enum.MESSAGE_STATUS_INBOX:
<once-button type="is-primary"
tag="a" href="${url('messages.move', uuid=instance.uuid)}?dest=archive"
text="Move to Archive">
</once-button>
% else:
<once-button type="is-primary"
tag="a" href="${url('messages.move', uuid=instance.uuid)}?dest=inbox"
text="Move to Inbox">
</once-button>
% endif
</div>
% else:
<div class="message-tools">
% if request.has_perm('messages.create'):
${h.link_to("Reply", url('messages.reply', uuid=instance.uuid), class_='button')}
${h.link_to("Reply to All", url('messages.reply_all', uuid=instance.uuid), class_='button')}
% endif
% if recipient.status == enum.MESSAGE_STATUS_INBOX:
${h.link_to("Move to Archive", url('messages.move', uuid=instance.uuid) + '?dest=archive', class_='button')}
% else:
${h.link_to("Move to Inbox", url('messages.move', uuid=instance.uuid) + '?dest=inbox', class_='button')}
% endif
</div>
% endif
<div class="buttons">
% if request.has_perm('messages.create'):
<once-button type="is-primary"
tag="a" href="${url('messages.reply', uuid=instance.uuid)}"
text="Reply">
</once-button>
<once-button type="is-primary"
tag="a" href="${url('messages.reply_all', uuid=instance.uuid)}"
text="Reply to All">
</once-button>
% endif
% if recipient.status == enum.MESSAGE_STATUS_INBOX:
<once-button type="is-primary"
tag="a" href="${url('messages.move', uuid=instance.uuid)}?dest=archive"
text="Move to Archive">
</once-button>
% else:
<once-button type="is-primary"
tag="a" href="${url('messages.move', uuid=instance.uuid)}?dest=inbox"
text="Move to Inbox">
</once-button>
% endif
</div>
% endif
</%def>
@ -132,22 +72,14 @@
<%def name="page_content()">
${parent.page_content()}
% if use_buefy:
<br />
<div style="margin-left: 5rem;">
${self.message_tools()}
<div class="tailbone-message-body">
${self.message_body()}
</div>
${self.message_tools()}
</div>
% else:
${self.message_tools()}
<div class="message-body">
${self.message_body()}
</div>
${self.message_tools()}
% endif
<br />
<div style="margin-left: 5rem;">
${self.message_tools()}
<div class="tailbone-message-body">
${self.message_body()}
</div>
${self.message_tools()}
</div>
</%def>
<%def name="modify_this_page_vars()">

View file

@ -1,82 +1,6 @@
## -*- coding: utf-8; -*-
<%inherit file="/batch/create.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
${self.func_show_mode()}
<script type="text/javascript">
var purchases_field = '${purchases_field}';
var purchases = null; // TODO: where is this used?
function vendor_selected(uuid, name) {
## var mode = $('.mode select').val();
## if (mode == ${enum.PURCHASE_BATCH_MODE_RECEIVING} || mode == ${enum.PURCHASE_BATCH_MODE_COSTING}) {
## var purchases = $('.purchase_uuid select');
## purchases.empty();
##
## var data = {'vendor_uuid': uuid, 'mode': mode};
## $.get('${url('purchases.batch.eligible_purchases')}', data, function(data) {
## if (data.error) {
## alert(data.error);
## } else {
## $.each(data.purchases, function(i, purchase) {
## purchases.append($('<option value="' + purchase.key + '">' + purchase.display + '</option>'));
## });
## }
## });
##
## // TODO: apparently refresh doesn't work right?
## // http://stackoverflow.com/a/10280078
## // purchases.selectmenu('refresh');
## purchases.selectmenu('destroy').selectmenu();
## }
}
function vendor_cleared() {
var purchases = $('.purchase_uuid select');
purchases.empty();
// TODO: apparently refresh doesn't work right?
// http://stackoverflow.com/a/10280078
// purchases.selectmenu('refresh');
purchases.selectmenu('destroy').selectmenu();
}
$(function() {
$('.field-wrapper.mode select').selectmenu({
change: function(event, ui) {
show_mode(ui.item.value);
}
});
show_mode(${enum.PURCHASE_BATCH_MODE_ORDERING});
});
</script>
% endif
</%def>
<%def name="func_show_mode()">
<script type="text/javascript">
// TODO: mode is presumably null here..
function show_mode(mode) {
$('.field-wrapper.store_uuid').show();
$('.field-wrapper.' + purchases_field).hide();
$('.field-wrapper.department_uuid').show();
$('.field-wrapper.buyer_uuid').show();
$('.field-wrapper.date_ordered').show();
$('.field-wrapper.date_received').hide();
$('.field-wrapper.po_number').show();
$('.field-wrapper.invoice_date').hide();
$('.field-wrapper.invoice_number').hide();
}
</script>
</%def>
## TODO: deprecate / remove
${parent.body()}

View file

@ -3,63 +3,6 @@
<%def name="title()">Ordering Worksheet</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
${h.javascript_link(request.static_url('tailbone:static/js/numeric.js'))}
<script type="text/javascript">
var submitting = false;
$(function() {
$('.order-form td.current-order input').focus(function(event) {
$(this).parents('tr:first').addClass('active');
});
$('.order-form td.current-order input').blur(function(event) {
$(this).parents('tr:first').removeClass('active');
});
$('.order-form td.current-order input').keydown(function(event) {
if (key_allowed(event) || key_modifies(event)) {
return true;
}
if (event.which == 13) {
if (! submitting) {
submitting = true;
var row = $(this).parents('tr:first');
var form = $('#item-update-form');
form.find('[name="product_uuid"]').val(row.data('uuid'));
form.find('[name="cases_ordered"]').val(row.find('input[name^="cases_ordered_"]').val() || '0');
form.find('[name="units_ordered"]').val(row.find('input[name^="units_ordered_"]').val() || '0');
$.post(form.attr('action'), form.serialize(), function(data) {
if (data.error) {
alert(data.error);
} else {
if (data.row_cases_ordered || data.row_units_ordered) {
row.find('input[name^="cases_ordered_"]').val(data.row_cases_ordered);
row.find('input[name^="units_ordered_"]').val(data.row_units_ordered);
row.find('td.po-total').html(data.row_po_total_calculated);
} else {
row.find('input[name^="cases_ordered_"]').val('');
row.find('input[name^="units_ordered_"]').val('');
row.find('td.po-total').html('');
}
$('.po-total .field').html(data.batch_po_total_calculated);
}
submitting = false;
});
}
}
return false;
});
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
<style type="text/css">
@ -187,10 +130,7 @@
<tbody>
% for i, cost in enumerate(subdepartment._order_costs, 1):
<tr data-uuid="${cost.product_uuid}" class="${'even' if i % 2 == 0 else 'odd'}"
% if use_buefy:
:class="{active: activeUUID == '${cost.uuid}'}"
% endif
>
:class="{active: activeUUID == '${cost.uuid}'}">
${self.order_form_row(cost)}
% for data in history:
<td class="scratch_pad">
@ -216,34 +156,21 @@
% endfor
% if not ignore_cases:
<td class="current-order">
% if use_buefy:
<numeric-input v-model="worksheet.cost_${cost.uuid}_cases"
@focus="activeUUID = '${cost.uuid}'; $event.target.select()"
@blur="activeUUID = null"
@keydown.native="inputKeydown($event, '${cost.uuid}', '${cost.product_uuid}')">
</numeric-input>
% else:
${h.text('cases_ordered_{}'.format(cost.uuid), value=int(cost._batchrow.cases_ordered or 0) if cost._batchrow else None)}
% endif
</td>
% endif
<td class="current-order">
% if use_buefy:
<numeric-input v-model="worksheet.cost_${cost.uuid}_units"
<numeric-input v-model="worksheet.cost_${cost.uuid}_cases"
@focus="activeUUID = '${cost.uuid}'; $event.target.select()"
@blur="activeUUID = null"
@keydown.native="inputKeydown($event, '${cost.uuid}', '${cost.product_uuid}')">
</numeric-input>
% else:
${h.text('units_ordered_{}'.format(cost.uuid), value=int(cost._batchrow.units_ordered or 0) if cost._batchrow else None)}
% endif
</td>
## TODO: should not fall back to po_total
% if use_buefy:
<td class="po-total">{{ worksheet.cost_${cost.uuid}_total_display }}</td>
% else:
<td class="po-total">${'${:0,.2f}'.format(cost._batchrow.po_total_calculated or cost._batchrow.po_total or 0) if cost._batchrow else ''}</td>
</td>
% endif
<td class="current-order">
<numeric-input v-model="worksheet.cost_${cost.uuid}_units"
@focus="activeUUID = '${cost.uuid}'; $event.target.select()"
@blur="activeUUID = null"
@keydown.native="inputKeydown($event, '${cost.uuid}', '${cost.product_uuid}')">
</numeric-input>
</td>
<td class="po-total">{{ worksheet.cost_${cost.uuid}_total_display }}</td>
${self.extra_td(cost)}
</tr>
% endfor
@ -269,55 +196,7 @@
</%def>
<%def name="page_content()">
% if use_buefy:
<ordering-worksheet></ordering-worksheet>
% else:
<div class="form-wrapper">
<div class="field-wrapper">
<label>Vendor</label>
<div class="field">${h.link_to(vendor, url('vendors.view', uuid=vendor.uuid))}</div>
</div>
<div class="field-wrapper">
<label>Vendor Email</label>
<div class="field">${vendor.email or ''}</div>
</div>
<div class="field-wrapper">
<label>Vendor Fax</label>
<div class="field">${vendor.fax_number or ''}</div>
</div>
<div class="field-wrapper">
<label>Vendor Contact</label>
<div class="field">${vendor.contact or ''}</div>
</div>
<div class="field-wrapper">
<label>Vendor Phone</label>
<div class="field">${vendor.phone or ''}</div>
</div>
${self.extra_vendor_fields()}
<div class="field-wrapper po-total">
<label>PO Total</label>
## TODO: should not fall back to po_total
<div class="field">$${'{:0,.2f}'.format(batch.po_total_calculated or batch.po_total or 0)}</div>
</div>
</div><!-- form-wrapper -->
${self.order_form_grid()}
${h.form(url('ordering.worksheet_update', uuid=batch.uuid), id='item-update-form', style='display: none;')}
${h.csrf_token(request)}
${h.hidden('product_uuid')}
${h.hidden('cases_ordered')}
${h.hidden('units_ordered')}
${h.end_form()}
% endif
<ordering-worksheet></ordering-worksheet>
</%def>
<%def name="render_this_page_template()">

View file

@ -4,7 +4,6 @@
<%def name="grid_tools()">
% if master.mergeable and master.has_perm('request_merge'):
% if use_buefy:
<b-button @click="showMergeRequest()"
icon-pack="fas"
icon-left="object-ungroup"
@ -57,7 +56,6 @@
</footer>
</div>
</b-modal>
% endif
% endif
${parent.grid_tools()}

View file

@ -4,7 +4,6 @@
<%def name="page_content()">
${parent.page_content()}
% if not instance.merged and request.has_perm('people.merge'):
% if use_buefy:
${h.form(url('people.merge'), **{'@submit': 'submitMergeForm'})}
${h.csrf_token(request)}
${h.hidden('uuids', value=','.join([instance.removing_uuid, instance.keeping_uuid]))}
@ -16,7 +15,6 @@
{{ mergeFormButtonText }}
</b-button>
${h.end_form()}
% endif
% endif
</%def>

View file

@ -2,25 +2,6 @@
<%inherit file="/master/view.mako" />
<%namespace file="/util.mako" import="view_profiles_helper" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy and not instance.users and request.has_perm('users.create'):
<script type="text/javascript">
## TODO: should do this differently for Buefy themes
$(function() {
$('#make-user').click(function() {
if (confirm("Really make a user account for this person?")) {
% if not use_buefy:
disable_button(this);
% endif
$('form[name="make-user-form"]').submit();
}
});
});
</script>
% endif
</%def>
<%def name="object_helpers()">
${parent.object_helpers()}
${view_profiles_helper([instance])}
@ -52,11 +33,7 @@
<%def name="page_content()">
${parent.page_content()}
% if not instance.users and request.has_perm('users.create'):
% if use_buefy:
${h.form(url('people.make_user'), ref='makeUserForm')}
% else:
${h.form(url('people.make_user'), name='make-user-form')}
% endif
${h.form(url('people.make_user'), ref='makeUserForm')}
${h.csrf_token(request)}
${h.hidden('person_uuid', value=instance.uuid)}
${h.end_form()}

View file

@ -3,77 +3,10 @@
<%def name="title()">Find ${model_title_plural} by Permission</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
<% gcount = len(permissions) %>
var permissions_by_group = {
% for g, (gkey, group) in enumerate(permissions, 1):
<% pcount = len(group['perms']) %>
'${gkey}': {
% for p, (pkey, perm) in enumerate(group['perms'], 1):
'${pkey}': "${perm['label']}"${',' if p < pcount else ''}
% endfor
}${',' if g < gcount else ''}
% endfor
};
$(function() {
$('#permission_group').selectmenu({
change: function(event, ui) {
var perms = $('#permission');
perms.find('option:first').siblings('option').remove();
$.each(permissions_by_group[ui.item.value], function(key, label) {
perms.append($('<option value="' + key + '">' + label + '</option>'));
});
perms.selectmenu('refresh');
}
});
$('#permission').selectmenu();
$('#find-by-perm-form').submit(function() {
$('.grid').remove();
$(this).find('#submit').button('disable').button('option', 'label', "Searching, please wait...");
});
});
</script>
% endif
</%def>
<%def name="page_content()">
% if use_buefy:
<find-principals :permission-groups="permissionGroups"
:sorted-groups="sortedGroups">
</find-principals>
% else:
## not buefy
${h.form(request.current_route_url(), id='find-by-perm-form')}
${h.csrf_token(request)}
<div class="form">
${self.wtfield(form, 'permission_group')}
${self.wtfield(form, 'permission')}
<div class="buttons">
${h.submit('submit', "Find {}".format(model_title_plural))}
</div>
</div>
${h.end_form()}
% if principals is not None:
<div class="grid half">
<br />
<h2>${model_title_plural} with that permission (${len(principals)} total):</h2>
${self.principal_table()}
</div>
% endif
% endif
<find-principals :permission-groups="permissionGroups"
:sorted-groups="sortedGroups">
</find-principals>
</%def>
<%def name="render_this_page_template()">

View file

@ -7,66 +7,22 @@
<li>${h.link_to("Back to Products", url('products'))}</li>
</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('select[name="batch_type"]').on('selectmenuchange', function(event, ui) {
$('.params-wrapper').hide();
$('.params-wrapper.' + ui.item.value).show();
});
$('.params-wrapper.' + $('select[name="batch_type"]').val()).show();
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if not use_buefy:
<style type="text/css">
.params-wrapper {
display: none;
}
</style>
% endif
</%def>
<%def name="render_deform_field(form, field)">
% if use_buefy:
<b-field horizontal
% if field.description:
message="${field.description}"
% endif
% if field.error:
type="is-danger"
:message='${form.messages_json(field.error.messages())|n}'
% endif
label="${field.title}">
${field.serialize(use_buefy=True)|n}
</b-field>
% else:
<div class="field-wrapper ${field.name}">
<div class="field-row">
<label for="${field.oid}">${field.title}</label>
<div class="field">
${field.serialize()|n}
</div>
</div>
</div>
% endif
<b-field horizontal
% if field.description:
message="${field.description}"
% endif
% if field.error:
type="is-danger"
:message='${form.messages_json(field.error.messages())|n}'
% endif
label="${field.title}">
${field.serialize()|n}
</b-field>
</%def>
<%def name="render_form_innards()">
% if use_buefy:
${h.form(request.current_route_url(), **{'@submit': 'submit{}'.format(form.component_studly)})}
% else:
${h.form(request.current_route_url(), class_='autodisable')}
% endif
${h.csrf_token(request)}
<section>
@ -75,53 +31,33 @@
${render_deform_field(form, dform['notes'])}
% for key, pform in six.iteritems(params_forms):
% if use_buefy:
<div v-show="field_model_batch_type == '${key}'">
% for field in pform.make_deform_form():
${render_deform_field(pform, field)}
% endfor
</div>
% else:
<div class="params-wrapper ${key}">
## TODO: hacky to use deform? at least is explicit..
% for field in pform.make_deform_form():
${render_deform_field(pform, field)}
% endfor
</div>
% endif
<div v-show="field_model_batch_type == '${key}'">
% for field in pform.make_deform_form():
${render_deform_field(pform, field)}
% endfor
</div>
% endfor
</section>
<br />
<div class="buttons">
% if use_buefy:
<b-button type="is-primary"
native-type="submit"
:disabled="${form.component_studly}Submitting">
{{ ${form.component_studly}ButtonText }}
</b-button>
<b-button tag="a" href="${url('products')}">
Cancel
</b-button>
% else:
${h.submit('make-batch', "Create Batch")}
${h.link_to("Cancel", url('products'), class_='button')}
% endif
<b-button type="is-primary"
native-type="submit"
:disabled="${form.component_studly}Submitting">
{{ ${form.component_studly}ButtonText }}
</b-button>
<b-button tag="a" href="${url('products')}">
Cancel
</b-button>
</div>
${h.end_form()}
</%def>
<%def name="render_form()">
% if use_buefy:
<script type="text/x-template" id="${form.component}-template">
${self.render_form_innards()}
</script>
% else:
<div class="form">
${self.render_form_innards()}
</div>
% endif
<script type="text/x-template" id="${form.component}-template">
${self.render_form_innards()}
</script>
</%def>
<%def name="modify_this_page_vars()">

View file

@ -1,133 +1,26 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/index.mako" />
<%def name="extra_styles()">
${parent.extra_styles()}
% if not use_buefy:
<style type="text/css">
table.label-printing th {
font-weight: normal;
padding: 0px 0px 2px 4px;
text-align: left;
}
table.label-printing td {
padding: 0px 0px 0px 4px;
}
table.label-printing #label-quantity {
text-align: right;
width: 30px;
}
div.grid table tbody td.size,
div.grid table tbody td.regular_price_uuid,
div.grid table tbody td.current_price_uuid {
padding-right: 6px;
text-align: right;
}
div.grid table tbody td.labels {
text-align: center;
}
</style>
% endif
</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy and label_profiles and master.has_perm('print_labels'):
<script type="text/javascript">
$(function() {
$('.grid-wrapper .grid-header .tools select').selectmenu();
$('.grid-wrapper').on('click', 'a.print_label', function() {
var tr = $(this).parents('tr:first');
var quantity = $('table.label-printing #label-quantity');
if (isNaN(quantity.val())) {
alert("You must provide a valid label quantity.");
quantity.select();
quantity.focus();
} else {
quantity = quantity.val();
var threshold = ${json.dumps(quick_label_speedbump_threshold)|n};
if (threshold && parseInt(quantity) >= threshold) {
if (!confirm("Are you sure you want to print " + quantity + " labels?")) {
return false;
}
}
var data = {
product: tr.data('uuid'),
profile: $('#label-profile').val(),
quantity: quantity
};
$.get('${url('products.print_labels')}', data, function(data) {
if (data.error) {
alert("An error occurred while attempting to print:\n\n" + data.error);
} else if (quantity == '1') {
alert("1 label has been printed.");
} else {
alert(quantity + " labels have been printed.");
}
});
}
return false;
});
});
</script>
% endif
</%def>
<%def name="grid_tools()">
${parent.grid_tools()}
% if label_profiles and master.has_perm('print_labels'):
% if use_buefy:
<b-field grouped>
<b-field label="Label">
<b-select v-model="quickLabelProfile">
% for profile in label_profiles:
<option value="${profile.uuid}">
${profile.description}
</option>
% endfor
</b-select>
</b-field>
<b-field label="Qty.">
<b-input v-model="quickLabelQuantity"
ref="quickLabelQuantityInput"
style="width: 4rem;">
</b-input>
</b-field>
</b-field>
% else:
<table class="label-printing">
<thead>
<tr>
<th>Label</th>
<th>Qty.</th>
</tr>
</thead>
<tbody>
<td>
<select name="label-profile" id="label-profile">
% for profile in label_profiles:
<option value="${profile.uuid}">${profile.description}</option>
% endfor
</select>
</td>
<td>
<input type="text" name="label-quantity" id="label-quantity" value="1" />
</td>
</tbody>
</table>
% endif
<b-field grouped>
<b-field label="Label">
<b-select v-model="quickLabelProfile">
% for profile in label_profiles:
<option value="${profile.uuid}">
${profile.description}
</option>
% endfor
</b-select>
</b-field>
<b-field label="Qty.">
<b-input v-model="quickLabelQuantity"
ref="quickLabelQuantityInput"
style="width: 4rem;">
</b-input>
</b-field>
</b-field>
% endif
</%def>

View file

@ -1,94 +1,16 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy and request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<script type="text/javascript">
function showPriceHistory(typ) {
var dialog = $('#' + typ + '-price-history-dialog');
dialog.dialog({
title: typ[0].toUpperCase() + typ.slice(1) + " Price History",
width: 600,
height: 300,
modal: true,
buttons: [
{
text: "Close",
click: function() {
dialog.dialog('close');
}
}
]
});
}
function showCostHistory() {
var dialog = $('#cost-history-dialog');
dialog.dialog({
title: "Cost History",
width: 600,
height: 300,
modal: true,
buttons: [
{
text: "Close",
click: function() {
dialog.dialog('close');
}
}
]
});
}
$(function() {
$('#view-regular-price-history').on('click', function() {
showPriceHistory('regular');
return false;
});
$('#view-current-price-history').on('click', function() {
showPriceHistory('current');
return false;
});
$('#view-suggested-price-history').on('click', function() {
showPriceHistory('suggested');
return false;
});
$('#view-cost-history').on('click', function() {
showCostHistory();
return false;
});
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
<style type="text/css">
% if use_buefy:
#main-product-panel {
margin-right: 2em;
margin-top: 1em;
}
#pricing-panel .field-wrapper .field {
white-space: nowrap;
}
% else:
.price-history-dialog {
display: none;
}
.price-history-dialog .grid {
color: black;
}
% endif
#main-product-panel {
margin-right: 2em;
margin-top: 1em;
}
#pricing-panel .field-wrapper .field {
white-space: nowrap;
}
</style>
</%def>
@ -100,37 +22,22 @@
</%def>
<%def name="left_column()">
% if use_buefy:
<nav class="panel" id="pricing-panel">
<p class="panel-heading">Pricing</p>
<div class="panel-block">
<div>
${self.render_price_fields(form)}
</div>
</div>
</nav>
<nav class="panel">
<p class="panel-heading">Flags</p>
<div class="panel-block">
<div>
${self.render_flag_fields(form)}
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Pricing</h2>
<div class="panel-body">
${self.render_price_fields(form)}
<nav class="panel" id="pricing-panel">
<p class="panel-heading">Pricing</p>
<div class="panel-block">
<div>
${self.render_price_fields(form)}
</div>
</div>
</div>
<div class="panel">
<h2>Flags</h2>
<div class="panel-body">
${self.render_flag_fields(form)}
</nav>
<nav class="panel">
<p class="panel-heading">Flags</p>
<div class="panel-block">
<div>
${self.render_flag_fields(form)}
</div>
</div>
</div>
% endif
</nav>
${self.extra_left_panels()}
</%def>
@ -147,23 +54,14 @@
<%def name="extra_main_fields(form)"></%def>
<%def name="organization_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Organization</p>
<div class="panel-block">
<div>
${self.render_organization_fields(form)}
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Organization</h2>
<div class="panel-body">
${self.render_organization_fields(form)}
<nav class="panel">
<p class="panel-heading">Organization</p>
<div class="panel-block">
<div>
${self.render_organization_fields(form)}
</div>
</div>
</div>
% endif
</nav>
</%def>
<%def name="render_organization_fields(form)">
@ -195,23 +93,14 @@
</%def>
<%def name="movement_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Movement</p>
<div class="panel-block">
<div>
${self.render_movement_fields(form)}
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Movement</h2>
<div class="panel-body">
${self.render_movement_fields(form)}
<nav class="panel">
<p class="panel-heading">Movement</p>
<div class="panel-block">
<div>
${self.render_movement_fields(form)}
</div>
</div>
</div>
% endif
</nav>
</%def>
<%def name="render_movement_fields(form)">
@ -219,9 +108,7 @@
</%def>
<%def name="lookup_codes_grid()">
% if use_buefy:
${lookup_codes['grid'].render_buefy_table_element(data_prop='lookupCodesData')|n}
% else:
${lookup_codes['grid'].render_buefy_table_element(data_prop='lookupCodesData')|n}
<div class="grid full no-border">
<table>
<thead>
@ -238,29 +125,19 @@
</tbody>
</table>
</div>
% endif
</%def>
<%def name="lookup_codes_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Additional Lookup Codes</p>
<div class="panel-block">
${self.lookup_codes_grid()}
</div>
</nav>
% else:
<div class="panel-grid" id="product-codes">
<h2>Additional Lookup Codes</h2>
${self.lookup_codes_grid()}
</div>
% endif
<nav class="panel">
<p class="panel-heading">Additional Lookup Codes</p>
<div class="panel-block">
${self.lookup_codes_grid()}
</div>
</nav>
</%def>
<%def name="sources_grid()">
% if use_buefy:
${vendor_sources['grid'].render_buefy_table_element(data_prop='vendorSourcesData')|n}
% else:
${vendor_sources['grid'].render_buefy_table_element(data_prop='vendorSourcesData')|n}
<div class="grid full no-border">
<table>
<thead>
@ -293,71 +170,40 @@
</tbody>
</table>
</div>
% endif
</%def>
<%def name="sources_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">
Vendor Sources
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<a href="#" @click.prevent="showCostHistory()">
(view cost history)
</a>
% endif
</p>
<div class="panel-block">
${self.sources_grid()}
</div>
</nav>
% else:
<div class="panel-grid" id="product-costs">
<h2>
<nav class="panel">
<p class="panel-heading">
Vendor Sources
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<a id="view-cost-history" href="#">(view cost history)</a>
<a href="#" @click.prevent="showCostHistory()">
(view cost history)
</a>
% endif
</h2>
${self.sources_grid()}
</div>
% endif
</p>
<div class="panel-block">
${self.sources_grid()}
</div>
</nav>
</%def>
<%def name="notes_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Notes</p>
<div class="panel-block">
<div class="field">${form.render_field_readonly('notes')}</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Notes</h2>
<div class="panel-body">
<nav class="panel">
<p class="panel-heading">Notes</p>
<div class="panel-block">
<div class="field">${form.render_field_readonly('notes')}</div>
</div>
</div>
% endif
</nav>
</%def>
<%def name="ingredients_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Ingredients</p>
<div class="panel-block">
${form.render_field_readonly('ingredients')}
</div>
</nav>
% else:
<div class="panel">
<h2>Ingredients</h2>
<div class="panel-body">
<nav class="panel">
<p class="panel-heading">Ingredients</p>
<div class="panel-block">
${form.render_field_readonly('ingredients')}
</div>
</div>
% endif
</nav>
</%def>
<%def name="extra_left_panels()"></%def>
@ -366,7 +212,7 @@
<%def name="render_this_page()">
${parent.render_this_page()}
% if use_buefy and request.rattail_config.versioning_enabled() and master.has_perm('versions'):
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<b-modal :active.sync="showingPriceHistory_regular"
has-modal-card>
@ -447,83 +293,34 @@
</%def>
<%def name="page_content()">
% if use_buefy:
<div style="display: flex; flex-direction: column;">
<nav class="panel" id="main-product-panel">
<p class="panel-heading">Product</p>
<div class="panel-block">
<div style="display: flex; justify-content: space-between; width: 100%;">
<div>
${self.render_main_fields(form)}
</div>
<div>
% if image_url:
${h.image(image_url, "Product Image", id='product-image', width=150, height=150)}
% endif
</div>
</div>
</div>
</nav>
<div style="display: flex;">
<div class="panel-wrapper"> <!-- left column -->
${self.left_column()}
</div> <!-- left column -->
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div> <!-- right column -->
</div>
<nav class="panel" id="main-product-panel">
<p class="panel-heading">Product</p>
<div class="panel-block">
<div style="display: flex; justify-content: space-between; width: 100%;">
<div>
${self.render_main_fields(form)}
</div>
% else:
## legacy / not buefy
<div style="display: flex; flex-direction: column;">
<div class="panel" id="product-main">
<h2>Product</h2>
<div class="panel-body">
<div style="display: flex; justify-content: space-between;">
<div>
${self.render_main_fields(form)}
</div>
<div>
% if image_url:
${h.image(image_url, "Product Image", id='product-image', width=150, height=150)}
% endif
</div>
</div>
</div>
<div>
% if image_url:
${h.image(image_url, "Product Image", id='product-image', width=150, height=150)}
% endif
</div>
<div style="display: flex;">
<div class="panel-wrapper"> <!-- left column -->
${self.left_column()}
</div> <!-- left column -->
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div> <!-- right column -->
</div>
</div>
</div>
</nav>
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<div class="price-history-dialog" id="regular-price-history-dialog">
${regular_price_history_grid.render_grid()|n}
</div>
<div class="price-history-dialog" id="current-price-history-dialog">
${current_price_history_grid.render_grid()|n}
</div>
<div class="price-history-dialog" id="suggested-price-history-dialog">
${suggested_price_history_grid.render_grid()|n}
</div>
<div class="price-history-dialog" id="cost-history-dialog">
${cost_history_grid.render_grid()|n}
</div>
% endif
% endif
<div style="display: flex;">
<div class="panel-wrapper"> <!-- left column -->
${self.left_column()}
</div> <!-- left column -->
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div> <!-- right column -->
</div>
</div>
% if buttons:
${buttons|n}

View file

@ -1,468 +0,0 @@
## -*- coding: utf-8 -*-
<%inherit file="/base.mako" />
<%def name="title()">Receiving Form (${batch.vendor})</%def>
<%def name="head_tags()">
${parent.head_tags()}
${h.javascript_link(request.static_url('tailbone:static/js/numeric.js'))}
<script type="text/javascript">
function assert_quantity() {
if ($('#cases').val() && parseFloat($('#cases').val())) {
return true;
}
if ($('#units').val() && parseFloat($('#units').val())) {
return true;
}
alert("Please provide case and/or unit quantity");
$('#cases').select().focus();
return false;
}
function invalid_product(msg) {
$('#received-product-info p').text(msg);
$('#received-product-info img').hide();
$('#upc').focus().select();
$('.field-wrapper.cases input').prop('disabled', true);
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
}
function pretty_quantity(cases, units) {
if (cases && units) {
return cases + " cases, " + units + " units";
} else if (cases) {
return cases + " cases";
} else if (units) {
return units + " units";
}
return '';
}
function show_quantity(name, cases, units) {
var quantity = pretty_quantity(cases, units);
var field = $('.field-wrapper.quantity_' + name);
field.find('.field').text(quantity);
if (quantity || name == 'ordered') {
field.show();
} else {
field.hide();
}
}
$(function() {
$('#upc').keydown(function(event) {
if (key_allowed(event)) {
return true;
}
if (key_modifies(event)) {
$('#product').val('');
$('#received-product-info p').html("please ENTER a scancode");
$('#received-product-info img').hide();
$('#received-product-info .warning').hide();
$('.product-fields').hide();
$('.receiving-fields').hide();
$('.field-wrapper.cases input').prop('disabled', true);
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
return true;
}
// when user presses ENTER, do product lookup
if (event.which == 13) {
var upc = $(this).val();
var data = {'upc': upc};
$.get('${url('purchases.batch.receiving_lookup', uuid=batch.uuid)}', data, function(data) {
if (data.error) {
alert(data.error);
if (data.redirect) {
$('#receiving-form').mask("Redirecting...");
location.href = data.redirect;
}
} else if (data.product) {
$('#upc').val(data.product.upc_pretty);
$('#product').val(data.product.uuid);
$('#brand_name').val(data.product.brand_name);
$('#description').val(data.product.description);
$('#size').val(data.product.size);
$('#case_quantity').val(data.product.case_quantity);
$('#received-product-info p').text(data.product.full_description);
$('#received-product-info img').attr('src', data.product.image_url).show();
if (! data.product.uuid) {
// $('#received-product-info .warning.notfound').show();
$('.product-fields').show();
}
if (data.product.found_in_batch) {
show_quantity('ordered', data.product.cases_ordered, data.product.units_ordered);
show_quantity('received', data.product.cases_received, data.product.units_received);
show_quantity('damaged', data.product.cases_damaged, data.product.units_damaged);
show_quantity('expired', data.product.cases_expired, data.product.units_expired);
show_quantity('mispick', data.product.cases_mispick, data.product.units_mispick);
$('.receiving-fields').show();
} else {
$('#received-product-info .warning.notordered').show();
}
$('.field-wrapper.cases input').prop('disabled', false);
$('.field-wrapper.units input').prop('disabled', false);
$('.buttons button').button('enable');
$('#cases').focus().select();
} else if (data.upc) {
$('#upc').val(data.upc_pretty);
$('#received-product-info p').text("product not found in our system");
$('#received-product-info img').attr('src', data.image_url).show();
$('#product').val('');
$('#brand_name').val('');
$('#description').val('');
$('#size').val('');
$('#case_quantity').val('');
$('#received-product-info .warning.notfound').show();
$('.product-fields').show();
$('#brand_name').focus();
$('.field-wrapper.cases input').prop('disabled', false);
$('.field-wrapper.units input').prop('disabled', false);
$('.buttons button').button('enable');
} else {
invalid_product('product not found');
}
});
}
return false;
});
$('#received').click(function() {
if (! assert_quantity()) {
return;
}
$(this).button('disable').button('option', 'label', "Working...");
$('#mode').val('received');
$('#receiving-form').submit();
});
$('#damaged').click(function() {
if (! assert_quantity()) {
return;
}
$(this).button('disable').button('option', 'label', "Working...");
$('#mode').val('damaged');
$('#damaged-dialog').dialog({
title: "Damaged Product",
modal: true,
width: '500px',
buttons: [
{
text: "OK",
click: function() {
$('#damaged-dialog').dialog('close');
$('#receiving-form #trash').val($('#damaged-dialog #trash').is(':checked') ? '1' : '');
$('#receiving-form').submit();
}
},
{
text: "Cancel",
click: function() {
$('#damaged').button('option', 'label', "Damaged").button('enable');
$('#damaged-dialog').dialog('close');
}
}
]
});
});
$('#expiration input[type="date"]').datepicker();
$('#expired').click(function() {
if (! assert_quantity()) {
return;
}
$(this).button('disable').button('option', 'label', "Working...");
$('#mode').val('expired');
$('#expiration').dialog({
title: "Expired / Short Date",
modal: true,
width: '500px',
buttons: [
{
text: "OK",
click: function() {
$('#expiration').dialog('close');
$('#receiving-form #expiration_date').val(
$('#expiration input[type="date"]').val());
$('#receiving-form #trash').val($('#expiration #trash').is(':checked') ? '1' : '');
$('#receiving-form').submit();
}
},
{
text: "Cancel",
click: function() {
$('#expired').button('option', 'label', "Expired").button('enable');
$('#expiration').dialog('close');
}
}
]
});
});
$('#mispick').click(function() {
if (! assert_quantity()) {
return;
}
$(this).button('disable').button('option', 'label', "Working...");
$('#ordered-product').val('');
$('#ordered-product-textbox').val('');
$('#ordered-product-info p').html("please ENTER a scancode");
$('#ordered-product-info img').hide();
$('#mispick-dialog').dialog({
title: "Mispick - Ordered Product",
modal: true,
width: 400,
buttons: [
{
text: "OK",
click: function() {
if ($('#ordered-product-info .warning').is(':visible')) {
alert("You must choose a product which was ordered.");
$('#ordered-product-textbox').select().focus();
return;
}
$('#mispick-dialog').dialog('close');
$('#mode').val('mispick');
$('#receiving-form').submit();
}
},
{
text: "Cancel",
click: function() {
$('#mispick').button('option', 'label', "Mispick").button('enable');
$('#mispick-dialog').dialog('close');
}
}
]
});
});
$('#ordered-product-textbox').keydown(function(event) {
if (key_allowed(event)) {
return true;
}
if (key_modifies(event)) {
$('#ordered_product').val('');
$('#ordered-product-info p').html("please ENTER a scancode");
$('#ordered-product-info img').hide();
$('#ordered-product-info .warning').hide();
return true;
}
if (event.which == 13) {
var input = $(this);
var data = {upc: input.val()};
$.get('${url('purchases.batch.receiving_lookup', uuid=batch.uuid)}', data, function(data) {
if (data.error) {
alert(data.error);
if (data.redirect) {
$('#mispick-dialog').mask("Redirecting...");
location.href = data.redirect;
}
} else if (data.product) {
input.val(data.product.upc_pretty);
$('#ordered_product').val(data.product.uuid);
$('#ordered-product-info p').text(data.product.full_description);
$('#ordered-product-info img').attr('src', data.product.image_url).show();
if (data.product.found_in_batch) {
$('#ordered-product-info .warning').hide();
} else {
$('#ordered-product-info .warning').show();
}
} else {
$('#ordered-product-info p').text("product not found");
$('#ordered-product-info img').hide();
$('#ordered-product-info .warning').hide();
}
});
}
return false;
});
$('#receiving-form').submit(function() {
$(this).mask("Working...");
});
$('#upc').focus();
$('.field-wrapper.cases input').prop('disabled', true);
$('.field-wrapper.units input').prop('disabled', true);
$('.buttons button').button('disable');
});
</script>
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
<style type="text/css">
.product-info {
margin-top: 0.5em;
text-align: center;
}
.product-info p {
margin-left: 0.5em;
}
.product-info .img-wrapper {
height: 150px;
margin: 0.5em 0;
}
#received-product-info .warning {
background: #f66;
display: none;
}
#mispick-dialog input[type="text"],
#ordered-product-info {
width: 320px;
}
#ordered-product-info .warning {
background: #f66;
display: none;
}
</style>
</%def>
<%def name="context_menu_items()">
<li>${h.link_to("Back to Purchase Batch", url('purchases.batch.view', uuid=batch.uuid))}</li>
</%def>
<ul id="context-menu">
${self.context_menu_items()}
</ul>
<div class="form-wrapper">
${form.begin(id='receiving-form')}
${form.csrf_token()}
${h.hidden('mode')}
${h.hidden('expiration_date')}
${h.hidden('trash')}
${h.hidden('ordered_product')}
<div class="field-wrapper">
<label for="upc">Receiving UPC</label>
<div class="field">
${h.hidden('product')}
<div>${h.text('upc', autocomplete='off')}</div>
<div id="received-product-info" class="product-info">
<p>please ENTER a scancode</p>
<div class="img-wrapper"><img /></div>
<div class="warning notfound">please confirm UPC and provide more details</div>
<div class="warning notordered">warning: product not found on current purchase</div>
</div>
</div>
</div>
<div class="product-fields" style="display: none;">
<div class="field-wrapper brand_name">
<label for="brand_name">Brand Name</label>
<div class="field">${h.text('brand_name')}</div>
</div>
<div class="field-wrapper description">
<label for="description">Description</label>
<div class="field">${h.text('description')}</div>
</div>
<div class="field-wrapper size">
<label for="size">Size</label>
<div class="field">${h.text('size')}</div>
</div>
<div class="field-wrapper case_quantity">
<label for="case_quantity">Units in Case</label>
<div class="field">${h.text('case_quantity')}</div>
</div>
</div>
<div class="receiving-fields" style="display: none;">
<div class="field-wrapper quantity_ordered">
<label for="quantity_ordered">Ordered</label>
<div class="field"></div>
</div>
<div class="field-wrapper quantity_received">
<label for="quantity_received">Received</label>
<div class="field"></div>
</div>
<div class="field-wrapper quantity_damaged">
<label for="quantity_damaged">Damaged</label>
<div class="field"></div>
</div>
<div class="field-wrapper quantity_expired">
<label for="quantity_expired">Expired</label>
<div class="field"></div>
</div>
<div class="field-wrapper quantity_mispick">
<label for="quantity_mispick">Mispick</label>
<div class="field"></div>
</div>
</div>
<div class="field-wrapper cases">
<label for="cases">Cases</label>
<div class="field">${h.text('cases', autocomplete='off')}</div>
</div>
<div class="field-wrapper units">
<label for="units">Units</label>
<div class="field">${h.text('units', autocomplete='off')}</div>
</div>
<div class="buttons">
<button type="button" id="received">Received</button>
<button type="button" id="damaged">Damaged</button>
<button type="button" id="expired">Expired</button>
<!-- <button type="button" id="mispick">Mispick</button> -->
</div>
${form.end()}
</div>
<div id="damaged-dialog" style="display: none;">
<div class="field-wrapper trash">${h.checkbox('trash', label="Product will be discarded and cannot be returned", checked=False)}</div>
</div>
<div id="expiration" style="display: none;">
<div class="field-wrapper expiration-date">
<label for="expiration-date">Expiration Date</label>
<div class="field">${h.text('expiration-date', type='date')}</div>
</div>
<div class="field-wrapper trash">${h.checkbox('trash', label="Product will be discarded and cannot be returned", checked=False)}</div>
</div>
<div id="mispick-dialog" style="display: none;">
<div>${h.text('ordered-product-textbox', autocomplete='off')}</div>
<div id="ordered-product-info" class="product-info">
<p>please ENTER a scancode</p>
<div class="img-wrapper"><img /></div>
<div class="warning">warning: product not found on current purchase</div>
</div>
</div>

View file

@ -1,80 +1,6 @@
## -*- coding: utf-8; -*-
<%inherit file="/batch/create.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
${self.func_show_batch_type()}
<script type="text/javascript">
% if master.handler.allow_truck_dump_receiving():
var batch_vendor_map = ${json.dumps(batch_vendor_map)|n};
% endif
$(function() {
$('.batch_type select').on('selectmenuchange', function(event, ui) {
show_batch_type(ui.item.value);
});
$('.truck_dump_batch_uuid select').on('selectmenuchange', function(event, ui) {
var form = $(this).parents('form');
var uuid = ui.item.value ? batch_vendor_map[ui.item.value] : '';
form.find('input[name="vendor_uuid"]').val(uuid);
});
show_batch_type();
});
</script>
% endif
</%def>
<%def name="func_show_batch_type()">
<script type="text/javascript">
function show_batch_type(batch_type) {
if (batch_type === undefined) {
batch_type = $('.field-wrapper.batch_type select').val();
}
if (batch_type == 'from_scratch') {
$('.field-wrapper.truck_dump_batch_uuid').hide();
$('.field-wrapper.invoice_file').hide();
$('.field-wrapper.invoice_parser_key').hide();
$('.field-wrapper.vendor_uuid').show();
$('.field-wrapper.date_ordered').show();
$('.field-wrapper.date_received').show();
$('.field-wrapper.po_number').show();
$('.field-wrapper.invoice_date').show();
$('.field-wrapper.invoice_number').show();
} else if (batch_type == 'truck_dump_children_first') {
$('.field-wrapper.truck_dump_batch_uuid').hide();
$('.field-wrapper.invoice_file').hide();
$('.field-wrapper.invoice_parser_key').hide();
$('.field-wrapper.vendor_uuid').show();
$('.field-wrapper.date_ordered').hide();
$('.field-wrapper.date_received').show();
$('.field-wrapper.po_number').hide();
$('.field-wrapper.invoice_date').hide();
$('.field-wrapper.invoice_number').hide();
} else if (batch_type == 'truck_dump_children_last') {
$('.field-wrapper.truck_dump_batch_uuid').hide();
$('.field-wrapper.invoice_file').hide();
$('.field-wrapper.invoice_parser_key').hide();
$('.field-wrapper.vendor_uuid').show();
$('.field-wrapper.date_ordered').hide();
$('.field-wrapper.date_received').show();
$('.field-wrapper.po_number').hide();
$('.field-wrapper.invoice_date').hide();
$('.field-wrapper.invoice_number').hide();
}
}
</script>
</%def>
## TODO: deprecate / remove this
${parent.body()}

View file

@ -11,35 +11,6 @@
% endif
</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
function toggleFields(creditType) {
if (creditType === undefined) {
creditType = $('select[name="credit_type"]').val();
}
if (creditType == 'expired') {
$('.field-wrapper.expiration_date').show();
} else {
$('.field-wrapper.expiration_date').hide();
}
}
$(function() {
toggleFields();
$('select[name="credit_type"]').on('selectmenuchange', function(event, ui) {
toggleFields(ui.item.value);
});
});
</script>
% endif
</%def>
<%def name="render_buefy_form()">
<p class="block">
@ -75,30 +46,7 @@
</%def>
<%def name="render_form()">
% if use_buefy:
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
% else:
<p style="padding: 1em;">
Please select the "state" of the product, and enter the appropriate
quantity.
</p>
<p style="padding: 1em;">
Note that this tool will <strong>deduct</strong> from the "received"
quantity, and <strong>add</strong> to the corresponding credit quantity.
</p>
<p style="padding: 1em;">
Please see ${h.link_to("Receive Row", url('{}.receive_row'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid))}
if you need to "receive" instead of "convert" the product.
</p>
${parent.render_form()}
% endif
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
</%def>

View file

@ -11,35 +11,6 @@
% endif
</%def>
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
function toggleFields(mode) {
if (mode === undefined) {
mode = $('select[name="mode"]').val();
}
if (mode == 'expired') {
$('.field-wrapper.expiration_date').show();
} else {
$('.field-wrapper.expiration_date').hide();
}
}
$(function() {
toggleFields();
$('select[name="mode"]').on('selectmenuchange', function(event, ui) {
toggleFields(ui.item.value);
});
});
</script>
% endif
</%def>
<%def name="render_buefy_form()">
<p class="block">
@ -72,30 +43,7 @@
</%def>
<%def name="render_form()">
% if use_buefy:
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
% else:
<p style="padding: 1em;">
Please select the "state" of the product, and enter the appropriate
quantity.
</p>
<p style="padding: 1em;">
Note that this tool will <strong>add</strong> the corresponding
quantities for the row.
</p>
<p style="padding: 1em;">
Please see ${h.link_to("Declare Credit", url('{}.declare_credit'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid))}
if you need to "convert" some already-received amount, into a credit.
</p>
${parent.render_form()}
% endif
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
</%def>

View file

@ -1,311 +1,32 @@
## -*- coding: utf-8; -*-
<%inherit file="/batch/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy and master.has_perm('edit_row'):
${h.javascript_link(request.static_url('tailbone:static/js/numeric.js'))}
<script type="text/javascript">
% if not batch.executed:
// keep track of which cost value is currently being edited
var editing_catalog_cost = null;
var editing_invoice_cost = null;
function start_editing(td) {
var value = null;
var text = td.text().replace(/^\s+|\s+$/g, '');
if (text) {
td.data('previous-value', text);
td.text('');
value = parseFloat(text.replace('$', ''));
}
var input = $('<input type="text" />');
td.append(input);
value = value ? value.toString() : '';
input.val(value).select().focus();
}
function start_editing_catalog_cost(td) {
start_editing(td);
editing_catalog_cost = td;
}
function start_editing_invoice_cost(td) {
start_editing(td);
editing_invoice_cost = td;
}
function start_editing_next_catalog_cost() {
var tr = editing_catalog_cost.parents('tr:first');
var next = tr.next('tr:first');
if (next.length) {
start_editing_catalog_cost(next.find('td.catalog_unit_cost'));
} else {
editing_catalog_cost = null;
}
}
function start_editing_next_invoice_cost() {
var tr = editing_invoice_cost.parents('tr:first');
var next = tr.next('tr:first');
if (next.length) {
start_editing_invoice_cost(next.find('td.invoice_unit_cost'));
} else {
editing_invoice_cost = null;
}
}
function cancel_edit(td) {
var input = td.find('input');
input.blur();
input.remove();
var value = td.data('previous-value');
if (value) {
td.text(value);
}
}
function cancel_edit_catalog_cost() {
cancel_edit(editing_catalog_cost);
editing_catalog_cost = null;
}
function cancel_edit_invoice_cost() {
cancel_edit(editing_invoice_cost);
editing_invoice_cost = null;
}
% endif
$(function() {
% if not batch.executed:
$('.grid-wrapper').on('click', '.grid td.catalog_unit_cost', function() {
if (editing_catalog_cost) {
editing_catalog_cost.find('input').focus();
return
}
if (editing_invoice_cost) {
editing_invoice_cost.find('input').focus();
return
}
var td = $(this);
start_editing_catalog_cost(td);
});
$('.grid-wrapper').on('click', '.grid td.invoice_unit_cost', function() {
if (editing_invoice_cost) {
editing_invoice_cost.find('input').focus();
return
}
if (editing_catalog_cost) {
editing_catalog_cost.find('input').focus();
return
}
var td = $(this);
start_editing_invoice_cost(td);
});
$('.grid-wrapper').on('keyup', '.grid td.catalog_unit_cost input', function(event) {
var input = $(this);
// let numeric keys modify input value
if (! key_modifies(event)) {
// when user presses Enter while editing cost value, submit
// value to server for immediate persistence
if (event.which == 13) {
$('.grid-wrapper').mask("Updating cost...");
var url = '${url('receiving.update_row_cost', uuid=batch.uuid)}';
var td = input.parents('td:first');
var tr = td.parents('tr:first');
var data = {
'_csrf': $('[name="_csrf"]').val(),
'row_uuid': tr.data('uuid'),
'catalog_unit_cost': input.val()
};
$.post(url, data, function(data) {
if (data.error) {
alert(data.error);
} else {
var total = null;
// update catalog cost for row
td.text(data.row.catalog_unit_cost);
// mark cost as confirmed
if (data.row.catalog_cost_confirmed) {
tr.addClass('catalog_cost_confirmed');
}
input.blur();
input.remove();
start_editing_next_catalog_cost();
}
$('.grid-wrapper').unmask();
});
// When user presses Escape while editing totals, cancel the edit.
} else if (event.which == 27) {
cancel_edit_catalog_cost();
// Most other keys at this point should be unwanted...
} else if (! key_allowed(event)) {
return false;
}
}
});
$('.grid-wrapper').on('keyup', '.grid td.invoice_unit_cost input', function(event) {
var input = $(this);
// let numeric keys modify input value
if (! key_modifies(event)) {
// when user presses Enter while editing cost value, submit
// value to server for immediate persistence
if (event.which == 13) {
$('.grid-wrapper').mask("Updating cost...");
var url = '${url('receiving.update_row_cost', uuid=batch.uuid)}';
var td = input.parents('td:first');
var tr = td.parents('tr:first');
var data = {
'_csrf': $('[name="_csrf"]').val(),
'row_uuid': tr.data('uuid'),
'invoice_unit_cost': input.val()
};
$.post(url, data, function(data) {
if (data.error) {
alert(data.error);
} else {
var total = null;
// update unit cost for row
td.text(data.row.invoice_unit_cost);
// update invoice total for row
total = tr.find('td.invoice_total_calculated');
total.text('$' + data.row.invoice_total_calculated);
// update invoice total for batch
total = $('.form .field-wrapper.invoice_total_calculated .field');
total.text('$' + data.batch.invoice_total_calculated);
// mark cost as confirmed
if (data.row.invoice_cost_confirmed) {
tr.addClass('invoice_cost_confirmed');
}
input.blur();
input.remove();
start_editing_next_invoice_cost();
}
$('.grid-wrapper').unmask();
});
// When user presses Escape while editing totals, cancel the edit.
} else if (event.which == 27) {
cancel_edit_invoice_cost();
// Most other keys at this point should be unwanted...
} else if (! key_allowed(event)) {
return false;
}
}
});
% endif
$('.grid-wrapper').on('click', '.grid .actions a.transform', function() {
var form = $('form[name="transform-unit-form"]');
var row_uuid = $(this).parents('tr:first').data('uuid');
form.find('[name="row_uuid"]').val(row_uuid);
$.get(form.attr('action'), {row_uuid: row_uuid}, function(data) {
if (typeof(data) == 'object') {
alert(data.error);
} else {
$('#transform-unit-dialog').html(data);
$('#transform-unit-dialog').dialog({
title: "Transform Pack to Unit Item",
width: 800,
height: 450,
modal: true,
buttons: [
{
text: "Transform",
click: function(event) {
disable_button(dialog_button(event));
form.submit();
}
},
{
text: "Cancel",
click: function() {
$(this).dialog('close');
}
}
]
});
}
});
return false;
});
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if use_buefy:
<style type="text/css">
% if allow_edit_catalog_unit_cost:
td.c_catalog_unit_cost {
cursor: pointer;
background-color: #fcc;
}
tr.catalog_cost_confirmed td.c_catalog_unit_cost {
background-color: #cfc;
}
% endif
% if allow_edit_invoice_unit_cost:
td.c_invoice_unit_cost {
cursor: pointer;
background-color: #fcc;
}
tr.invoice_cost_confirmed td.c_invoice_unit_cost {
background-color: #cfc;
}
% endif
</style>
% elif not use_buefy and not batch.executed and master.has_perm('edit_row'):
<style type="text/css">
.grid tr:not(.header) td.catalog_unit_cost,
.grid tr:not(.header) td.invoice_unit_cost {
cursor: pointer;
background-color: #fcc;
<style type="text/css">
% if allow_edit_catalog_unit_cost:
td.c_catalog_unit_cost {
cursor: pointer;
background-color: #fcc;
}
.grid tr.catalog_cost_confirmed:not(.header) td.catalog_unit_cost,
.grid tr.invoice_cost_confirmed:not(.header) td.invoice_unit_cost {
background-color: #cfc;
tr.catalog_cost_confirmed td.c_catalog_unit_cost {
background-color: #cfc;
}
.grid td.catalog_unit_cost input,
.grid td.invoice_unit_cost input {
width: 4rem;
% endif
% if allow_edit_invoice_unit_cost:
td.c_invoice_unit_cost {
cursor: pointer;
background-color: #fcc;
}
</style>
% endif
tr.invoice_cost_confirmed td.c_invoice_unit_cost {
background-color: #cfc;
}
% endif
</style>
</%def>
<%def name="render_po_vs_invoice_helper()">
% if use_buefy and master.handler.has_purchase_order(batch) and master.handler.has_invoice_file(batch):
% if master.handler.has_purchase_order(batch) and master.handler.has_invoice_file(batch):
<div class="object-helper">
<h3>PO vs. Invoice</h3>
<div class="object-helper-content">
@ -321,60 +42,51 @@
<div class="object-helper">
<h3>Tools</h3>
<div class="object-helper-content">
% if use_buefy:
<b-button type="is-primary"
@click="autoReceiveShowDialog = true"
icon-pack="fas"
icon-left="check">
Auto-Receive All Items
</b-button>
% else:
${h.form(url('{}.auto_receive'.format(route_prefix), uuid=batch.uuid), class_='autodisable')}
${h.csrf_token(request)}
${h.submit('submit', "Auto-Receive All Items")}
${h.end_form()}
% endif
<b-button type="is-primary"
@click="autoReceiveShowDialog = true"
icon-pack="fas"
icon-left="check">
Auto-Receive All Items
</b-button>
</div>
</div>
% if use_buefy:
<b-modal has-modal-card
:active.sync="autoReceiveShowDialog">
<div class="modal-card">
<b-modal has-modal-card
:active.sync="autoReceiveShowDialog">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Auto-Receive All Items</p>
</header>
<header class="modal-card-head">
<p class="modal-card-title">Auto-Receive All Items</p>
</header>
<section class="modal-card-body">
<p class="block">
You can automatically set the "received" quantity to
match the "shipped" quantity for all items, based on
the invoice.
</p>
<p class="block">
Would you like to do so?
</p>
</section>
<section class="modal-card-body">
<p class="block">
You can automatically set the "received" quantity to
match the "shipped" quantity for all items, based on
the invoice.
</p>
<p class="block">
Would you like to do so?
</p>
</section>
<footer class="modal-card-foot">
<b-button @click="autoReceiveShowDialog = false">
Cancel
</b-button>
${h.form(url('{}.auto_receive'.format(route_prefix), uuid=batch.uuid), **{'@submit': 'autoReceiveSubmitting = true'})}
${h.csrf_token(request)}
<b-button type="is-primary"
native-type="submit"
:disabled="autoReceiveSubmitting"
icon-pack="fas"
icon-left="check">
{{ autoReceiveSubmitting ? "Working, please wait..." : "Auto-Receive All Items" }}
</b-button>
${h.end_form()}
</footer>
</div>
</b-modal>
% endif
<footer class="modal-card-foot">
<b-button @click="autoReceiveShowDialog = false">
Cancel
</b-button>
${h.form(url('{}.auto_receive'.format(route_prefix), uuid=batch.uuid), **{'@submit': 'autoReceiveSubmitting = true'})}
${h.csrf_token(request)}
<b-button type="is-primary"
native-type="submit"
:disabled="autoReceiveSubmitting"
icon-pack="fas"
icon-left="check">
{{ autoReceiveSubmitting ? "Working, please wait..." : "Auto-Receive All Items" }}
</b-button>
${h.end_form()}
</footer>
</div>
</b-modal>
% endif
</%def>
@ -607,14 +319,3 @@
${parent.body()}
% if not use_buefy and master.handler.allow_truck_dump_receiving() and master.has_perm('edit_row'):
${h.form(url('{}.transform_unit_row'.format(route_prefix), uuid=batch.uuid), name='transform-unit-form')}
${h.csrf_token(request)}
${h.hidden('row_uuid')}
${h.end_form()}
<div id="transform-unit-dialog" style="display: none;">
<p>hello world</p>
</div>
% endif

View file

@ -4,479 +4,456 @@
<%def name="extra_styles()">
${parent.extra_styles()}
<style type="text/css">
% if use_buefy:
nav.panel {
margin: 0.5rem;
}
nav.panel {
margin: 0.5rem;
}
.header-fields {
margin-top: 1rem;
}
.header-fields {
margin-top: 1rem;
}
.header-fields .field.is-horizontal {
margin-left: 3rem;
}
.header-fields .field.is-horizontal {
margin-left: 3rem;
}
.header-fields .field.is-horizontal .field-label .label {
white-space: nowrap;
}
.header-fields .field.is-horizontal .field-label .label {
white-space: nowrap;
}
.quantity-form-fields {
margin: 2rem;
}
.quantity-form-fields {
margin: 2rem;
}
.quantity-form-fields .field.is-horizontal .field-label .label {
text-align: left;
width: 8rem;
}
.quantity-form-fields .field.is-horizontal .field-label .label {
text-align: left;
width: 8rem;
}
.remove-credit .field.is-horizontal .field-label .label {
white-space: nowrap;
}
.remove-credit .field.is-horizontal .field-label .label {
white-space: nowrap;
}
% endif
</style>
</%def>
<%def name="object_helpers()">
${parent.object_helpers()}
% if not use_buefy and master.row_editable(row) and not batch.is_truck_dump_child():
<div class="object-helper">
<h3>Receiving Tools</h3>
<div class="object-helper-content">
<div style="white-space: nowrap;">
${h.link_to("Receive Product", url('{}.receive_row'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid), class_='button autodisable')}
${h.link_to("Declare Credit", url('{}.declare_credit'.format(route_prefix), uuid=batch.uuid, row_uuid=row.uuid), class_='button autodisable')}
<%def name="page_content()">
<b-field grouped class="header-fields">
<b-field label="Sequence" horizontal>
{{ rowData.sequence }}
</b-field>
<b-field label="Status" horizontal>
{{ rowData.status }}
</b-field>
<b-field label="Calculated Total" horizontal>
{{ rowData.invoice_total_calculated }}
</b-field>
</b-field>
<div style="display: flex;">
<nav class="panel">
<p class="panel-heading">Product</p>
<div class="panel-block">
<div style="display: flex;">
<div>
${form.render_field_readonly('item_entry')}
% if row.product:
${form.render_field_readonly(product_key_field)}
${form.render_field_readonly('product')}
% else:
${form.render_field_readonly(product_key_field)}
% if product_key_field != 'upc':
${form.render_field_readonly('upc')}
% endif
${form.render_field_readonly('brand_name')}
${form.render_field_readonly('description')}
${form.render_field_readonly('size')}
% endif
${form.render_field_readonly('vendor_code')}
${form.render_field_readonly('case_quantity')}
${form.render_field_readonly('catalog_unit_cost')}
</div>
% if image_url:
<div class="is-pulled-right">
${h.image(image_url, "Product Image", width=150, height=150)}
</div>
% endif
</div>
</div>
% endif
</%def>
</nav>
<%def name="page_content()">
% if use_buefy:
<b-field grouped class="header-fields">
<b-field label="Sequence" horizontal>
{{ rowData.sequence }}
</b-field>
<b-field label="Status" horizontal>
{{ rowData.status }}
</b-field>
<b-field label="Calculated Total" horizontal>
{{ rowData.invoice_total_calculated }}
</b-field>
</b-field>
<div style="display: flex;">
<nav class="panel">
<p class="panel-heading">Product</p>
<div class="panel-block">
<div style="display: flex;">
<div>
${form.render_field_readonly('item_entry')}
% if row.product:
${form.render_field_readonly(product_key_field)}
${form.render_field_readonly('product')}
% else:
${form.render_field_readonly(product_key_field)}
% if product_key_field != 'upc':
${form.render_field_readonly('upc')}
% endif
${form.render_field_readonly('brand_name')}
${form.render_field_readonly('description')}
${form.render_field_readonly('size')}
% endif
${form.render_field_readonly('vendor_code')}
${form.render_field_readonly('case_quantity')}
${form.render_field_readonly('catalog_unit_cost')}
</div>
% if image_url:
<div class="is-pulled-right">
${h.image(image_url, "Product Image", width=150, height=150)}
</div>
% endif
</div>
</div>
</nav>
<nav class="panel">
<p class="panel-heading">Quantities</p>
<div class="panel-block">
<div>
<div class="quantity-form-fields">
<b-field label="Ordered" horizontal>
{{ rowData.ordered }}
</b-field>
<hr />
<b-field label="Shipped" horizontal>
{{ rowData.shipped }}
</b-field>
<hr />
<b-field label="Received" horizontal
v-if="rowData.received">
{{ rowData.received }}
</b-field>
<b-field label="Damaged" horizontal
v-if="rowData.damaged">
{{ rowData.damaged }}
</b-field>
<b-field label="Expired" horizontal
v-if="rowData.expired">
{{ rowData.expired }}
</b-field>
<b-field label="Mispick" horizontal
v-if="rowData.mispick">
{{ rowData.mispick }}
</b-field>
<b-field label="Missing" horizontal
v-if="rowData.missing">
{{ rowData.missing }}
</b-field>
</div>
% if master.has_perm('edit_row') and master.row_editable(row):
<div class="buttons">
<b-button type="is-primary"
@click="accountForProductInit()"
icon-pack="fas"
icon-left="check">
Account for Product
</b-button>
<b-button type="is-warning"
@click="declareCreditInit()"
:disabled="!rowData.received"
icon-pack="fas"
icon-left="thumbs-down">
Declare Credit
</b-button>
</div>
% endif
</div>
</div>
</nav>
</div>
<b-modal has-modal-card
:active.sync="accountForProductShowDialog">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Account for Product</p>
</header>
<section class="modal-card-body">
<p class="block">
This is for declaring that you have encountered some
amount of the product.&nbsp; Ideally you will just
"receive" it normally, but you can indicate a "credit"
state if there is something amiss.
</p>
<b-field grouped>
% if allow_cases:
<b-field label="Case Qty.">
<span class="control">
{{ rowData.case_quantity }}
</span>
</b-field>
<span class="control">
&nbsp;
</span>
% endif
<b-field label="Product State"
:type="accountForProductMode ? null : 'is-danger'">
<b-select v-model="accountForProductMode">
<option v-for="mode in possibleReceivingModes"
:key="mode"
:value="mode">
{{ mode }}
</option>
</b-select>
</b-field>
<b-field label="Expiration Date"
v-show="accountForProductMode == 'expired'"
:type="accountForProductExpiration ? null : 'is-danger'">
<tailbone-datepicker v-model="accountForProductExpiration">
</tailbone-datepicker>
</b-field>
<nav class="panel">
<p class="panel-heading">Quantities</p>
<div class="panel-block">
<div>
<div class="quantity-form-fields">
<b-field label="Ordered" horizontal>
{{ rowData.ordered }}
</b-field>
<div class="level">
<div class="level-left">
<hr />
<div class="level-item">
<numeric-input v-model="accountForProductQuantity"
ref="accountForProductQuantityInput">
</numeric-input>
</div>
<b-field label="Shipped" horizontal>
{{ rowData.shipped }}
</b-field>
<div class="level-item">
% if allow_cases:
<b-field>
<b-radio-button v-model="accountForProductUOM"
@click.native="accountForProductUOMClicked('units')"
native-value="units">
Units
</b-radio-button>
<b-radio-button v-model="accountForProductUOM"
@click.native="accountForProductUOMClicked('cases')"
native-value="cases">
Cases
</b-radio-button>
</b-field>
% else:
<b-field>
<input type="hidden" v-model="accountForProductUOM" />
Units
</b-field>
% endif
</div>
<hr />
% if allow_cases:
<div class="level-item"
v-if="accountForProductUOM == 'cases' && accountForProductQuantity">
= {{ accountForProductTotalUnits }}
</div>
% endif
<b-field label="Received" horizontal
v-if="rowData.received">
{{ rowData.received }}
</b-field>
<b-field label="Damaged" horizontal
v-if="rowData.damaged">
{{ rowData.damaged }}
</b-field>
<b-field label="Expired" horizontal
v-if="rowData.expired">
{{ rowData.expired }}
</b-field>
<b-field label="Mispick" horizontal
v-if="rowData.mispick">
{{ rowData.mispick }}
</b-field>
<b-field label="Missing" horizontal
v-if="rowData.missing">
{{ rowData.missing }}
</b-field>
</div>
% if master.has_perm('edit_row') and master.row_editable(row):
<div class="buttons">
<b-button type="is-primary"
@click="accountForProductInit()"
icon-pack="fas"
icon-left="check">
Account for Product
</b-button>
<b-button type="is-warning"
@click="declareCreditInit()"
:disabled="!rowData.received"
icon-pack="fas"
icon-left="thumbs-down">
Declare Credit
</b-button>
</div>
</div>
% endif
</section>
<footer class="modal-card-foot">
<b-button @click="accountForProductShowDialog = false">
Cancel
</b-button>
<b-button type="is-primary"
@click="accountForProductSubmit()"
:disabled="accountForProductSubmitDisabled"
icon-pack="fas"
icon-left="check">
{{ accountForProductSubmitting ? "Working, please wait..." : "Account for Product" }}
</b-button>
</footer>
</div>
</b-modal>
</div>
</nav>
<b-modal has-modal-card
:active.sync="declareCreditShowDialog">
<div class="modal-card">
</div>
<header class="modal-card-head">
<p class="modal-card-title">Declare Credit</p>
</header>
<b-modal has-modal-card
:active.sync="accountForProductShowDialog">
<div class="modal-card">
<section class="modal-card-body">
<header class="modal-card-head">
<p class="modal-card-title">Account for Product</p>
</header>
<p class="block">
This is for <span class="is-italic">converting</span>
some amount you <span class="is-italic">already
received</span>, and now declaring there is something
wrong with it.
</p>
<section class="modal-card-body">
<b-field grouped>
<p class="block">
This is for declaring that you have encountered some
amount of the product.&nbsp; Ideally you will just
"receive" it normally, but you can indicate a "credit"
state if there is something amiss.
</p>
<b-field label="Received">
<b-field grouped>
% if allow_cases:
<b-field label="Case Qty.">
<span class="control">
{{ rowData.received }}
{{ rowData.case_quantity }}
</span>
</b-field>
<span class="control">
&nbsp;
</span>
% endif
<b-field label="Credit Type"
:type="declareCreditType ? null : 'is-danger'">
<b-select v-model="declareCreditType">
<option v-for="typ in possibleCreditTypes"
:key="typ"
:value="typ">
{{ typ }}
</option>
</b-select>
</b-field>
<b-field label="Product State"
:type="accountForProductMode ? null : 'is-danger'">
<b-select v-model="accountForProductMode">
<option v-for="mode in possibleReceivingModes"
:key="mode"
:value="mode">
{{ mode }}
</option>
</b-select>
</b-field>
<b-field label="Expiration Date"
v-show="declareCreditType == 'expired'"
:type="declareCreditExpiration ? null : 'is-danger'">
<tailbone-datepicker v-model="declareCreditExpiration">
</tailbone-datepicker>
</b-field>
<b-field label="Expiration Date"
v-show="accountForProductMode == 'expired'"
:type="accountForProductExpiration ? null : 'is-danger'">
<tailbone-datepicker v-model="accountForProductExpiration">
</tailbone-datepicker>
</b-field>
</b-field>
</b-field>
<div class="level">
<div class="level-left">
<div class="level">
<div class="level-left">
<div class="level-item">
<numeric-input v-model="declareCreditQuantity"
ref="declareCreditQuantityInput">
</numeric-input>
</div>
<div class="level-item">
% if allow_cases:
<b-field>
<b-radio-button v-model="declareCreditUOM"
@click.native="declareCreditUOMClicked('units')"
native-value="units">
Units
</b-radio-button>
<b-radio-button v-model="declareCreditUOM"
@click.native="declareCreditUOMClicked('cases')"
native-value="cases">
Cases
</b-radio-button>
</b-field>
% else:
<b-field>
<input type="hidden" v-model="declareCreditUOM" />
Units
</b-field>
% endif
</div>
% if allow_cases:
<div class="level-item"
v-if="declareCreditUOM == 'cases' && declareCreditQuantity">
= {{ declareCreditTotalUnits }}
</div>
% endif
</div>
<div class="level-item">
<numeric-input v-model="accountForProductQuantity"
ref="accountForProductQuantityInput">
</numeric-input>
</div>
</section>
<div class="level-item">
% if allow_cases:
<b-field>
<b-radio-button v-model="accountForProductUOM"
@click.native="accountForProductUOMClicked('units')"
native-value="units">
Units
</b-radio-button>
<b-radio-button v-model="accountForProductUOM"
@click.native="accountForProductUOMClicked('cases')"
native-value="cases">
Cases
</b-radio-button>
</b-field>
% else:
<b-field>
<input type="hidden" v-model="accountForProductUOM" />
Units
</b-field>
% endif
</div>
<footer class="modal-card-foot">
<b-button @click="declareCreditShowDialog = false">
Cancel
</b-button>
<b-button type="is-warning"
@click="declareCreditSubmit()"
:disabled="declareCreditSubmitDisabled"
icon-pack="fas"
icon-left="thumbs-down">
{{ declareCreditSubmitting ? "Working, please wait..." : "Declare this Credit" }}
</b-button>
</footer>
</div>
</b-modal>
% if allow_cases:
<div class="level-item"
v-if="accountForProductUOM == 'cases' && accountForProductQuantity">
= {{ accountForProductTotalUnits }}
</div>
% endif
<nav class="panel" >
<p class="panel-heading">Credits</p>
<div class="panel-block">
<div>
${form.render_field_value('credits')}
</div>
</div>
</nav>
<b-modal has-modal-card
:active.sync="removeCreditShowDialog">
<div class="modal-card remove-credit">
</section>
<header class="modal-card-head">
<p class="modal-card-title">Un-Declare Credit</p>
</header>
<footer class="modal-card-foot">
<b-button @click="accountForProductShowDialog = false">
Cancel
</b-button>
<b-button type="is-primary"
@click="accountForProductSubmit()"
:disabled="accountForProductSubmitDisabled"
icon-pack="fas"
icon-left="check">
{{ accountForProductSubmitting ? "Working, please wait..." : "Account for Product" }}
</b-button>
</footer>
</div>
</b-modal>
<section class="modal-card-body">
<b-modal has-modal-card
:active.sync="declareCreditShowDialog">
<div class="modal-card">
<p class="block">
If you un-declare this credit, the quantity below will
be added back to the
<span class="has-text-weight-bold">Received</span> tally.
</p>
<header class="modal-card-head">
<p class="modal-card-title">Declare Credit</p>
</header>
<b-field label="Credit Type" horizontal>
{{ removeCreditRow.credit_type }}
</b-field>
<section class="modal-card-body">
<b-field label="Quantity" horizontal>
{{ removeCreditRow.shorted }}
</b-field>
<p class="block">
This is for <span class="is-italic">converting</span>
some amount you <span class="is-italic">already
received</span>, and now declaring there is something
wrong with it.
</p>
</section>
<b-field grouped>
<footer class="modal-card-foot">
<b-button @click="removeCreditShowDialog = false">
Cancel
</b-button>
<b-button type="is-danger"
@click="removeCreditSubmit()"
:disabled="removeCreditSubmitting"
icon-pack="fas"
icon-left="trash">
{{ removeCreditSubmitting ? "Working, please wait..." : "Un-Declare this Credit" }}
</b-button>
</footer>
<b-field label="Received">
<span class="control">
{{ rowData.received }}
</span>
</b-field>
<span class="control">
&nbsp;
</span>
<b-field label="Credit Type"
:type="declareCreditType ? null : 'is-danger'">
<b-select v-model="declareCreditType">
<option v-for="typ in possibleCreditTypes"
:key="typ"
:value="typ">
{{ typ }}
</option>
</b-select>
</b-field>
<b-field label="Expiration Date"
v-show="declareCreditType == 'expired'"
:type="declareCreditExpiration ? null : 'is-danger'">
<tailbone-datepicker v-model="declareCreditExpiration">
</tailbone-datepicker>
</b-field>
</b-field>
<div class="level">
<div class="level-left">
<div class="level-item">
<numeric-input v-model="declareCreditQuantity"
ref="declareCreditQuantityInput">
</numeric-input>
</div>
<div class="level-item">
% if allow_cases:
<b-field>
<b-radio-button v-model="declareCreditUOM"
@click.native="declareCreditUOMClicked('units')"
native-value="units">
Units
</b-radio-button>
<b-radio-button v-model="declareCreditUOM"
@click.native="declareCreditUOMClicked('cases')"
native-value="cases">
Cases
</b-radio-button>
</b-field>
% else:
<b-field>
<input type="hidden" v-model="declareCreditUOM" />
Units
</b-field>
% endif
</div>
% if allow_cases:
<div class="level-item"
v-if="declareCreditUOM == 'cases' && declareCreditQuantity">
= {{ declareCreditTotalUnits }}
</div>
% endif
</div>
</div>
</b-modal>
<div style="display: flex;">
</section>
% if master.batch_handler.has_purchase_order(batch):
<nav class="panel" >
<p class="panel-heading">Purchase Order</p>
<div class="panel-block">
<div>
${form.render_field_readonly('po_line_number')}
${form.render_field_readonly('po_unit_cost')}
${form.render_field_readonly('po_case_size')}
${form.render_field_readonly('po_total')}
</div>
</div>
</nav>
% endif
% if master.batch_handler.has_invoice_file(batch):
<nav class="panel" >
<p class="panel-heading">Invoice</p>
<div class="panel-block">
<div>
${form.render_field_readonly('invoice_line_number')}
${form.render_field_readonly('invoice_unit_cost')}
${form.render_field_readonly('invoice_case_size')}
${form.render_field_readonly('invoice_total', label="Invoice Total")}
</div>
</div>
</nav>
% endif
<footer class="modal-card-foot">
<b-button @click="declareCreditShowDialog = false">
Cancel
</b-button>
<b-button type="is-warning"
@click="declareCreditSubmit()"
:disabled="declareCreditSubmitDisabled"
icon-pack="fas"
icon-left="thumbs-down">
{{ declareCreditSubmitting ? "Working, please wait..." : "Declare this Credit" }}
</b-button>
</footer>
</div>
</b-modal>
<nav class="panel" >
<p class="panel-heading">Credits</p>
<div class="panel-block">
<div>
${form.render_field_value('credits')}
</div>
</div>
</nav>
% else:
## legacy / not buefy
${parent.page_content()}
% endif
<b-modal has-modal-card
:active.sync="removeCreditShowDialog">
<div class="modal-card remove-credit">
<header class="modal-card-head">
<p class="modal-card-title">Un-Declare Credit</p>
</header>
<section class="modal-card-body">
<p class="block">
If you un-declare this credit, the quantity below will
be added back to the
<span class="has-text-weight-bold">Received</span> tally.
</p>
<b-field label="Credit Type" horizontal>
{{ removeCreditRow.credit_type }}
</b-field>
<b-field label="Quantity" horizontal>
{{ removeCreditRow.shorted }}
</b-field>
</section>
<footer class="modal-card-foot">
<b-button @click="removeCreditShowDialog = false">
Cancel
</b-button>
<b-button type="is-danger"
@click="removeCreditSubmit()"
:disabled="removeCreditSubmitting"
icon-pack="fas"
icon-left="trash">
{{ removeCreditSubmitting ? "Working, please wait..." : "Un-Declare this Credit" }}
</b-button>
</footer>
</div>
</b-modal>
<div style="display: flex;">
% if master.batch_handler.has_purchase_order(batch):
<nav class="panel" >
<p class="panel-heading">Purchase Order</p>
<div class="panel-block">
<div>
${form.render_field_readonly('po_line_number')}
${form.render_field_readonly('po_unit_cost')}
${form.render_field_readonly('po_case_size')}
${form.render_field_readonly('po_total')}
</div>
</div>
</nav>
% endif
% if master.batch_handler.has_invoice_file(batch):
<nav class="panel" >
<p class="panel-heading">Invoice</p>
<div class="panel-block">
<div>
${form.render_field_readonly('invoice_line_number')}
${form.render_field_readonly('invoice_unit_cost')}
${form.render_field_readonly('invoice_case_size')}
${form.render_field_readonly('invoice_total', label="Invoice Total")}
</div>
</div>
</nav>
% endif
</div>
</%def>
<%def name="modify_this_page_vars()">

View file

@ -1,47 +1,14 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/create.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
var report_descriptions = ${json.dumps(report_descriptions)|n};
function show_description(key) {
var desc = report_descriptions[key];
$('#report-description').text(desc);
}
$(function() {
var report_type = $('select[name="report_type"]');
report_type.change(function(event) {
show_description(report_type.val());
});
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
<style type="text/css">
% if use_form:
% if use_buefy:
#report-description {
margin-left: 2em;
}
% else:
#report-description {
margin-top: 2em;
margin-left: 2em;
}
% endif
#report-description {
margin-left: 2em;
}
% else:
.report-selection {
margin-left: 10em;
@ -69,19 +36,7 @@
<%def name="page_content()">
% if use_form:
% if use_buefy:
${parent.page_content()}
% else:
<div class="form-wrapper">
<p>Please select the type of report you wish to generate.</p>
<div style="display: flex;">
${form.render()|n}
<div id="report-description"></div>
</div>
</div><!-- form-wrapper -->
% endif
${parent.page_content()}
% else:
<div>
<br />

View file

@ -24,11 +24,5 @@
</div>
</%def>
<%def name="render_form()">
% if not use_buefy:
<p style="padding: 1em;">${report.__doc__}</p>
% endif
${parent.render_form()}
</%def>
${parent.body()}

View file

@ -4,83 +4,47 @@
<%def name="title()">Report : Inventory Worksheet</%def>
<%def name="page_content()">
% if use_buefy:
<p class="block">
Please provide the following criteria to generate your report:
</p>
<p class="block">
Please provide the following criteria to generate your report:
</p>
${h.form(request.current_route_url())}
${h.csrf_token(request)}
${h.form(request.current_route_url())}
${h.csrf_token(request)}
<b-field label="Department">
<b-select name="department">
<option v-for="dept in departments"
:key="dept.uuid"
:value="dept.uuid">
{{ dept.name }}
</option>
</b-select>
</b-field>
<b-field label="Department">
<b-select name="department">
<option v-for="dept in departments"
:key="dept.uuid"
:value="dept.uuid">
{{ dept.name }}
</option>
</b-select>
</b-field>
<b-field>
<b-checkbox name="weighted-only" native-value="1">
Only include items which are sold by weight.
</b-checkbox>
</b-field>
<b-field>
<b-checkbox name="weighted-only" native-value="1">
Only include items which are sold by weight.
</b-checkbox>
</b-field>
<b-field>
<b-checkbox name="exclude-not-for-sale" :value="true"
native-value="1">
Exclude items marked "not for sale".
</b-checkbox>
</b-field>
<b-field>
<b-checkbox name="exclude-not-for-sale" :value="true"
native-value="1">
Exclude items marked "not for sale".
</b-checkbox>
</b-field>
<div class="buttons">
<b-button type="is-primary"
native-type="submit"
icon-pack="fas"
icon-left="arrow-circle-right">
Generate Report
</b-button>
</div>
<div class="buttons">
<b-button type="is-primary"
native-type="submit"
icon-pack="fas"
icon-left="arrow-circle-right">
Generate Report
</b-button>
</div>
${h.end_form()}
% else:
<p>Please provide the following criteria to generate your report:</p>
<br />
${h.form(request.current_route_url())}
${h.csrf_token(request)}
<div class="field-wrapper">
<label for="department">Department</label>
<div class="field">
<select name="department">
% for department in departments:
<option value="${department.uuid}">${department.name}</option>
% endfor
</select>
</div>
</div>
<div class="field-wrapper">
${h.checkbox('weighted-only', label="Only include items which are sold by weight.")}
</div>
<div class="field-wrapper">
${h.checkbox('exclude-not-for-sale', label="Exclude items marked \"not for sale\".", checked=True)}
</div>
<div class="buttons">
${h.submit('submit', "Generate Report")}
</div>
${h.end_form()}
% endif
${h.end_form()}
</%def>
<%def name="modify_this_page_vars()">

View file

@ -6,24 +6,6 @@
${h.stylesheet_link(request.static_url('tailbone:static/css/perms.css'))}
</%def>
<%def name="page_content()">
${parent.page_content()}
% if not use_buefy:
<h2>Users</h2>
% if instance is guest_role:
<p>The guest role is implied for all anonymous users, i.e. when not logged in.</p>
% elif instance is authenticated_role:
<p>The authenticated role is implied for all users, but only when logged in.</p>
% elif users:
<p>The following users are assigned to this role:</p>
${users.render_grid()|n}
% else:
<p>There are no users assigned to this role.</p>
% endif
% endif
</%def>
<%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()}
<script type="text/javascript">

View file

@ -1,41 +1,6 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
% if not email.get_template('html'):
$(function() {
$('#preview-html').button('disable');
$('#preview-html').attr('title', "There is no HTML template on file for this email.");
});
% endif
% if not email.get_template('txt'):
$(function() {
$('#preview-txt').button('disable');
$('#preview-txt').attr('title', "There is no TXT template on file for this email.");
});
% endif
</script>
% endif
</%def>
<%def name="render_form()">
${parent.render_form()}
% if not use_buefy:
${h.form(url('email.preview'), name='send-email-preview', class_='autodisable')}
${h.csrf_token(request)}
${h.hidden('email_key', value=instance['key'])}
${h.link_to("Preview HTML", '{}?key={}&type=html'.format(url('email.preview'), instance['key']), id='preview-html', class_='button', target='_blank')}
${h.link_to("Preview TXT", '{}?key={}&type=txt'.format(url('email.preview'), instance['key']), id='preview-txt', class_='button', target='_blank')}
or
${h.text('recipient', value=request.user.email_address or '')}
${h.submit('send_{}'.format(instance['key']), value="Send Preview Email")}
${h.end_form()}
% endif
</%def>
<%def name="render_buefy_form()">
${parent.render_buefy_form()}
<email-preview-tools></email-preview-tools>

View file

@ -1,20 +1,6 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
$(function() {
$('#restart-client').click(function() {
disable_button(this);
location.href = '${url('tempmon.clients.restart', uuid=instance.uuid)}';
});
});
</script>
% endif
</%def>
<%def name="context_menu_items()">
${parent.context_menu_items()}
% if request.has_perm('tempmon.appliances.dashboard'):
@ -27,14 +13,10 @@
<div class="object-helper">
<h3>Client Tools</h3>
<div class="object-helper-content">
% if use_buefy:
<once-button tag="a" href="${url('{}.restart'.format(route_prefix), uuid=instance.uuid)}"
type="is-primary"
text="Restart tempmon-client daemon">
</once-button>
% else:
<button type="button" id="restart-client">Restart tempmon-client daemon</button>
% endif
<once-button tag="a" href="${url('{}.restart'.format(route_prefix), uuid=instance.uuid)}"
type="is-primary"
text="Restart tempmon-client daemon">
</once-button>
</div>
</div>
% endif

View file

@ -8,178 +8,54 @@
<%def name="extra_javascript()">
${parent.extra_javascript()}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.min.js"></script>
% if not use_buefy:
<script type="text/javascript">
var contexts = {};
var charts = {};
function fetchReadings(appliance_uuid) {
if (appliance_uuid === undefined) {
appliance_uuid = $('#appliance_uuid').val();
}
$('.form-wrapper').mask("Fetching data");
if (Object.keys(charts).length) {
Object.keys(charts).forEach(function(key) {
charts[key].destroy();
delete charts[key];
});
}
var url = '${url("tempmon.dashboard.readings")}';
var params = {'appliance_uuid': appliance_uuid};
$.get(url, params, function(data) {
if (data.probes) {
data.probes.forEach(function(probe) {
charts[probe.uuid] = new Chart(contexts[probe.uuid], {
type: 'scatter',
data: {
datasets: [{
label: probe.description,
data: probe.readings
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {unit: 'minute'},
position: 'bottom'
}]
}
}
});
});
} else {
// TODO: should improve this
alert(data.error);
}
$('.form-wrapper').unmask();
});
}
$(function() {
% for probe in appliance.probes:
contexts['${probe.uuid}'] = $('#tempchart-${probe.uuid}');
% endfor
$('#appliance_uuid').selectmenu({
change: function(event, ui) {
$('.form-wrapper').mask("Fetching data");
$(this).parents('form').submit();
}
});
fetchReadings();
});
</script>
% endif
</%def>
<%def name="render_this_page()">
% if use_buefy:
${h.form(request.current_route_url(), ref='applianceForm')}
${h.csrf_token(request)}
<div class="level-left">
${h.form(request.current_route_url(), ref='applianceForm')}
${h.csrf_token(request)}
<div class="level-left">
<div class="level-item">
<b-field label="Appliance" horizontal>
<b-select name="appliance_uuid"
v-model="applianceUUID"
@input="$refs.applianceForm.submit()">
<option v-for="appliance in appliances"
:key="appliance.uuid"
:value="appliance.uuid">
{{ appliance.name }}
</option>
</b-select>
</b-field>
</div>
% if appliance:
<div class="level-item">
<a href="${url('tempmon.appliances.view', uuid=appliance.uuid)}">
${h.image(url('tempmon.appliances.thumbnail', uuid=appliance.uuid), "")}
</a>
</div>
% endif
</div>
${h.end_form()}
% if appliance and appliance.probes:
% for probe in appliance.probes:
<h4 class="is-size-4">
Probe:&nbsp; ${h.link_to(probe.description, url('tempmon.probes.graph', uuid=probe.uuid))}
(status: ${enum.TEMPMON_PROBE_STATUS[probe.status]})
</h4>
% if probe.enabled:
<canvas ref="tempchart-${probe.uuid}" width="400" height="60"></canvas>
% else:
<p>This probe is not enabled.</p>
% endif
% endfor
% elif appliance:
<h3>This appliance has no probes configured!</h3>
% else:
<h3>Please choose an appliance.</h3>
% endif
% else:
## not buefy
<div style="display: flex;">
<div class="form-wrapper">
<div class="form">
${h.form(request.current_route_url())}
${h.csrf_token(request)}
% if use_buefy:
<b-field horizontal label="Appliance">
${appliance_select}
</b-field>
% else:
<div class="field-wrapper">
<label>Appliance</label>
<div class="field">
${appliance_select}
</div>
</div>
% endif
${h.end_form()}
</div>
<div class="level-item">
<b-field label="Appliance" horizontal>
<b-select name="appliance_uuid"
v-model="applianceUUID"
@input="$refs.applianceForm.submit()">
<option v-for="appliance in appliances"
:key="appliance.uuid"
:value="appliance.uuid">
{{ appliance.name }}
</option>
</b-select>
</b-field>
</div>
<a href="${url('tempmon.appliances.view', uuid=appliance.uuid)}">
${h.image(url('tempmon.appliances.thumbnail', uuid=appliance.uuid), "")}
</a>
</div>
% if appliance:
<div class="level-item">
<a href="${url('tempmon.appliances.view', uuid=appliance.uuid)}">
${h.image(url('tempmon.appliances.thumbnail', uuid=appliance.uuid), "")}
</a>
</div>
% endif
% if appliance.probes:
</div>
${h.end_form()}
% if appliance and appliance.probes:
% for probe in appliance.probes:
<h3>
<h4 class="is-size-4">
Probe:&nbsp; ${h.link_to(probe.description, url('tempmon.probes.graph', uuid=probe.uuid))}
(status: ${enum.TEMPMON_PROBE_STATUS[probe.status]})
</h3>
</h4>
% if probe.enabled:
% if use_buefy:
<canvas ref="tempchart" width="400" height="150"></canvas>
% else:
<canvas id="tempchart-${probe.uuid}" width="400" height="60"></canvas>
% endif
<canvas ref="tempchart-${probe.uuid}" width="400" height="60"></canvas>
% else:
<p>This probe is not enabled.</p>
% endif
% endfor
% else:
% elif appliance:
<h3>This appliance has no probes configured!</h3>
% endif
% else:
<h3>Please choose an appliance.</h3>
% endif
</%def>

View file

@ -6,71 +6,6 @@
<%def name="extra_javascript()">
${parent.extra_javascript()}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.min.js"></script>
% if not use_buefy:
<script type="text/javascript">
var ctx = null;
var chart = null;
function fetchReadings(timeRange) {
if (timeRange === undefined) {
timeRange = $('#time-range').val();
}
var timeUnit;
if (timeRange == 'last hour') {
timeUnit = 'minute';
} else if (['last 6 hours', 'last day'].includes(timeRange)) {
timeUnit = 'hour';
} else {
timeUnit = 'day';
}
$('.form-wrapper').mask("Fetching data");
if (chart) {
chart.destroy();
}
$.get('${url('{}.graph_readings'.format(route_prefix), uuid=probe.uuid)}', {'time-range': timeRange}, function(data) {
chart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [{
label: "${probe.description}",
data: data
}]
},
options: {
scales: {
xAxes: [{
type: 'time',
time: {unit: timeUnit},
position: 'bottom'
}]
}
}
});
$('.form-wrapper').unmask();
});
}
$(function() {
ctx = $('#tempchart');
$('#time-range').selectmenu({
change: function(event, ui) {
fetchReadings(ui.item.value);
}
});
fetchReadings();
});
</script>
% endif
</%def>
<%def name="context_menu_items()">
@ -89,50 +24,23 @@
<div class="form-wrapper">
<div class="form">
% if use_buefy:
<b-field horizontal label="Appliance">
<div>
% if probe.appliance:
<a href="${url('tempmon.appliances.view', uuid=probe.appliance.uuid)}">${probe.appliance}</a>
% endif
</div>
</b-field>
% else:
<div class="field-wrapper">
<label>Appliance</label>
<div class="field">
% if probe.appliance:
<a href="${url('tempmon.appliances.view', uuid=probe.appliance.uuid)}">${probe.appliance}</a>
% endif
</div>
</div>
% endif
<b-field horizontal label="Appliance">
<div>
% if probe.appliance:
<a href="${url('tempmon.appliances.view', uuid=probe.appliance.uuid)}">${probe.appliance}</a>
% endif
</div>
</b-field>
% if use_buefy:
<b-field horizontal label="Probe Location">
<div>
${probe.location or ""}
</div>
</b-field>
% else:
<div class="field-wrapper">
<label>Probe Location</label>
<div class="field">${probe.location or ""}</div>
</div>
% endif
<b-field horizontal label="Probe Location">
<div>
${probe.location or ""}
</div>
</b-field>
% if use_buefy:
<b-field horizontal label="Showing">
${time_range}
</b-field>
% else:
<div class="field-wrapper">
<label>Showing</label>
<div class="field">
${time_range}
</div>
</div>
% endif
<b-field horizontal label="Showing">
${time_range}
</b-field>
</div>
</div>
@ -149,11 +57,7 @@
</div>
% if use_buefy:
<canvas ref="tempchart" width="400" height="150"></canvas>
% else:
<canvas id="tempchart" width="400" height="150"></canvas>
% endif
<canvas ref="tempchart" width="400" height="150"></canvas>
</%def>
<%def name="modify_this_page_vars()">

View file

@ -2,86 +2,48 @@
<%inherit file="/master/view.mako" />
<%def name="render_form_complete()">
% if use_buefy:
## ${self.render_form()}
## ${self.render_form()}
<script type="text/x-template" id="form-page-template">
<script type="text/x-template" id="form-page-template">
<div style="display: flex; justify-content: space-between;">
<div style="display: flex; justify-content: space-between;">
<div class="form-wrapper">
<div class="form-wrapper">
<div style="display: flex; flex-direction: column;">
<div style="display: flex; flex-direction: column;">
<nav class="panel" id="probe-main">
<p class="panel-heading">General</p>
<div class="panel-block">
<div>
${self.render_main_fields(form)}
</div>
</div>
</nav>
<div style="display: flex;">
<div class="panel-wrapper">
${self.left_column()}
</div>
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div>
<nav class="panel" id="probe-main">
<p class="panel-heading">General</p>
<div class="panel-block">
<div>
${self.render_main_fields(form)}
</div>
</div>
</nav>
<div style="display: flex;">
<div class="panel-wrapper">
${self.left_column()}
</div>
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div>
</div>
<ul id="context-menu">
${self.context_menu_items()}
</ul>
</div>
</script>
<div id="form-page-app">
<form-page></form-page>
</div>
% else:
## legacy / not buefy
<ul id="context-menu">
${self.context_menu_items()}
</ul>
<div style="display: flex; justify-content: space-between;">
</div>
</script>
<div class="form-wrapper">
<div style="display: flex; flex-direction: column;">
<div class="panel" id="probe-main">
<h2>General</h2>
<div class="panel-body">
<div>
${self.render_main_fields(form)}
</div>
</div>
</div>
<div style="display: flex;">
<div class="panel-wrapper">
${self.left_column()}
</div>
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div>
</div>
</div>
</div>
<ul id="context-menu">
${self.context_menu_items()}
</ul>
</div>
% endif
<div id="form-page-app">
<form-page></form-page>
</div>
</%def>
@ -113,43 +75,25 @@
</%def>
<%def name="left_column()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Temperatures</p>
<div class="panel-block">
<div>
${self.render_temperature_fields(form)}
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Temperatures</h2>
<div class="panel-body">
${self.render_temperature_fields(form)}
<nav class="panel">
<p class="panel-heading">Temperatures</p>
<div class="panel-block">
<div>
${self.render_temperature_fields(form)}
</div>
</div>
</div>
% endif
</nav>
</%def>
<%def name="right_column()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Timeouts</p>
<div class="panel-block">
<div>
${self.render_timeout_fields(form)}
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Timeouts</h2>
<div class="panel-body">
${self.render_timeout_fields(form)}
<nav class="panel">
<p class="panel-heading">Timeouts</p>
<div class="panel-block">
<div>
${self.render_timeout_fields(form)}
</div>
</div>
</div>
% endif
</nav>
</%def>
<%def name="render_temperature_fields(form)">

View file

@ -353,14 +353,10 @@
<div class="level">
<div class="level-right">
<div class="level-item">
% if use_buefy:
<b-input name="entry"
placeholder="${quickie.placeholder}"
autocomplete="off">
</b-input>
% else:
${h.text('entry', placeholder=quickie.placeholder, autocomplete='off')}
% endif
<b-input name="entry"
placeholder="${quickie.placeholder}"
autocomplete="off">
</b-input>
</div>
<div class="level-item">
<button type="submit" class="button is-primary">
@ -706,54 +702,38 @@
% if show_prev_next is not Undefined and show_prev_next:
% if prev_url:
<div class="level-item">
% if use_buefy:
<b-button tag="a" href="${prev_url}"
icon-pack="fas"
icon-left="arrow-left">
Older
</b-button>
% else:
${h.link_to(u"« Older", prev_url, class_='button autodisable')}
% endif
<b-button tag="a" href="${prev_url}"
icon-pack="fas"
icon-left="arrow-left">
Older
</b-button>
</div>
% else:
<div class="level-item">
% if use_buefy:
<b-button tag="a" href="#"
disabled
icon-pack="fas"
icon-left="arrow-left">
Older
</b-button>
% else:
${h.link_to(u"« Older", '#', class_='button', disabled='disabled')}
% endif
<b-button tag="a" href="#"
disabled
icon-pack="fas"
icon-left="arrow-left">
Older
</b-button>
</div>
% endif
% if next_url:
<div class="level-item">
% if use_buefy:
<b-button tag="a" href="${next_url}"
icon-pack="fas"
icon-left="arrow-right">
Newer
</b-button>
% else:
${h.link_to(u"Newer »", next_url, class_='button autodisable')}
% endif
<b-button tag="a" href="${next_url}"
icon-pack="fas"
icon-left="arrow-right">
Newer
</b-button>
</div>
% else:
<div class="level-item">
% if use_buefy:
<b-button tag="a" href="#"
disabled
icon-pack="fas"
icon-left="arrow-right">
Newer
</b-button>
% else:
${h.link_to(u"Newer »", '#', class_='button', disabled='disabled')}
% endif
<b-button tag="a" href="#"
disabled
icon-pack="fas"
icon-left="arrow-right">
Newer
</b-button>
</div>
% endif
% endif

View file

@ -1,43 +1,6 @@
## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
function show_packages(type) {
if (type == 'all') {
$('.showing .diffs').css('font-weight', 'normal');
$('table.diff tbody tr').show();
$('.showing .all').css('font-weight', 'bold');
} else if (type == 'diffs') {
$('.showing .all').css('font-weight', 'normal');
$('table.diff tbody tr:not(.diff)').hide();
$('.showing .diffs').css('font-weight', 'bold');
}
}
$(function() {
show_packages('diffs');
$('.showing .all').click(function() {
show_packages('all');
return false;
});
$('.showing .diffs').click(function() {
show_packages('diffs')
return false;
});
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
% if master.has_perm('execute'):
@ -132,7 +95,7 @@
% if instance_executable and master.has_perm('execute'):
<div class="buttons">
% if instance.enabled and not instance.executing:
% if use_buefy and expose_websockets:
% if expose_websockets:
<b-button type="is-primary"
icon-pack="fas"
icon-left="arrow-circle-right"
@ -140,7 +103,7 @@
@click="$emit('execute-upgrade-click')">
{{ upgradeExecuting ? "Working, please wait..." : "Execute this upgrade" }}
</b-button>
% elif use_buefy:
% else:
${h.form(url('{}.execute'.format(route_prefix), uuid=instance.uuid), **{'@submit': 'submitForm'})}
${h.csrf_token(request)}
<b-button type="is-primary"
@ -151,11 +114,6 @@
{{ formSubmitting ? "Working, please wait..." : "Execute this upgrade" }}
</b-button>
${h.end_form()}
% else:
${h.form(url('{}.execute'.format(route_prefix), uuid=instance.uuid), class_='autodisable')}
${h.csrf_token(request)}
${h.submit('execute', "Execute this upgrade", class_='button is-primary')}
${h.end_form()}
% endif
% elif instance.enabled:
<button type="button" class="button is-primary" disabled="disabled" title="This upgrade is currently executing">Execute this upgrade</button>

View file

@ -2,43 +2,27 @@
<%def name="view_profile_button(person)">
<div class="buttons">
% if use_buefy:
<b-button type="is-primary"
tag="a" href="${url('people.view_profile', uuid=person.uuid)}"
icon-pack="fas"
icon-left="user">
${person}
</b-button>
% else:
${h.link_to(person, url('people.view_profile', uuid=person.uuid), class_='button is-primary')}
% endif
<b-button type="is-primary"
tag="a" href="${url('people.view_profile', uuid=person.uuid)}"
icon-pack="fas"
icon-left="user">
${person}
</b-button>
</div>
</%def>
<%def name="view_profiles_helper(people)">
% if request.has_perm('people.view_profile'):
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Profiles</p>
<div class="panel-block">
<div style="display: flex; flex-direction: column;">
<p class="block">View full profile for:</p>
% for person in people:
${view_profile_button(person)}
% endfor
</div>
</div>
</nav>
% else:
<div class="object-helper">
<h3>Profiles</h3>
<div class="object-helper-content">
<p>View full profile for:</p>
% for person in people:
${view_profile_button(person)}
% endfor
</div>
<nav class="panel">
<p class="panel-heading">Profiles</p>
<div class="panel-block">
<div style="display: flex; flex-direction: column;">
<p class="block">View full profile for:</p>
% for person in people:
${view_profile_button(person)}
% endfor
</div>
% endif
</div>
</nav>
% endif
</%def>

View file

@ -24,11 +24,8 @@
Utilities
"""
from __future__ import unicode_literals, absolute_import
import datetime
import six
import pytz
import humanize
import logging
@ -198,26 +195,6 @@ def get_liburl(request, key, fallback=True):
return 'https://code.jquery.com/ui/{}/themes/dark-hive/jquery-ui.css'.format(version)
def should_use_buefy(request):
"""
Returns a flag indicating whether or not the current theme supports (and
therefore should use) the Buefy JS library.
"""
# first check theme-specific setting, if one has been defined
theme = request.registry.settings['tailbone.theme']
buefy = request.rattail_config.getbool('tailbone', 'themes.{}.use_buefy'.format(theme))
if buefy is not None:
return buefy
# TODO: should not hard-code this surely, but works for now...
if theme == 'falafel':
return True
# TODO: probably should not use this fallback? it was the first setting
# i tested with, but is poorly named to say the least
return request.rattail_config.getbool('tailbone', 'grids.use_buefy', default=False)
def pretty_datetime(config, value):
"""
Formats a datetime as a "pretty" human-readable string, with a tooltip
@ -284,7 +261,7 @@ def raw_datetime(config, value, verbose=False, as_date=False):
else:
kwargs['c'] = value.strftime('%Y-%m-%d %I:%M:%S %p')
else:
kwargs['c'] = six.text_type(value)
kwargs['c'] = str(value)
time_diff = app.render_time_ago(time_ago, fallback=None)
if time_diff is not None:

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,8 +24,6 @@
Auth Views
"""
from __future__ import unicode_literals, absolute_import
from rattail.db.auth import authenticate_user, set_user_password
import colander
@ -101,9 +99,7 @@ class AuthenticationView(View):
self.request.session.flash("{} is already logged in".format(self.request.user), 'error')
return self.redirect(referrer)
use_buefy = self.get_use_buefy()
form = forms.Form(schema=UserLogin(), request=self.request,
use_buefy=use_buefy)
form = forms.Form(schema=UserLogin(), request=self.request)
form.save_label = "Login"
form.auto_disable_save = False
form.auto_disable = False # TODO: deprecate / remove this
@ -126,16 +122,13 @@ class AuthenticationView(View):
'tailbone', 'main_image_url',
default=self.request.static_url('tailbone:static/img/home_logo.png'))
context = {
return {
'form': form,
'referrer': referrer,
'image_url': image_url,
'use_buefy': use_buefy,
'index_title': self.rattail_config.node_title(),
'help_url': global_help_url(self.rattail_config),
}
if use_buefy:
context['index_title'] = self.rattail_config.node_title()
return context
def authenticate_user(self, username, password):
app = self.get_rattail_app()
@ -177,15 +170,14 @@ class AuthenticationView(View):
self.request.session.flash("Cannot change password for user: {}".format(self.request.user))
return self.redirect(self.request.get_referrer())
use_buefy = self.get_use_buefy()
schema = ChangePassword().bind(user=self.request.user, request=self.request)
form = forms.Form(schema=schema, request=self.request, use_buefy=use_buefy)
form = forms.Form(schema=schema, request=self.request)
if form.validate(newstyle=True):
set_user_password(self.request.user, form.validated['new_password'])
self.request.session.flash("Your password has been changed.")
return self.redirect(self.request.get_referrer())
return {'form': form, 'use_buefy': use_buefy}
return {'form': form}
def become_root(self):
"""

View file

@ -24,8 +24,6 @@
Base views for maintaining "new-style" batches.
"""
from __future__ import unicode_literals, absolute_import
import os
import sys
import json
@ -37,7 +35,6 @@ import tempfile
from six import StringIO
import json
import six
import markdown
import sqlalchemy as sa
from sqlalchemy import orm
@ -172,7 +169,6 @@ class BatchMasterView(MasterView):
def template_kwargs_view(self, **kwargs):
kwargs = super(BatchMasterView, self).template_kwargs_view(**kwargs)
use_buefy = self.get_use_buefy()
batch = kwargs['instance']
kwargs['batch'] = batch
kwargs['handler'] = self.handler
@ -194,30 +190,22 @@ class BatchMasterView(MasterView):
breakdown = self.make_status_breakdown(batch)
if use_buefy:
factory = self.get_grid_factory()
g = factory('batch_row_status_breakdown', [],
columns=['title', 'count'])
g.set_click_handler('title', "autoFilterStatus(props.row)")
kwargs['status_breakdown_data'] = breakdown
kwargs['status_breakdown_grid'] = HTML.literal(
g.render_buefy_table_element(data_prop='statusBreakdownData',
empty_labels=True))
else:
kwargs['status_breakdown'] = [
(status['title'], status['count'])
for status in breakdown]
factory = self.get_grid_factory()
g = factory('batch_row_status_breakdown', [],
columns=['title', 'count'])
g.set_click_handler('title', "autoFilterStatus(props.row)")
kwargs['status_breakdown_data'] = breakdown
kwargs['status_breakdown_grid'] = HTML.literal(
g.render_buefy_table_element(data_prop='statusBreakdownData',
empty_labels=True))
return kwargs
def make_upload_worksheet_form(self, batch):
action_url = self.get_action_url('upload_worksheet', batch)
use_buefy = self.get_use_buefy()
form = forms.Form(schema=UploadWorksheet(),
request=self.request,
action_url=action_url,
use_buefy=use_buefy,
component='upload-worksheet-form')
form.set_type('worksheet_file', 'file')
# TODO: must set these to avoid some default Buefy code
@ -431,7 +419,6 @@ class BatchMasterView(MasterView):
return dict(batch.params or {})
def render_complete(self, batch, field):
use_buefy = self.get_use_buefy()
text = "Yes" if batch.complete else "No"
if batch.executed or not self.has_perm('edit'):
@ -446,18 +433,13 @@ class BatchMasterView(MasterView):
url = self.get_action_url('toggle_complete', batch)
kwargs = {'@submit': 'togglingBatchComplete = true'}
if not use_buefy:
kwargs['class_'] = 'autodisable'
begin_form = tags.form(url, **kwargs)
if use_buefy:
label = HTML.literal(
'{{{{ togglingBatchComplete ? "Working, please wait..." : "{}" }}}}'.format(label))
submit = self.make_buefy_button(label, is_primary=True,
native_type='submit',
**{':disabled': 'togglingBatchComplete'})
else:
submit = tags.submit('submit', label)
label = HTML.literal(
'{{{{ togglingBatchComplete ? "Working, please wait..." : "{}" }}}}'.format(label))
submit = self.make_buefy_button(label, is_primary=True,
native_type='submit',
**{':disabled': 'togglingBatchComplete'})
form = [
begin_form,
@ -467,23 +449,16 @@ class BatchMasterView(MasterView):
tags.end_form(),
]
if use_buefy:
text = HTML.tag('div', class_='control', c=text)
form = HTML.tag('div', class_='control', c=form)
content = [
HTML.tag('nav', class_='level',
c=[HTML.tag('div', class_='level-left', c=[
text,
HTML.literal(' &nbsp; &nbsp; '),
form,
])]),
]
else:
content = [
text,
HTML.literal(' &nbsp; '),
] + form
text = HTML.tag('div', class_='control', c=text)
form = HTML.tag('div', class_='control', c=form)
content = [
HTML.tag('nav', class_='level',
c=[HTML.tag('div', class_='level-left', c=[
text,
HTML.literal(' &nbsp; &nbsp; '),
form,
])]),
]
return HTML.tag('div', c=content)
@ -491,7 +466,7 @@ class BatchMasterView(MasterView):
user = getattr(batch, field)
if not user:
return ""
title = six.text_type(user)
title = str(user)
url = self.request.route_url('users.view', uuid=user.uuid)
return tags.link_to(title, url)
@ -513,7 +488,7 @@ class BatchMasterView(MasterView):
# TODO: this needs work yet surely...why is this an issue?
# treat 'filename' field specially, for some reason it can be a filedict?
if 'filename' in kwargs and not isinstance(kwargs['filename'], six.string_types):
if 'filename' in kwargs and not isinstance(kwargs['filename'], str):
kwargs['filename'] = '' # null not allowed
# TODO: is this still necessary with colander?
@ -533,7 +508,7 @@ class BatchMasterView(MasterView):
os.remove(upload['temp_path'])
os.rmdir(upload['tempdir'])
for key, upload in six.iteritems(uploads):
for key, upload in uploads.items():
if isinstance(upload, dict):
process(upload, key)
else:
@ -657,7 +632,7 @@ class BatchMasterView(MasterView):
code = row.status_code
if code is None:
return ""
text = self.get_row_status_enum().get(code, six.text_type(code))
text = self.get_row_status_enum().get(code, str(code))
if row.status_text:
return HTML.tag('span', title=row.status_text, c=text)
return text
@ -707,21 +682,12 @@ class BatchMasterView(MasterView):
permission_prefix = self.get_permission_prefix()
if self.request.has_perm('{}.create_row'.format(permission_prefix)):
url = self.get_action_url('create_row', batch)
if self.get_use_buefy():
return self.make_buefy_button("New Row", url=url,
is_primary=True,
icon_left='plus')
else:
text = "Create a new {}".format(self.get_row_model_title())
link = tags.link_to(text, url)
return HTML.tag('p', c=[link])
return self.make_buefy_button("New Row", url=url,
is_primary=True,
icon_left='plus')
def make_batch_row_grid_tools(self, batch):
if self.get_use_buefy():
return
if self.rows_bulk_deletable and not batch.executed and self.request.has_perm('{}.delete_rows'.format(self.get_permission_prefix())):
url = self.request.route_url('{}.delete_rows'.format(self.get_route_prefix()), uuid=batch.uuid)
return HTML.tag('p', c=[tags.link_to("Delete all rows matching current search", url)])
pass
def make_row_grid_kwargs(self, **kwargs):
"""
@ -733,21 +699,19 @@ class BatchMasterView(MasterView):
# TODO: most of this logic is copied from MasterView, should refactor/merge somehow...
if 'main_actions' not in kwargs:
actions = []
use_buefy = self.get_use_buefy()
# view action
if self.rows_viewable:
view = lambda r, i: self.get_row_action_url('view', r)
icon = 'eye' if use_buefy else 'zoomin'
actions.append(self.make_action('view', icon=icon, url=view))
actions.append(self.make_action('view', icon='eye', url=view))
# edit and delete are NOT allowed after execution, or if batch is "complete"
if not batch.executed and not batch.complete:
# edit action
if self.rows_editable and self.has_perm('edit_row'):
icon = 'edit' if use_buefy else 'pencil'
actions.append(self.make_action('edit', icon=icon, url=self.row_edit_action_url))
actions.append(self.make_action('edit', icon='edit',
url=self.row_edit_action_url))
# delete action
if self.rows_deletable and self.has_perm('delete_row'):
@ -793,7 +757,7 @@ class BatchMasterView(MasterView):
# nb. must make new session, separate from main thread
session = app.make_session()
batch = self.get_instance_for_key(key, session)
batch_str = six.text_type(batch)
batch_str = str(batch)
try:
# try to delete batch
@ -869,7 +833,6 @@ class BatchMasterView(MasterView):
"""
defaults = {}
route_prefix = self.get_route_prefix()
use_buefy = self.get_use_buefy()
schema = None
if self.has_execution_options(batch):
@ -891,13 +854,12 @@ class BatchMasterView(MasterView):
labels[field.name] = field.title
# auto-convert select widgets for buefy theme
if use_buefy and isinstance(field.widget, forms.widgets.PlainSelectWidget):
if isinstance(field.widget, forms.widgets.PlainSelectWidget):
field.widget = dfwidget.SelectWidget(values=field.widget.values)
if not schema:
schema = colander.Schema()
kwargs['use_buefy'] = use_buefy
kwargs['component'] = 'execute-form'
form = forms.Form(schema=schema, request=self.request, defaults=defaults, **kwargs)
self.configure_execute_form(form)
@ -1051,8 +1013,7 @@ class BatchMasterView(MasterView):
data = json.dumps({
'everything_complete': True,
})
if six.PY3:
data = data.encode('utf_8')
data = data.encode('utf_8')
cxn.send(data)
cxn.send(suffix)
cxn.close()
@ -1061,7 +1022,7 @@ class BatchMasterView(MasterView):
with short_session() as s:
batch = s.query(self.model_class).get(batch_uuid)
batch_id = batch.id_str
description = six.text_type(batch)
description = str(batch)
self.launch_subprocess(
port=port, username=username,

View file

@ -24,8 +24,6 @@
Views for importer batches
"""
from __future__ import unicode_literals, absolute_import
import sqlalchemy as sa
from rattail.db import model
@ -139,7 +137,6 @@ class ImporterBatchView(BatchMasterView):
def configure_row_grid(self, g):
super(ImporterBatchView, self).configure_row_grid(g)
use_buefy = self.get_use_buefy()
def make_filter(field, **kwargs):
column = getattr(self.current_row_table.c, field)
@ -150,11 +147,8 @@ class ImporterBatchView(BatchMasterView):
# for some reason we have to do this differently for Buefy?
kwargs = {}
if not use_buefy:
kwargs['value_enum'] = self.enum.IMPORTER_BATCH_ROW_STATUS
make_filter('status_code', label="Status", **kwargs)
if use_buefy:
g.filters['status_code'].set_choices(self.enum.IMPORTER_BATCH_ROW_STATUS)
g.filters['status_code'].set_choices(self.enum.IMPORTER_BATCH_ROW_STATUS)
def make_sorter(field):
column = getattr(self.current_row_table.c, field)

View file

@ -24,14 +24,10 @@
Views for inventory batches
"""
from __future__ import unicode_literals, absolute_import
import re
import decimal
import logging
import six
from rattail import pod
from rattail.db import model
from rattail.db.util import make_full_description
@ -234,9 +230,8 @@ class InventoryBatchView(BatchMasterView):
if batch.executed:
return self.redirect(self.get_action_url('view', batch))
use_buefy = self.get_use_buefy()
schema = DesktopForm().bind(session=self.Session())
form = forms.Form(schema=schema, request=self.request, use_buefy=use_buefy)
form = forms.Form(schema=schema, request=self.request)
if self.request.method == 'POST':
if form.validate(newstyle=True):
@ -273,7 +268,7 @@ class InventoryBatchView(BatchMasterView):
else:
dform = form.make_deform_form()
msg = "Form did not validate: {}".format(six.text_type(dform.error))
msg = "Form did not validate: {}".format(str(dform.error))
self.request.session.flash(msg, 'error')
title = self.get_instance_title(batch)
@ -345,7 +340,7 @@ class InventoryBatchView(BatchMasterView):
upc = re.sub(r'\D', '', entry.strip())
if upc:
upc = GPC(upc)
result['upc'] = six.text_type(upc)
result['upc'] = str(upc)
result['upc_pretty'] = upc.pretty()
result['image_url'] = pod.get_image_url(self.rattail_config, upc)
@ -374,10 +369,10 @@ class InventoryBatchView(BatchMasterView):
data = {}
if product and (not product.deleted or self.request.has_perm('products.view_deleted')):
data['uuid'] = product.uuid
data['upc'] = six.text_type(product.upc)
data['upc'] = str(product.upc)
data['upc_pretty'] = product.upc.pretty()
data['full_description'] = product.full_description
data['brand_name'] = six.text_type(product.brand or '')
data['brand_name'] = str(product.brand or '')
data['description'] = product.description
data['size'] = product.size
data['case_quantity'] = 1 # default

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,12 +24,8 @@
Views for maintaining vendor catalogs
"""
from __future__ import unicode_literals, absolute_import
import logging
import six
from rattail.db import model
import colander
@ -196,9 +192,6 @@ class VendorCatalogView(FileBatchMasterView):
values = [(p.key, p.display) for p in parsers]
if len(values) == 1:
f.set_default('parser_key', parsers[0].key)
use_buefy = self.get_use_buefy()
if not use_buefy:
values.insert(0, ('', "(please choose)"))
f.set_widget('parser_key', dfwidget.SelectWidget(values=values))
else:
f.set_readonly('parser_key')
@ -235,7 +228,7 @@ class VendorCatalogView(FileBatchMasterView):
vendor = self.Session.query(model.Vendor).get(
self.request.POST['vendor_uuid'])
if vendor:
vendor_display = six.text_type(vendor)
vendor_display = str(vendor)
f.set_widget('vendor_uuid',
forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display,
@ -275,35 +268,20 @@ class VendorCatalogView(FileBatchMasterView):
return parser.display
def template_kwargs_create(self, **kwargs):
use_buefy = self.get_use_buefy()
app = self.get_rattail_app()
vendor_handler = app.get_vendor_handler()
parsers = self.get_parsers()
parsers_data = {}
for parser in parsers:
if use_buefy:
pdata = {'key': parser.key,
'vendor_key': parser.vendor_key}
if parser.vendor_key:
vendor = vendor_handler.get_vendor(self.Session(),
parser.vendor_key)
if vendor:
pdata['vendor_uuid'] = vendor.uuid
pdata['vendor_name'] = vendor.name
parsers_data[parser.key] = pdata
else:
if parser.vendor_key:
vendor = vendor_handler.get_vendor(self.Session(),
parser.vendor_key)
if vendor:
parser.vendormap_value = "{{uuid: '{}', name: '{}'}}".format(
vendor.uuid, vendor.name.replace("'", "\\'"))
else:
log.warning("vendor '{}' not found for parser: {}".format(
parser.vendor_key, parser.key))
parser.vendormap_value = 'null'
else:
parser.vendormap_value = 'null'
pdata = {'key': parser.key,
'vendor_key': parser.vendor_key}
if parser.vendor_key:
vendor = vendor_handler.get_vendor(self.Session(),
parser.vendor_key)
if vendor:
pdata['vendor_uuid'] = vendor.uuid
pdata['vendor_name'] = vendor.name
parsers_data[parser.key] = pdata
kwargs['parsers'] = parsers
kwargs['parsers_data'] = parsers_data
return kwargs

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,10 +24,7 @@
Various common views
"""
from __future__ import unicode_literals, absolute_import
import os
import six
from rattail.batch import consume_batch_id
from rattail.util import OrderedDict, simple_error, import_module_path
@ -62,14 +59,11 @@ class CommonView(View):
'tailbone', 'main_image_url',
default=self.request.static_url('tailbone:static/img/home_logo.png'))
use_buefy = self.get_use_buefy()
context = {
'image_url': image_url,
'use_buefy': use_buefy,
'index_title': self.rattail_config.node_title(),
'help_url': global_help_url(self.rattail_config),
}
if use_buefy:
context['index_title'] = self.rattail_config.node_title()
if self.expose_quickie_search:
context['quickie'] = self.get_quickie_context()
@ -83,12 +77,8 @@ class CommonView(View):
with open(self.robots_txt_path, 'rt') as f:
content = f.read()
response = self.request.response
if six.PY3:
response.text = content
response.content_type = 'text/plain'
else:
response.body = content
response.content_type = b'text/plain'
response.text = content
response.content_type = 'text/plain'
return response
def get_project_title(self):
@ -114,16 +104,12 @@ class CommonView(View):
"""
Generic view to show "about project" info page.
"""
use_buefy = self.get_use_buefy()
context = {
return {
'project_title': self.get_project_title(),
'project_version': self.get_project_version(),
'packages': self.get_packages(),
'use_buefy': use_buefy,
'index_title': self.rattail_config.node_title(),
}
if use_buefy:
context['index_title'] = self.rattail_config.node_title()
return context
def get_packages(self):
"""
@ -203,7 +189,6 @@ class CommonView(View):
if not self.request.is_root:
raise self.forbidden()
use_buefy = self.get_use_buefy()
app = self.get_rattail_app()
app_title = self.rattail_config.app_title()
poser_handler = app.get_poser_handler()
@ -253,7 +238,6 @@ class CommonView(View):
poser_error = simple_error(error)
return {
'use_buefy': use_buefy,
'app_title': app_title,
'index_title': app_title,
'poser_dir': poser_dir,

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,12 +24,8 @@
Base View Class
"""
from __future__ import unicode_literals, absolute_import
import os
import six
from rattail.db import model
from rattail.core import Object
from rattail.util import progress_loop
@ -41,7 +37,6 @@ from pyramid.response import FileResponse
from tailbone.db import Session
from tailbone.auth import logout_user
from tailbone.progress import SessionProgress
from tailbone.util import should_use_buefy
from tailbone.config import protected_usernames
@ -94,13 +89,6 @@ class View(object):
def notfound(self):
return httpexceptions.HTTPNotFound()
def get_use_buefy(self):
"""
Returns a flag indicating whether or not the current theme supports
(and therefore should use) the Buefy JS library.
"""
return should_use_buefy(self.request)
def late_login_user(self):
"""
Returns the :class:`rattail:rattail.db.model.User` instance
@ -170,8 +158,6 @@ class View(object):
if attachment:
if not filename:
filename = os.path.basename(path)
if six.PY2:
filename = filename.encode('ascii', 'replace')
response.content_disposition = str('attachment; filename="{}"'.format(filename))
return response

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,9 +24,6 @@
Customer Views
"""
from __future__ import unicode_literals, absolute_import
import six
import sqlalchemy as sa
import colander
@ -205,7 +202,6 @@ class CustomerView(MasterView):
super(CustomerView, self).configure_common_form(f)
customer = f.model_instance
permission_prefix = self.get_permission_prefix()
use_buefy = self.get_use_buefy()
f.set_renderer('default_email', self.render_default_email)
if not self.creating and customer.emails:
@ -251,12 +247,7 @@ class CustomerView(MasterView):
# people
if self.viewing:
if use_buefy:
f.set_renderer('people', self.render_people_buefy)
elif self.people_detachable and self.has_perm('detach_person'):
f.set_renderer('people', self.render_people_removable)
else:
f.set_renderer('people', self.render_people)
f.set_renderer('people', self.render_people_buefy)
else:
f.remove('people')
@ -288,30 +279,28 @@ class CustomerView(MasterView):
kwargs['show_profiles_helper'] = self.show_profiles_helper
use_buefy = self.get_use_buefy()
if use_buefy:
customer = kwargs['instance']
people = []
for person in customer.people:
data = {
'uuid': person.uuid,
'full_name': person.display_name,
'first_name': person.first_name,
'last_name': person.last_name,
'_action_url_view': self.request.route_url('people.view',
uuid=person.uuid),
}
if self.editable and self.request.has_perm('people.edit'):
data['_action_url_edit'] = self.request.route_url(
'people.edit',
uuid=person.uuid)
if self.people_detachable and self.has_perm('detach_person'):
data['_action_url_detach'] = self.request.route_url(
'customers.detach_person',
uuid=customer.uuid,
person_uuid=person.uuid)
people.append(data)
kwargs['people_data'] = people
customer = kwargs['instance']
people = []
for person in customer.people:
data = {
'uuid': person.uuid,
'full_name': person.display_name,
'first_name': person.first_name,
'last_name': person.last_name,
'_action_url_view': self.request.route_url('people.view',
uuid=person.uuid),
}
if self.editable and self.request.has_perm('people.edit'):
data['_action_url_edit'] = self.request.route_url(
'people.edit',
uuid=person.uuid)
if self.people_detachable and self.has_perm('detach_person'):
data['_action_url_detach'] = self.request.route_url(
'customers.detach_person',
uuid=customer.uuid,
person_uuid=person.uuid)
people.append(data)
kwargs['people_data'] = people
return kwargs
@ -326,20 +315,20 @@ class CustomerView(MasterView):
def render_default_address(self, customer, field):
if customer.addresses:
return six.text_type(customer.addresses[0])
return str(customer.addresses[0])
def grid_render_person(self, customer, field):
person = getattr(customer, field)
if not person:
return ""
return six.text_type(person)
return str(person)
def form_render_person(self, customer, field):
person = getattr(customer, field)
if not person:
return ""
text = six.text_type(person)
text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url)
@ -350,12 +339,13 @@ class CustomerView(MasterView):
items = []
for person in people:
text = six.text_type(person)
text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid)
link = tags.link_to(text, url)
items.append(HTML.tag('li', c=[link]))
return HTML.tag('ul', c=items)
# TODO: remove if no longer used
def render_people_removable(self, customer, field):
people = customer.people
if not people:
@ -431,7 +421,7 @@ class CustomerView(MasterView):
return ""
items = []
for member in members:
text = six.text_type(member)
text = str(member)
url = self.request.route_url('members.view', uuid=member.uuid)
items.append(HTML.tag('li', tags.link_to(text, url)))
return HTML.tag('ul', HTML.literal('').join(items))
@ -587,7 +577,7 @@ class PendingCustomerView(MasterView):
g.set_enum('status_code', self.enum.PENDING_CUSTOMER_STATUS)
g.filters['status_code'].default_active = True
g.filters['status_code'].default_verb = 'not_equal'
g.filters['status_code'].default_value = six.text_type(self.enum.PENDING_CUSTOMER_STATUS_RESOLVED)
g.filters['status_code'].default_value = str(self.enum.PENDING_CUSTOMER_STATUS_RESOLVED)
g.set_sort_defaults('display_name')
g.set_link('id')

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,11 +24,8 @@
Customer order item views
"""
from __future__ import unicode_literals, absolute_import
import datetime
import six
from sqlalchemy import orm
from rattail.db import model
@ -156,7 +153,7 @@ class CustomerOrderItemView(MasterView):
def render_person_text(self, item, field):
person = item.order.person
if person:
text = six.text_type(person)
text = str(person)
return text
def render_order_created(self, item, column):
@ -165,14 +162,13 @@ class CustomerOrderItemView(MasterView):
def render_status_code_column(self, item, field):
text = self.enum.CUSTORDER_ITEM_STATUS.get(item.status_code,
six.text_type(item.status_code))
str(item.status_code))
if item.status_text:
return HTML.tag('span', title=item.status_text, c=[text])
return text
def configure_form(self, f):
super(CustomerOrderItemView, self).configure_form(f)
use_buefy = self.get_use_buefy()
item = f.model_instance
# order
@ -222,10 +218,7 @@ class CustomerOrderItemView(MasterView):
f.set_renderer('status_code', self.render_status_code)
# notes
if use_buefy:
f.set_renderer('notes', self.render_notes)
else:
f.remove('notes')
f.set_renderer('notes', self.render_notes)
def highlight_pending_field(self, item, field, value=None):
if value is None:
@ -271,13 +264,12 @@ class CustomerOrderItemView(MasterView):
return outer
def render_status_code(self, item, field):
use_buefy = self.get_use_buefy()
text = self.enum.CUSTORDER_ITEM_STATUS[item.status_code]
if item.status_text:
text = "{} ({})".format(text, item.status_text)
items = [HTML.tag('span', c=[text])]
if use_buefy and self.has_perm('change_status'):
if self.has_perm('change_status'):
button = HTML.tag('b-button', type='is-primary', c="Change Status",
style='margin-left: 1rem;',
icon_pack='fas', icon_left='edit',
@ -484,14 +476,14 @@ class CustomerOrderItemView(MasterView):
order = item.order
if not order:
return ""
text = six.text_type(order)
text = str(order)
url = self.request.route_url('custorders.view', uuid=order.uuid)
return tags.link_to(text, url)
def render_person(self, item, field):
person = item.order.person
if person:
text = six.text_type(person)
text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url)

View file

@ -24,15 +24,10 @@
Department Views
"""
from __future__ import unicode_literals, absolute_import
import six
from rattail.db import model
from webhelpers2.html import HTML
from tailbone import grids
from tailbone.views import MasterView
@ -99,11 +94,10 @@ class DepartmentView(MasterView):
def configure_form(self, f):
super(DepartmentView, self).configure_form(f)
use_buefy = self.get_use_buefy()
f.remove_field('subdepartments')
if not use_buefy or self.creating or self.editing:
if self.creating or self.editing:
f.remove('employees')
else:
f.set_renderer('employees', self.render_employees)
@ -137,33 +131,20 @@ class DepartmentView(MasterView):
def template_kwargs_view(self, **kwargs):
kwargs = super(DepartmentView, self).template_kwargs_view(**kwargs)
use_buefy = self.get_use_buefy()
department = kwargs['instance']
department_employees = sorted(department.employees, key=six.text_type)
department_employees = sorted(department.employees, key=str)
if use_buefy:
employees = []
for employee in department_employees:
person = employee.person
employees.append({
'uuid': employee.uuid,
'first_name': person.first_name,
'last_name': person.last_name,
'_action_url_view': self.request.route_url('employees.view', uuid=employee.uuid),
'_action_url_edit': self.request.route_url('employees.edit', uuid=employee.uuid),
})
kwargs['employees_data'] = employees
else: # not buefy
if department.employees:
actions = [
grids.GridAction('view', icon='zoomin',
url=lambda r, i: self.request.route_url('employees.view', uuid=r.uuid))
]
kwargs['employees'] = grids.Grid(None, department_employees, ['display_name'], request=self.request,
model_class=model.Employee, main_actions=actions)
else:
kwargs['employees'] = None
employees = []
for employee in department_employees:
person = employee.person
employees.append({
'uuid': employee.uuid,
'first_name': person.first_name,
'last_name': person.last_name,
'_action_url_view': self.request.route_url('employees.view', uuid=employee.uuid),
'_action_url_edit': self.request.route_url('employees.edit', uuid=employee.uuid),
})
kwargs['employees_data'] = employees
return kwargs
@ -218,33 +199,14 @@ class DepartmentView(MasterView):
.distinct()\
.order_by(model.Department.name)
if self.get_use_buefy():
def normalize(dept):
return {
'uuid': dept.uuid,
'number': dept.number,
'name': dept.name,
}
def normalize(dept):
return {
'uuid': dept.uuid,
'number': dept.number,
'name': dept.name,
}
return self.json_response([normalize(d) for d in data])
# nb. the rest of this is legacy / not buefy
def configure(g):
g.configure(include=[
g.name,
], readonly=True)
def row_attrs(row, i):
return {'data-uuid': row.uuid}
grid = self.make_grid(data=data, sortable=False, filterable=False, pageable=False,
configure=configure, width=None, checkboxes=True,
row_attrs=row_attrs, main_actions=[], more_actions=[])
self.request.response.content_type = str('text/html')
self.request.response.text = grid.render_grid()
return self.request.response
return self.json_response([normalize(d) for d in data])
@classmethod
def defaults(cls, config):

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,9 +24,6 @@
Employee Views
"""
from __future__ import unicode_literals, absolute_import
import six
import sqlalchemy as sa
from rattail.db import model
@ -84,7 +81,6 @@ class EmployeeView(MasterView):
def configure_grid(self, g):
super(EmployeeView, self).configure_grid(g)
route_prefix = self.get_route_prefix()
use_buefy = self.get_use_buefy()
# phone
g.set_joiner('phone', lambda q: q.outerjoin(model.EmployeePhoneNumber, sa.and_(
@ -127,10 +123,7 @@ class EmployeeView(MasterView):
g.set_enum('status', self.enum.EMPLOYEE_STATUS)
g.filters['status'].default_active = True
g.filters['status'].default_verb = 'equal'
if use_buefy:
g.filters['status'].default_value = six.text_type(self.enum.EMPLOYEE_STATUS_CURRENT)
else:
g.filters['status'].default_value = self.enum.EMPLOYEE_STATUS_CURRENT
g.filters['status'].default_value = str(self.enum.EMPLOYEE_STATUS_CURRENT)
else:
g.remove('status')
del g.filters['status']
@ -202,7 +195,7 @@ class EmployeeView(MasterView):
f.set_label('stores', "Stores") # TODO: should not be necessary
if self.creating or self.editing:
stores = self.get_possible_stores().all()
store_values = [(s.uuid, six.text_type(s)) for s in stores]
store_values = [(s.uuid, str(s)) for s in stores]
f.set_node('stores', colander.SchemaNode(colander.Set()))
f.set_widget('stores', dfwidget.SelectWidget(multiple=True,
size=len(stores),
@ -214,7 +207,7 @@ class EmployeeView(MasterView):
f.set_label('departments', "Departments") # TODO: should not be necessary
if self.creating or self.editing:
departments = self.get_possible_departments().all()
dept_values = [(d.uuid, six.text_type(d)) for d in departments]
dept_values = [(d.uuid, str(d)) for d in departments]
f.set_node('departments', colander.SchemaNode(colander.Set()))
f.set_widget('departments', dfwidget.SelectWidget(multiple=True,
size=len(departments),
@ -284,7 +277,7 @@ class EmployeeView(MasterView):
person = employee.person if employee else None
if not person:
return ""
text = six.text_type(person)
text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url)
@ -293,8 +286,8 @@ class EmployeeView(MasterView):
if not stores:
return ""
items = []
for store in sorted(stores, key=six.text_type):
items.append(HTML.tag('li', c=six.text_type(store)))
for store in sorted(stores, key=str):
items.append(HTML.tag('li', c=str(store)))
return HTML.tag('ul', c=items)
def render_departments(self, employee, field):
@ -302,8 +295,8 @@ class EmployeeView(MasterView):
if not departments:
return ""
items = []
for department in sorted(departments, key=six.text_type):
items.append(HTML.tag('li', c=six.text_type(department)))
for department in sorted(departments, key=str):
items.append(HTML.tag('li', c=str(department)))
return HTML.tag('ul', c=items)
def touch_instance(self, employee):

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,9 +24,6 @@
Feature views
"""
from __future__ import unicode_literals, absolute_import
import six
import colander
import markdown
@ -49,20 +46,16 @@ class GenerateFeatureView(View):
return handler
def __call__(self):
use_buefy = self.get_use_buefy()
schema = self.handler.make_schema()
app_form = forms.Form(schema=schema, request=self.request,
use_buefy=use_buefy)
for key, value in six.iteritems(self.handler.get_defaults()):
app_form = forms.Form(schema=schema, request=self.request)
for key, value in self.handler.get_defaults().items():
app_form.set_default(key, value)
feature_forms = {}
for feature in self.handler.iter_features():
schema = feature.make_schema()
form = forms.Form(schema=schema, request=self.request,
use_buefy=use_buefy)
for key, value in six.iteritems(feature.get_defaults()):
form = forms.Form(schema=schema, request=self.request)
for key, value in feature.get_defaults().items():
form.set_default(key, value)
feature_forms[feature.feature_key] = form
@ -86,7 +79,6 @@ class GenerateFeatureView(View):
context = {
'index_title': "Generate Feature",
'handler': self.handler,
'use_buefy': use_buefy,
'app_form': app_form,
'feature_type': feature_type,
'feature_forms': feature_forms,

View file

@ -24,8 +24,6 @@
View for running arbitrary import/export jobs
"""
from __future__ import unicode_literals, absolute_import
import getpass
import socket
import sys
@ -34,7 +32,6 @@ import subprocess
import time
import json
import six
import sqlalchemy as sa
from rattail.exceptions import ConfigurationError
@ -222,7 +219,7 @@ class ImportingView(MasterView):
try:
return self.do_runjob(handler_info, form)
except Exception as error:
self.request.session.flash(six.text_type(error), 'error')
self.request.session.flash(str(error), 'error')
return self.redirect(self.request.current_route_url())
return self.render_to_response('runjob', {
@ -274,7 +271,6 @@ class ImportingView(MasterView):
handler = handler_info['_handler']
defaults = {
'request': self.request,
'use_buefy': self.get_use_buefy(),
'model_instance': handler,
'cancel_url': self.request.route_url('{}.view'.format(route_prefix),
key=handler.get_key()),
@ -411,8 +407,7 @@ And here is the output:
data = json.dumps({
'everything_complete': True,
})
if six.PY3:
data = data.encode('utf_8')
data = data.encode('utf_8')
cxn.send(data)
cxn.send(suffix)
cxn.close()

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,8 +24,6 @@
Label Profile Views
"""
from __future__ import unicode_literals, absolute_import
from rattail.db import model
import colander
@ -93,7 +91,6 @@ class LabelProfileView(MasterView):
pass
def make_printer_settings_form(self, profile, printer):
use_buefy = self.get_use_buefy()
schema = colander.Schema()
for name, label in printer.required_settings.items():
@ -104,7 +101,6 @@ class LabelProfileView(MasterView):
schema.add(node)
form = forms.Form(schema=schema, request=self.request,
use_buefy=use_buefy,
model_instance=profile,
# TODO: ugh, this is necessary to avoid some logic
# which assumes a ColanderAlchemy schema i think?

View file

@ -24,15 +24,12 @@
Views for Luigi
"""
from __future__ import unicode_literals, absolute_import
import json
import logging
import os
import re
import shlex
import six
import sqlalchemy as sa
from rattail.util import simple_error
@ -81,7 +78,6 @@ class LuigiTaskView(MasterView):
luigi_url = self.rattail_config.get('rattail.luigi', 'url')
history_url = '{}/history'.format(luigi_url.rstrip('/')) if luigi_url else None
return self.render_to_response('index', {
'use_buefy': self.get_use_buefy(),
'index_url': None,
'luigi_url': luigi_url,
'luigi_history_url': history_url,
@ -169,7 +165,7 @@ class LuigiTaskView(MasterView):
tasks = []
for task in tasks:
if task['last_date']:
task['last_date'] = six.text_type(task['last_date'])
task['last_date'] = str(task['last_date'])
return tasks
def get_backfill_tasks(self):
@ -179,9 +175,9 @@ class LuigiTaskView(MasterView):
tasks = []
for task in tasks:
if task['last_date']:
task['last_date'] = six.text_type(task['last_date'])
task['last_date'] = str(task['last_date'])
if task['target_date']:
task['target_date'] = six.text_type(task['target_date'])
task['target_date'] = str(task['target_date'])
return tasks
def configure_gather_settings(self, data):
@ -224,7 +220,7 @@ class LuigiTaskView(MasterView):
{'name': 'rattail.luigi.backfill.task.{}.notes'.format(key),
'value': task['notes']},
{'name': 'rattail.luigi.backfill.task.{}.target_date'.format(key),
'value': six.text_type(task['target_date'])},
'value': str(task['target_date'])},
])
if keys:
settings.append({'name': 'rattail.luigi.backfill.tasks',

View file

@ -24,8 +24,6 @@
Model Master View
"""
from __future__ import unicode_literals, absolute_import
import os
import csv
import datetime
@ -252,7 +250,7 @@ class MasterView(View):
def set_labels(self, obj):
labels = self.collect_labels()
for key, label in six.iteritems(labels):
for key, label in labels.items():
obj.set_label(key, label)
def collect_labels(self):
@ -283,7 +281,7 @@ class MasterView(View):
def set_row_labels(self, obj):
labels = self.collect_row_labels()
for key, label in six.iteritems(labels):
for key, label in labels.items():
obj.set_label(key, label)
def collect_row_labels(self):
@ -333,7 +331,6 @@ class MasterView(View):
"""
self.listing = True
grid = self.make_grid()
use_buefy = self.get_use_buefy()
# If user just refreshed the page with a reset instruction, issue a
# redirect in order to clear out the query string.
@ -346,14 +343,9 @@ class MasterView(View):
# return grid only, if partial page was requested
if self.request.params.get('partial'):
if use_buefy:
# render grid data only, as JSON
return render_to_response('json', grid.get_buefy_data(),
request=self.request)
else: # just do traditional thing, render grid HTML
self.request.response.content_type = str('text/html')
self.request.response.text = grid.render_grid()
return self.request.response
# render grid data only, as JSON
return render_to_response('json', grid.get_buefy_data(),
request=self.request)
context = {
'grid': grid,
@ -552,17 +544,16 @@ class MasterView(View):
if self.has_rows and 'main_actions' not in defaults:
actions = []
use_buefy = self.get_use_buefy()
# view action
if self.rows_viewable:
icon = 'eye' if use_buefy else 'zoomin'
actions.append(self.make_action('view', icon=icon, url=self.row_view_action_url))
actions.append(self.make_action('view', icon='eye',
url=self.row_view_action_url))
# edit action
if self.rows_editable and self.has_perm('edit_row'):
icon = 'edit' if use_buefy else 'pencil'
actions.append(self.make_action('edit', icon=icon, url=self.row_edit_action_url))
actions.append(self.make_action('edit', icon='edit',
url=self.row_edit_action_url))
# delete action
if self.rows_deletable and self.has_perm('delete_row'):
@ -626,7 +617,6 @@ class MasterView(View):
Return a dictionary of kwargs to be passed to the factory when
constructing a new version grid.
"""
use_buefy = self.get_use_buefy()
instance = kwargs.get('instance') or self.get_instance()
route = '{}.version'.format(self.get_route_prefix())
defaults = {
@ -638,7 +628,7 @@ class MasterView(View):
if 'main_actions' not in kwargs:
url = lambda txn, i: self.request.route_url(route, uuid=instance.uuid, txnid=txn.id)
defaults['main_actions'] = [
self.make_action('view', icon='eye' if use_buefy else 'zoomin', url=url),
self.make_action('view', icon='eye', url=url),
]
defaults.update(kwargs)
return defaults
@ -735,11 +725,10 @@ class MasterView(View):
delete=False, schema=None, importer_host_title=None):
handler = handler_factory(self.rattail_config)
use_buefy = self.get_use_buefy()
if not schema:
schema = forms.SimpleFileImport().bind(request=self.request)
form = forms.Form(schema=schema, request=self.request, use_buefy=use_buefy)
form = forms.Form(schema=schema, request=self.request)
form.save_label = "Upload"
form.cancel_url = self.get_index_url()
if form.validate(newstyle=True):
@ -771,7 +760,7 @@ class MasterView(View):
value = getattr(obj, field)
if value is None:
return ""
value = six.text_type(value)
value = str(value)
if len(value) > 100:
value = value[:100] + '...'
return value
@ -841,7 +830,7 @@ class MasterView(View):
product = getattr(obj, field)
if not product:
return ""
text = six.text_type(product)
text = str(product)
url = self.request.route_url('products.view', uuid=product.uuid)
return tags.link_to(text, url)
@ -849,7 +838,7 @@ class MasterView(View):
pending = getattr(obj, field)
if not pending:
return
text = six.text_type(pending)
text = str(pending)
url = self.request.route_url('pending_products.view', uuid=pending.uuid)
return tags.link_to(text, url,
class_='has-background-warning')
@ -862,7 +851,7 @@ class MasterView(View):
if short:
text = "({}) {}".format(short, vendor.name)
else:
text = six.text_type(vendor)
text = str(vendor)
url = self.request.route_url('vendors.view', uuid=vendor.uuid)
return tags.link_to(text, url)
@ -918,7 +907,7 @@ class MasterView(View):
person = getattr(obj, field)
if not person:
return ""
text = six.text_type(person)
text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url)
@ -926,7 +915,7 @@ class MasterView(View):
person = getattr(obj, field)
if not person:
return ""
text = six.text_type(person)
text = str(person)
url = self.request.route_url('people.view_profile', uuid=person.uuid)
return tags.link_to(text, url)
@ -934,7 +923,7 @@ class MasterView(View):
user = getattr(obj, field)
if not user:
return ""
text = six.text_type(user)
text = str(user)
url = self.request.route_url('users.view', uuid=user.uuid)
return tags.link_to(text, url)
@ -954,7 +943,7 @@ class MasterView(View):
customer = getattr(obj, field)
if not customer:
return ""
text = six.text_type(customer)
text = str(customer)
url = self.request.route_url('customers.view', uuid=customer.uuid)
return tags.link_to(text, url)
@ -984,7 +973,7 @@ class MasterView(View):
value = obj.status_code
if value is None:
return ""
status_code_text = enum.get(value, six.text_type(value))
status_code_text = enum.get(value, str(value))
if obj.status_text:
return HTML.tag('span', title=obj.status_text, c=status_code_text)
return status_code_text
@ -1072,7 +1061,6 @@ class MasterView(View):
View for viewing details of an existing model record.
"""
self.viewing = True
use_buefy = self.get_use_buefy()
if instance is None:
instance = self.get_instance()
form = self.make_form(instance)
@ -1090,14 +1078,9 @@ class MasterView(View):
# return grid only, if partial page was requested
if self.request.params.get('partial'):
if use_buefy:
# render grid data only, as JSON
return render_to_response('json', grid.get_buefy_data(),
request=self.request)
else: # just do traditional thing, render grid HTML
self.request.response.content_type = str('text/html')
self.request.response.text = grid.render_grid()
return self.request.response
# render grid data only, as JSON
return render_to_response('json', grid.get_buefy_data(),
request=self.request)
context = {
'instance': instance,
@ -1112,12 +1095,8 @@ class MasterView(View):
context['dform'] = form.make_deform_form()
if self.has_rows:
if use_buefy:
context['rows_grid'] = grid
context['rows_grid_tools'] = HTML(self.make_row_grid_tools(instance) or '').strip()
else:
context['rows_grid'] = grid.render_complete(allow_save_defaults=False,
tools=self.make_row_grid_tools(instance))
context['rows_grid'] = grid
context['rows_grid_tools'] = HTML(self.make_row_grid_tools(instance) or '').strip()
return self.render_to_response('view', context)
@ -1224,18 +1203,12 @@ class MasterView(View):
instance = self.get_instance()
instance_title = self.get_instance_title(instance)
grid = self.make_version_grid(instance=instance)
use_buefy = self.get_use_buefy()
# return grid only, if partial page was requested
if self.request.params.get('partial'):
if use_buefy:
# render grid data only, as JSON
return render_to_response('json', grid.get_buefy_data(),
request=self.request)
else: # just do traditional thing, render grid HTML
self.request.response.content_type = str('text/html')
self.request.response.text = grid.render_grid()
return self.request.response
# render grid data only, as JSON
return render_to_response('json', grid.get_buefy_data(),
request=self.request)
return self.render_to_response('versions', {
'instance': instance,
@ -1567,15 +1540,10 @@ class MasterView(View):
response.content_length = os.path.getsize(path)
content_type = self.download_content_type(path, filename)
if content_type:
if six.PY3:
response.content_type = content_type
else:
response.content_type = six.binary_type(content_type)
response.content_type = content_type
# content-disposition
filename = os.path.basename(path)
if six.PY2:
filename = filename.encode('ascii', 'replace')
response.content_disposition = str('attachment; filename="{}"'.format(filename))
return response
@ -1986,8 +1954,7 @@ class MasterView(View):
# strip suffix, interpret data as JSON
data = data[:-len(suffix)]
if six.PY3:
data = data.decode('utf_8')
data = data.decode('utf_8')
data = json.loads(data)
if data.get('everything_complete'):
@ -2056,7 +2023,7 @@ class MasterView(View):
object_to_keep = self.Session.query(self.get_model_class()).get(uuids[1])
if object_to_remove and object_to_keep and self.request.POST.get('commit-merge') == 'yes':
msg = six.text_type(object_to_remove)
msg = str(object_to_remove)
try:
self.validate_merge(object_to_remove, object_to_keep)
except Exception as error:
@ -2166,7 +2133,7 @@ class MasterView(View):
"""
if hasattr(cls, 'model_key'):
keys = cls.model_key
if isinstance(keys, six.string_types):
if isinstance(keys, str):
keys = [keys]
else:
keys = get_primary_keys(cls.get_model_class())
@ -2399,7 +2366,6 @@ class MasterView(View):
"""
context = {
'master': self,
'use_buefy': self.get_use_buefy(),
'model_title': self.get_model_title(),
'model_title_plural': self.get_model_title_plural(),
'route_prefix': self.get_route_prefix(),
@ -2699,7 +2665,7 @@ class MasterView(View):
# nb. unfortunately HTML.tag() calls its first arg 'tag' and
# so we can't pass a kwarg with that name...so instead we
# patch that into place manually
button = six.text_type(button)
button = str(button)
button = button.replace('<b-button ',
'<b-button tag="a"')
button = HTML.literal(button)
@ -2733,7 +2699,7 @@ class MasterView(View):
btn_kw['icon_left'] = 'external-link-alt'
btn_kw['target'] = '_blank'
button = HTML.tag('b-button', **btn_kw)
button = six.text_type(button)
button = str(button)
button = button.replace('<b-button ',
'<b-button tag="a"')
button = HTML.literal(button)
@ -2840,9 +2806,7 @@ class MasterView(View):
return actions
def make_grid_action_view(self):
use_buefy = self.get_use_buefy()
icon = 'eye' if use_buefy else 'zoomin'
return self.make_action('view', icon=icon, url=self.default_view_url())
return self.make_action('view', icon='eye', url=self.default_view_url())
def default_view_url(self):
if self.use_index_links:
@ -2869,18 +2833,15 @@ class MasterView(View):
return actions
def make_grid_action_edit(self):
use_buefy = self.get_use_buefy()
icon = 'edit' if use_buefy else 'pencil'
return self.make_action('edit', icon=icon, url=self.default_edit_url)
return self.make_action('edit', icon='edit', url=self.default_edit_url)
def make_grid_action_clone(self):
return self.make_action('clone', icon='object-ungroup',
url=self.default_clone_url)
def make_grid_action_delete(self):
use_buefy = self.get_use_buefy()
kwargs = {}
if use_buefy and self.delete_confirm == 'simple':
if self.delete_confirm == 'simple':
kwargs['click_handler'] = 'deleteObject'
return self.make_action('delete', icon='trash', url=self.default_delete_url, **kwargs)
@ -2917,7 +2878,7 @@ class MasterView(View):
mapper = orm.object_mapper(row)
except orm.exc.UnmappedInstanceError:
try:
if isinstance(self.model_key, six.string_types):
if isinstance(self.model_key, str):
return {self.model_key: row[self.model_key]}
return dict([(key, row[key])
for key in self.model_key])
@ -3134,12 +3095,8 @@ class MasterView(View):
"""
if fmt == 'csv':
if six.PY2:
csv_file = open(path, 'wb')
writer = UnicodeDictWriter(csv_file, fields, encoding='utf_8')
else: # PY3
csv_file = open(path, 'wt', encoding='utf_8')
writer = csv.DictWriter(csv_file, fields)
csv_file = open(path, 'wt', encoding='utf_8')
writer = csv.DictWriter(csv_file, fields)
writer.writeheader()
def write(obj, i):
@ -3229,7 +3186,7 @@ class MasterView(View):
if value is None:
value = ''
else:
value = six.text_type(value)
value = str(value)
csvrow[field] = value
@ -3297,13 +3254,8 @@ class MasterView(View):
results = results.with_session(session).all()
fields = self.get_csv_fields()
if six.PY2:
csv_file = open(path, 'wb')
writer = UnicodeDictWriter(csv_file, fields, encoding='utf_8')
else: # PY3
csv_file = open(path, 'wt', encoding='utf_8')
writer = csv.DictWriter(csv_file, fields)
csv_file = open(path, 'wt', encoding='utf_8')
writer = csv.DictWriter(csv_file, fields)
writer.writeheader()
def write(obj, i):
@ -3663,12 +3615,8 @@ class MasterView(View):
if fmt == 'csv':
if six.PY2:
csv_file = open(path, 'wb')
writer = UnicodeDictWriter(csv_file, fields, encoding='utf_8')
else: # PY3
csv_file = open(path, 'wt', encoding='utf_8')
writer = csv.DictWriter(csv_file, fields)
csv_file = open(path, 'wt', encoding='utf_8')
writer = csv.DictWriter(csv_file, fields)
writer.writeheader()
def write(obj, i):
@ -3737,7 +3685,7 @@ class MasterView(View):
if value is None:
value = ''
else:
value = six.text_type(value)
value = str(value)
csvrow[field] = value
@ -3814,7 +3762,7 @@ class MasterView(View):
value = getattr(row, field, None)
if isinstance(value, GPC):
value = six.text_type(value)
value = str(value)
elif isinstance(value, datetime.datetime):
# datetime values we provide to Excel must *not* have time zone info,
@ -3844,14 +3792,9 @@ class MasterView(View):
writer.writerow(self.get_row_csv_row(row, fields))
response = self.request.response
filename = self.get_row_results_csv_filename(obj)
if six.PY3:
response.text = data.getvalue()
response.content_type = 'text/csv'
response.content_disposition = 'attachment; filename={}'.format(filename)
else:
response.body = data.getvalue()
response.content_type = b'text/csv'
response.content_disposition = b'attachment; filename={}'.format(filename)
response.text = data.getvalue()
response.content_type = 'text/csv'
response.content_disposition = 'attachment; filename={}'.format(filename)
data.close()
response.content_length = len(response.body)
return response
@ -3898,7 +3841,7 @@ class MasterView(View):
if isinstance(value, datetime.datetime):
# TODO: this assumes value is *always* naive UTC
value = localtime(self.rattail_config, value, from_utc=True)
csvrow[field] = '' if value is None else six.text_type(value)
csvrow[field] = '' if value is None else str(value)
return csvrow
def get_row_csv_row(self, row, fields):
@ -3911,7 +3854,7 @@ class MasterView(View):
if isinstance(value, datetime.datetime):
# TODO: this assumes value is *always* naive UTC
value = localtime(self.rattail_config, value, from_utc=True)
csvrow[field] = '' if value is None else six.text_type(value)
csvrow[field] = '' if value is None else str(value)
return csvrow
##############################
@ -3966,7 +3909,7 @@ class MasterView(View):
"""
Return a "pretty" title for the instance, to be used in the page title etc.
"""
return six.text_type(instance)
return str(instance)
@classmethod
def get_form_factory(cls):
@ -4078,7 +4021,6 @@ class MasterView(View):
'readonly': self.viewing,
'model_class': getattr(self, 'model_class', None),
'action_url': self.request.current_route_url(_query=None),
'use_buefy': self.get_use_buefy(),
'assume_local_times': self.has_local_times,
'route_prefix': route_prefix,
'can_edit_help': (self.has_perm('edit_help')
@ -4547,7 +4489,6 @@ class MasterView(View):
'readonly': self.viewing,
'model_class': getattr(self, 'model_row_class', None),
'action_url': self.request.current_route_url(_query=None),
'use_buefy': self.get_use_buefy(),
}
if self.creating:
kwargs.setdefault('cancel_url', self.request.get_referrer())
@ -4644,7 +4585,7 @@ class MasterView(View):
# collect any uploaded files
uploads = {}
for key, value in six.iteritems(data):
for key, value in data.items():
if isinstance(value, cgi_FieldStorage):
tempdir = tempfile.mkdtemp()
filename = os.path.basename(value.filename)
@ -4829,13 +4770,13 @@ class MasterView(View):
value = data.get(name)
if simple.get('type') is bool:
value = six.text_type(bool(value)).lower()
value = str(bool(value)).lower()
elif simple.get('type') is int:
value = six.text_type(int(value or '0'))
value = str(int(value or '0'))
elif value is None:
value = ''
else:
value = six.text_type(value)
value = str(value)
# only want to save this setting if we received a
# value, or if empty values are okay to save

View file

@ -24,8 +24,6 @@
Base class for Config Views
"""
from __future__ import unicode_literals, absolute_import
import json
import sqlalchemy as sa
@ -62,7 +60,6 @@ class MenuConfigView(View):
context = {
'config_title': "Menus",
'use_buefy': True,
'index_title': "App Details",
'index_url': self.request.route_url('appinfo'),
}

View file

@ -24,10 +24,6 @@
Message Views
"""
from __future__ import unicode_literals, absolute_import
import six
from rattail.db import model
from rattail.time import localtime
@ -139,7 +135,7 @@ class MessageView(MasterView):
sender = message.sender
if sender is self.request.user:
return 'you'
return six.text_type(sender)
return str(sender)
def render_subject_bold(self, message, field):
if not message.subject:
@ -164,8 +160,6 @@ class MessageView(MasterView):
if not recipients:
return ""
use_buefy = self.get_use_buefy()
# remove current user from displayed list, even if they're a recipient
recips = [r for r in recipients
if r.recipient is not self.request.user]
@ -182,23 +176,17 @@ class MessageView(MasterView):
# client-side JS allowing the user to view all if they want
max_display = 5
if len(recips) > max_display:
if use_buefy:
basic = HTML.tag('span', c="{}, ".format(', '.join(recips[:max_display-1])))
more = tags.link_to("({} more)".format(len(recips[max_display-1:])), '#', **{
'v-show': '!showingAllRecipients',
'@click.prevent': 'showMoreRecipients()',
})
everyone = HTML.tag('span', c=', '.join(recips[max_display-1:]), **{
'v-show': 'showingAllRecipients',
'@click': 'hideMoreRecipients()',
'class_': 'everyone',
})
return HTML.tag('div', c=[basic, more, everyone])
else:
basic = HTML.literal("{}, ".format(', '.join(recips[:max_display-1])))
more = tags.link_to("({} more)".format(len(recips[max_display-1:])), '#', class_='more')
everyone = HTML.tag('span', class_='everyone', c=', '.join(recips[max_display-1:]))
return basic + more + everyone
basic = HTML.tag('span', c="{}, ".format(', '.join(recips[:max_display-1])))
more = tags.link_to("({} more)".format(len(recips[max_display-1:])), '#', **{
'v-show': '!showingAllRecipients',
'@click.prevent': 'showMoreRecipients()',
})
everyone = HTML.tag('span', c=', '.join(recips[max_display-1:]), **{
'v-show': 'showingAllRecipients',
'@click': 'hideMoreRecipients()',
'class_': 'everyone',
})
return HTML.tag('div', c=[basic, more, everyone])
# show the full list if there are few enough recipients for that
return ', '.join(recips)
@ -214,15 +202,9 @@ class MessageView(MasterView):
def configure_form(self, f):
super(MessageView, self).configure_form(f)
use_buefy = self.get_use_buefy()
f.submit_label = "Send Message"
if not use_buefy:
# we have custom logic to disable submit button
f.auto_disable = False
f.auto_disable_save = False
# TODO: A fair amount of this still seems hacky...
f.set_renderer('sender', self.render_sender)
@ -235,13 +217,12 @@ class MessageView(MasterView):
f.set_label('recipients', "To")
# subject
if use_buefy:
f.set_renderer('subject', self.render_subject_bold)
if self.creating:
f.set_widget('subject', dfwidget.TextInputWidget(
placeholder="please enter a subject",
autocomplete='off'))
f.set_required('subject')
f.set_renderer('subject', self.render_subject_bold)
if self.creating:
f.set_widget('subject', dfwidget.TextInputWidget(
placeholder="please enter a subject",
autocomplete='off'))
f.set_required('subject')
# body
f.set_widget('body', dfwidget.TextAreaWidget(cols=50, rows=15))
@ -253,10 +234,7 @@ class MessageView(MasterView):
f.insert_after('recipients', 'set_recipients')
f.remove('recipients')
f.set_node('set_recipients', colander.SchemaNode(colander.Set()))
if use_buefy:
f.set_widget('set_recipients', RecipientsWidgetBuefy())
else:
f.set_widget('set_recipients', RecipientsWidget())
f.set_widget('set_recipients', RecipientsWidgetBuefy())
f.set_label('set_recipients', "To")
if self.replying:
@ -278,17 +256,11 @@ class MessageView(MasterView):
value = [r[0] for r in value]
if old_message.sender is not self.request.user and old_message.sender.active:
value.insert(0, old_message.sender_uuid)
if use_buefy:
f.set_default('set_recipients', value)
else:
f.set_default('set_recipients', ','.join(value))
f.set_default('set_recipients', value)
# Just a normal reply, to sender only.
elif self.filter_reply_recipient(old_message.sender):
if use_buefy:
f.set_default('set_recipients', [old_message.sender.uuid])
else:
f.set_default('set_recipients', old_message.sender.uuid)
f.set_default('set_recipients', [old_message.sender.uuid])
# TODO?
# # Set focus to message body instead of recipients, when replying.
@ -347,11 +319,9 @@ class MessageView(MasterView):
return recipient
def template_kwargs_create(self, **kwargs):
use_buefy = self.get_use_buefy()
recips = self.get_available_recipients()
if use_buefy:
kwargs['recipient_display_map'] = recips
kwargs['recipient_display_map'] = recips
recips = list(recips.items())
recips.sort(key=self.recipient_sortkey)
kwargs['available_recipients'] = recips
@ -359,9 +329,8 @@ class MessageView(MasterView):
if self.replying:
kwargs['original_message'] = self.get_instance()
if use_buefy:
kwargs['index_url'] = None
kwargs['index_title'] = "New Message"
kwargs['index_url'] = None
kwargs['index_title'] = "New Message"
return kwargs
def recipient_sortkey(self, recip):
@ -538,20 +507,6 @@ class SentView(MessageView):
default_active=True, default_verb='contains')
class RecipientsWidget(dfwidget.TextInputWidget):
def deserialize(self, field, pstruct):
if pstruct is colander.null:
return []
elif not isinstance(pstruct, six.string_types):
raise colander.Invalid(field.schema, "Pstruct is not a string")
if self.strip:
pstruct = pstruct.strip()
if not pstruct:
return []
return pstruct.split(',')
class RecipientsWidgetBuefy(dfwidget.Widget):
"""
Custom "message recipients" widget, for use with Buefy / Vue.js themes.
@ -561,7 +516,7 @@ class RecipientsWidgetBuefy(dfwidget.Widget):
def deserialize(self, field, pstruct):
if pstruct is colander.null:
return colander.null
if not isinstance(pstruct, six.string_types):
if not isinstance(pstruct, str):
raise colander.Invalid(field.schema, "Pstruct is not a string")
if not pstruct:
return colander.null

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,12 +24,9 @@
Person Views
"""
from __future__ import unicode_literals, absolute_import
import datetime
import logging
import six
import sqlalchemy as sa
from sqlalchemy import orm
@ -165,13 +162,10 @@ class PersonView(MasterView):
.filter(model.MergePeopleRequest.merged == None)\
.first()
if merge_request:
use_buefy = self.get_use_buefy()
if use_buefy:
return HTML.tag('span',
class_='has-text-danger has-text-weight-bold',
title="A merge has been requested for this person.",
c="MR")
return "MR"
return HTML.tag('span',
class_='has-text-danger has-text-weight-bold',
title="A merge has been requested for this person.",
c="MR")
def get_instance(self):
# TODO: I don't recall why this fallback check for a vendor contact
@ -335,7 +329,7 @@ class PersonView(MasterView):
employee = person.employee
if not employee:
return ""
text = six.text_type(employee)
text = str(employee)
url = self.request.route_url('employees.view', uuid=employee.uuid)
return tags.link_to(text, url)
@ -346,7 +340,7 @@ class PersonView(MasterView):
items = []
for customer in customers:
customer = customer.customer
text = six.text_type(customer)
text = str(customer)
if customer.number:
text = "(#{}) {}".format(customer.number, text)
elif customer.id:
@ -361,7 +355,7 @@ class PersonView(MasterView):
return ""
items = []
for member in members:
text = six.text_type(member)
text = str(member)
if member.number:
text = "(#{}) {}".format(member.number, text)
elif member.id:
@ -371,7 +365,6 @@ class PersonView(MasterView):
return HTML.tag('ul', c=items)
def render_users(self, person, field):
use_buefy = self.get_use_buefy()
users = person.users
items = []
for user in users:
@ -381,11 +374,8 @@ class PersonView(MasterView):
if items:
return HTML.tag('ul', c=items)
elif self.viewing and self.request.has_perm('users.create'):
if use_buefy:
return HTML.tag('b-button', type='is-primary', c="Make User",
**{'@click': 'clickMakeUser()'})
else:
return HTML.tag('button', type='button', id='make-user', c="Make User")
return HTML.tag('b-button', type='is-primary', c="Make User",
**{'@click': 'clickMakeUser()'})
else:
return ""
@ -428,8 +418,7 @@ class PersonView(MasterView):
'dynamic_content_title': self.get_context_content_title(person),
}
use_buefy = self.get_use_buefy()
template = 'view_profile_buefy' if use_buefy else 'view_profile'
template = 'view_profile_buefy'
return self.render_to_response(template, context)
def get_customer_xref_buttons(self, person):
@ -524,7 +513,7 @@ class PersonView(MasterView):
return context
def get_context_content_title(self, person):
return six.text_type(person)
return str(person)
def get_context_address(self, address):
context = {
@ -534,7 +523,7 @@ class PersonView(MasterView):
'city': address.city,
'state': address.state,
'zipcode': address.zipcode,
'display': six.text_type(address),
'display': str(address),
}
model = self.model
@ -587,12 +576,12 @@ class PersonView(MasterView):
'number': member.number,
'id': member.id,
'active': member.active,
'joined': six.text_type(member.joined) if member.joined else None,
'withdrew': six.text_type(member.withdrew) if member.withdrew else None,
'joined': str(member.joined) if member.joined else None,
'withdrew': str(member.withdrew) if member.withdrew else None,
'customer_uuid': member.customer_uuid,
'customer_name': member.customer.name if member.customer else None,
'person_uuid': member.person_uuid,
'display': six.text_type(member),
'display': str(member),
'person_display_name': member.person.display_name if member.person else None,
'view_url': self.request.route_url('members.view', uuid=member.uuid),
'view_profile_url': profile_url,
@ -614,8 +603,8 @@ class PersonView(MasterView):
for history in employee.sorted_history(reverse=True):
data.append({
'uuid': history.uuid,
'start_date': six.text_type(history.start_date),
'end_date': six.text_type(history.end_date or ''),
'start_date': str(history.start_date),
'end_date': str(history.end_date or ''),
})
return data
@ -911,7 +900,7 @@ class PersonView(MasterView):
'success': True,
'employee': self.get_context_employee(employee),
'employee_view_url': self.request.route_url('employees.view', uuid=employee.uuid),
'start_date': six.text_type(start_date),
'start_date': str(start_date),
'employee_history_data': self.get_context_employee_history(employee),
'dynamic_content_title': self.get_context_content_title(person),
}
@ -942,7 +931,7 @@ class PersonView(MasterView):
'success': True,
'employee': self.get_context_employee(employee),
'employee_view_url': self.request.route_url('employees.view', uuid=employee.uuid),
'end_date': six.text_type(end_date),
'end_date': str(end_date),
'employee_history_data': self.get_context_employee_history(employee),
'dynamic_content_title': self.get_context_content_title(person),
}
@ -975,8 +964,8 @@ class PersonView(MasterView):
return {
'success': True,
'employee': self.get_context_employee(employee),
'start_date': six.text_type(current_history.start_date),
'end_date': six.text_type(current_history.end_date or ''),
'start_date': str(current_history.start_date),
'end_date': str(current_history.end_date or ''),
'employee_history_data': self.get_context_employee_history(employee),
}
@ -1438,7 +1427,7 @@ class MergePeopleRequestView(MasterView):
uuid = getattr(merge_request, field)
person = self.Session.query(self.model.Person).get(uuid)
if person:
return six.text_type(person)
return str(person)
return "(person not found)"
def get_instance_title(self, merge_request):
@ -1459,7 +1448,7 @@ class MergePeopleRequestView(MasterView):
uuid = getattr(merge_request, field)
person = self.Session.query(self.model.Person).get(uuid)
if person:
text = six.text_type(person)
text = str(person)
url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url)
return "(person not found)"

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,8 +24,6 @@
"Principal" master view
"""
from __future__ import unicode_literals, absolute_import
import copy
from rattail.core import Object
@ -85,12 +83,11 @@ class PrincipalMasterView(MasterView):
context = {'form': form, 'permissions': sorted_perms, 'principals': principals}
if self.get_use_buefy():
perms = self.get_buefy_perms_data(sorted_perms)
context['buefy_perms'] = perms
context['buefy_sorted_groups'] = list(perms)
context['selected_group'] = self.request.POST.get('permission_group', 'common')
context['selected_permission'] = self.request.POST.get('permission', None)
perms = self.get_buefy_perms_data(sorted_perms)
context['buefy_perms'] = perms
context['buefy_sorted_groups'] = list(perms)
context['selected_group'] = self.request.POST.get('permission_group', 'common')
context['selected_permission'] = self.request.POST.get('permission', None)
return self.render_to_response('find_by_perm', context)

View file

@ -24,12 +24,9 @@
Product Views
"""
from __future__ import unicode_literals, absolute_import
import re
import logging
import six
import humanize
import sqlalchemy as sa
from sqlalchemy import orm
@ -212,7 +209,6 @@ class ProductView(MasterView):
super(ProductView, self).configure_grid(g)
app = self.get_rattail_app()
model = self.model
use_buefy = self.get_use_buefy()
def join_vendor(q):
return q.outerjoin(self.ProductVendorCost,
@ -257,9 +253,6 @@ class ProductView(MasterView):
departments = self.get_departments()
department_choices = OrderedDict([('', "(any)")]
+ [(d.uuid, d.name) for d in departments])
if not use_buefy:
department_choices = [tags.Option(name, uuid)
for uuid, name in six.iteritems(department_choices)]
g.set_filter('department', model.Department.uuid,
value_enum=department_choices,
verbs=['equal', 'not_equal', 'is_null', 'is_not_null', 'is_any'],
@ -378,12 +371,9 @@ class ProductView(MasterView):
g.set_filter('report_code_name', model.ReportCode.name)
if self.expose_label_printing and self.has_perm('print_labels'):
if use_buefy:
g.more_actions.append(self.make_action(
'print_label', icon='print', url='#',
click_handler='quickLabelPrint(props.row)'))
else:
g.more_actions.append(grids.GridAction('print_label', icon='print'))
g.more_actions.append(self.make_action(
'print_label', icon='print', url='#',
click_handler='quickLabelPrint(props.row)'))
g.set_renderer('regular_price', self.render_price)
g.set_renderer('on_hand', self.render_on_hand)
@ -572,10 +562,7 @@ class ProductView(MasterView):
if not self.has_perm('versions'):
return text
if self.get_use_buefy():
kwargs = {'@click.prevent': 'showPriceHistory_{}()'.format(typ)}
else:
kwargs = {'id': 'view-{}-price-history'.format(typ)}
kwargs = {'@click.prevent': 'showPriceHistory_{}()'.format(typ)}
history = tags.link_to("(view history)", '#', **kwargs)
if not text:
return history
@ -815,7 +802,7 @@ class ProductView(MasterView):
if 'upc' in data:
if isinstance(data['upc'], GPC):
data['upc'] = six.text_type(data['upc'])
data['upc'] = str(data['upc'])
return data
@ -971,9 +958,9 @@ class ProductView(MasterView):
if self.request.POST.get('brand_uuid'):
brand = self.Session.query(model.Brand).get(self.request.POST['brand_uuid'])
if brand:
brand_display = six.text_type(brand)
brand_display = str(brand)
elif self.editing:
brand_display = six.text_type(product.brand or '')
brand_display = str(product.brand or '')
brands_url = self.request.route_url('brands.autocomplete')
f.set_widget('brand_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=brand_display, service_url=brands_url))
@ -1139,11 +1126,11 @@ class ProductView(MasterView):
history['price'] = float(price)
history['price_display'] = app.render_currency(price)
changed = localtime(self.rattail_config, history['changed'], from_utc=True)
history['changed'] = six.text_type(changed)
history['changed'] = str(changed)
history['changed_display_html'] = raw_datetime(self.rattail_config, changed)
user = history.pop('changed_by')
history['changed_by_uuid'] = user.uuid if user else None
history['changed_by_display'] = six.text_type(user or "??")
history['changed_by_display'] = str(user or "??")
jsdata.append(history)
return jsdata
@ -1165,18 +1152,17 @@ class ProductView(MasterView):
else:
history['cost_display'] = None
changed = localtime(self.rattail_config, history['changed'], from_utc=True)
history['changed'] = six.text_type(changed)
history['changed'] = str(changed)
history['changed_display_html'] = raw_datetime(self.rattail_config, changed)
user = history.pop('changed_by')
history['changed_by_uuid'] = user.uuid
history['changed_by_display'] = six.text_type(user)
history['changed_by_display'] = str(user)
jsdata.append(history)
return jsdata
def template_kwargs_view(self, **kwargs):
kwargs = super(ProductView, self).template_kwargs_view(**kwargs)
product = kwargs['instance']
use_buefy = self.get_use_buefy()
kwargs['image_url'] = self.products_handler.get_image_url(product)
@ -1184,10 +1170,7 @@ class ProductView(MasterView):
if self.rattail_config.versioning_enabled() and self.has_perm('versions'):
# regular price
if use_buefy:
data = [] # defer fetching until user asks for it
else:
data = self.get_regular_price_history(product)
data = [] # defer fetching until user asks for it
grid = grids.Grid('products.regular_price_history', data,
request=self.request,
columns=[
@ -1201,10 +1184,7 @@ class ProductView(MasterView):
kwargs['regular_price_history_grid'] = grid
# current price
if use_buefy:
data = [] # defer fetching until user asks for it
else:
data = self.get_current_price_history(product)
data = [] # defer fetching until user asks for it
grid = grids.Grid('products.current_price_history', data,
request=self.request,
columns=[
@ -1222,10 +1202,7 @@ class ProductView(MasterView):
kwargs['current_price_history_grid'] = grid
# suggested price
if use_buefy:
data = [] # defer fetching until user asks for it
else:
data = self.get_suggested_price_history(product)
data = [] # defer fetching until user asks for it
grid = grids.Grid('products.suggested_price_history', data,
request=self.request,
columns=[
@ -1239,10 +1216,7 @@ class ProductView(MasterView):
kwargs['suggested_price_history_grid'] = grid
# cost history
if use_buefy:
data = [] # defer fetching until user asks for it
else:
data = self.get_cost_history(product)
data = [] # defer fetching until user asks for it
grid = grids.Grid('products.cost_history', data,
request=self.request,
columns=[
@ -1264,9 +1238,8 @@ class ProductView(MasterView):
kwargs['costs_label_code'] = "Order Code"
kwargs['costs_label_case_size'] = "Case Size"
if use_buefy:
kwargs['vendor_sources'] = self.get_context_vendor_sources(product)
kwargs['lookup_codes'] = self.get_context_lookup_codes(product)
kwargs['vendor_sources'] = self.get_context_vendor_sources(product)
kwargs['lookup_codes'] = self.get_context_lookup_codes(product)
kwargs['panel_fields'] = self.get_panel_fields(product)
@ -1362,7 +1335,7 @@ class ProductView(MasterView):
source['case_size'] = app.render_quantity(cost.case_size)
source['case_cost'] = app.render_currency(cost.case_cost)
text = six.text_type(cost.vendor)
text = str(cost.vendor)
if link_vendor:
url = self.request.route_url('vendors.view', uuid=cost.vendor.uuid)
source['vendor'] = tags.link_to(text, url)
@ -1768,8 +1741,6 @@ class ProductView(MasterView):
# TODO: how to properly detect image type?
# content_type = 'image/png'
content_type = 'image/jpeg'
if not six.PY3:
content_type = six.binary_type(content_type)
self.request.response.content_type = content_type
self.request.response.body = product.image.bytes
return self.request.response
@ -1802,7 +1773,7 @@ class ProductView(MasterView):
printer.print_labels([({'product': product}, quantity)])
except Exception as error:
log.warning("error occurred while printing labels", exc_info=True)
return {'error': six.text_type(error)}
return {'error': str(error)}
return {'ok': True}
def search(self):
@ -1923,7 +1894,7 @@ class ProductView(MasterView):
if product and (not product.deleted or self.request.has_perm('products.view_deleted')):
data = {
'uuid': product.uuid,
'upc': six.text_type(product.upc),
'upc': str(product.upc),
'upc_pretty': product.upc.pretty(),
'full_description': product.full_description,
'image_url': pod.get_image_url(self.rattail_config, product.upc),
@ -2282,7 +2253,7 @@ class PendingProductView(MasterView):
g.set_enum('status_code', self.enum.PENDING_PRODUCT_STATUS)
g.filters['status_code'].default_active = True
g.filters['status_code'].default_verb = 'not_equal'
g.filters['status_code'].default_value = six.text_type(self.enum.PENDING_PRODUCT_STATUS_RESOLVED)
g.filters['status_code'].default_value = str(self.enum.PENDING_PRODUCT_STATUS_RESOLVED)
g.set_sort_defaults('created', 'desc')
@ -2317,9 +2288,9 @@ class PendingProductView(MasterView):
if self.request.POST.get('brand_uuid'):
brand = self.Session.query(model.Brand).get(self.request.POST['brand_uuid'])
if brand:
brand_display = six.text_type(brand)
brand_display = str(brand)
elif self.editing:
brand_display = six.text_type(pending.brand or '')
brand_display = str(pending.brand or '')
brands_url = self.request.route_url('brands.autocomplete')
f.set_widget('brand_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=brand_display, service_url=brands_url))
@ -2344,7 +2315,7 @@ class PendingProductView(MasterView):
if self.request.POST.get('vendor_uuid'):
vendor = self.Session.query(model.Vendor).get(self.request.POST['vendor_uuid'])
if vendor:
vendor_display = six.text_type(vendor)
vendor_display = str(vendor)
f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display,
service_url=self.request.route_url('vendors.autocomplete')))

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,8 +24,6 @@
Project views
"""
from __future__ import unicode_literals, absolute_import
import os
import zipfile
# from collections import OrderedDict
@ -160,7 +158,6 @@ class GenerateProjectView(View):
return RattailProjectHandler(self.rattail_config)
def __call__(self):
use_buefy = self.get_use_buefy()
# choices = OrderedDict([
# ('has_db', {'prompt': "Does project need its own Rattail DB?",
@ -183,8 +180,7 @@ class GenerateProjectView(View):
schema = GenerateTailboneIntegrationProject
else:
schema = GenerateProject
form = forms.Form(schema=schema(), request=self.request,
use_buefy=use_buefy)
form = forms.Form(schema=schema(), request=self.request)
if form.validate(newstyle=True):
zipped = self.generate_project(project_type, form)
return self.file_response(zipped)
@ -195,7 +191,6 @@ class GenerateProjectView(View):
'index_title': "Generate Project",
'handler': self.handler,
# 'choices': choices,
'use_buefy': use_buefy,
}
def generate_project(self, project_type, form):

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,10 +24,6 @@
Base class for purchasing batch views
"""
from __future__ import unicode_literals, absolute_import
import six
from rattail.db import model, api
import colander
@ -230,7 +226,6 @@ class PurchasingBatchView(BatchMasterView):
batch = f.model_instance
app = self.get_rattail_app()
today = app.localtime().date()
use_buefy = self.get_use_buefy()
# mode
f.set_enum('mode', self.enum.PURCHASE_BATCH_MODE)
@ -278,7 +273,7 @@ class PurchasingBatchView(BatchMasterView):
if self.request.POST.get('vendor_uuid'):
vendor = self.Session.query(model.Vendor).get(self.request.POST['vendor_uuid'])
if vendor:
vendor_display = six.text_type(vendor)
vendor_display = str(vendor)
vendors_url = self.request.route_url('vendors.autocomplete')
f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, service_url=vendors_url))
@ -311,14 +306,14 @@ class PurchasingBatchView(BatchMasterView):
if self.request.POST.get('buyer_uuid'):
buyer = self.Session.query(model.Employee).get(self.request.POST['buyer_uuid'])
if buyer:
buyer_display = six.text_type(buyer)
buyer_display = str(buyer)
elif self.creating:
buyer = self.request.user.employee
if buyer:
buyer_display = six.text_type(buyer)
buyer_display = str(buyer)
f.set_default('buyer_uuid', buyer.uuid)
elif self.editing:
buyer_display = six.text_type(batch.buyer or '')
buyer_display = str(batch.buyer or '')
buyers_url = self.request.route_url('employees.autocomplete')
f.set_widget('buyer_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=buyer_display, service_url=buyers_url))
@ -346,11 +341,7 @@ class PurchasingBatchView(BatchMasterView):
if len(parsers) == 1:
f.set_default('invoice_parser_key', parsers[0].key)
if use_buefy:
f.set_widget('invoice_parser_key', dfwidget.SelectWidget(values=parser_values))
else:
parser_values.insert(0, ('', "(please choose)"))
f.set_widget('invoice_parser_key', forms.widgets.JQuerySelectWidget(values=parser_values))
f.set_widget('invoice_parser_key', dfwidget.SelectWidget(values=parser_values))
else:
f.remove_field('invoice_parser_key')
@ -422,7 +413,7 @@ class PurchasingBatchView(BatchMasterView):
purchase = batch.purchase
if not purchase:
return ""
text = six.text_type(purchase)
text = str(purchase)
url = self.request.route_url('purchases.view', uuid=purchase.uuid)
return tags.link_to(text, url)
@ -435,7 +426,7 @@ class PurchasingBatchView(BatchMasterView):
def render_vendor_contact(self, batch, field):
if batch.vendor.contact:
return six.text_type(batch.vendor.contact)
return str(batch.vendor.contact)
def render_vendor_phone(self, batch, field):
return self.get_vendor_phone_number(batch)
@ -455,7 +446,7 @@ class PurchasingBatchView(BatchMasterView):
employee = batch.buyer
if not employee:
return ""
text = six.text_type(employee)
text = str(employee)
if self.request.has_perm('employees.view'):
url = self.request.route_url('employees.view', uuid=employee.uuid)
return tags.link_to(text, url)
@ -484,7 +475,7 @@ class PurchasingBatchView(BatchMasterView):
def get_buyer_values(self):
buyers = self.get_buyers()
return [(b.uuid, six.text_type(b))
return [(b.uuid, str(b))
for b in buyers]
def get_department_options(self):
@ -802,13 +793,12 @@ class PurchasingBatchView(BatchMasterView):
return app.render_cases_units(cases, units)
def make_row_credits_grid(self, row):
use_buefy = self.get_use_buefy()
route_prefix = self.get_route_prefix()
factory = self.get_grid_factory()
g = factory(
key='{}.row_credits'.format(route_prefix),
data=[] if use_buefy else row.credits,
data=[],
columns=[
'credit_type',
'shorted',
@ -837,17 +827,9 @@ class PurchasingBatchView(BatchMasterView):
return g
def render_row_credits(self, row, field):
use_buefy = self.get_use_buefy()
if not use_buefy and not row.credits:
return
g = self.make_row_credits_grid(row)
if use_buefy:
return HTML.literal(
g.render_buefy_table_element(data_prop='rowData.credits'))
else:
return HTML.literal(g.render_grid())
return HTML.literal(
g.render_buefy_table_element(data_prop='rowData.credits'))
# def item_lookup(self, value, field=None):
# """

Some files were not shown because too many files have changed in this diff Show more