Several disparate changes needed for vendor catalog improvements

- invoke vendor handler where appropriate, e.g. for parsers
- reverse "polarity" of dropdown chooser setting; rename it
- tweak autocomplete behavior yet again, for dynamic values
- auto-select vendor upon parser selection, when possible
This commit is contained in:
Lance Edgar 2022-01-07 19:27:10 -06:00
parent ab61778d35
commit 88b3279e63
12 changed files with 164 additions and 93 deletions

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar
# Copyright © 2010-2022 Lance Edgar
#
# This file is part of Rattail.
#
@ -247,6 +247,7 @@ class JQueryAutocompleteWidget(dfwidget.AutocompleteInputWidget):
template = 'autocomplete_jquery'
requirements = None
field_display = ""
assigned_label = None
service_url = None
cleared_callback = None
selected_callback = None
@ -275,6 +276,7 @@ class JQueryAutocompleteWidget(dfwidget.AutocompleteInputWidget):
kw['options'] = json.dumps(options)
kw['field_display'] = self.field_display
kw['cleared_callback'] = self.cleared_callback
kw['assigned_label'] = self.assigned_label
kw.setdefault('selected_callback', self.selected_callback)
tmpl_values = self.get_template_values(field, cstruct, kw)
template = readonly and self.readonly_template or self.template

View file

@ -95,6 +95,22 @@ const TailboneAutocomplete = {
}
},
watch: {
// TODO: yikes this feels hacky. what happens is, when the
// caller explicitly assigns a new UUID value to the tailbone
// autocomplate component, the underlying buefy autocomplete
// component was not getting the new value. so here we are
// explicitly making sure it is in sync. this issue was
// discovered on the "new vendor catalog batch" page
value(val) {
this.$nextTick(() => {
if (this.buefyValue != val) {
this.buefyValue = val
}
})
},
},
methods: {
// fetch new search results from the server. this is invoked

View file

@ -64,7 +64,7 @@
<b-autocomplete ref="autocomplete"
:name="name"
v-show="!assignedValue && !selected"
v-show="!value && !selected"
v-model="buefyValue"
:placeholder="placeholder"
:data="data"
@ -76,7 +76,7 @@
</template>
</b-autocomplete>
<b-button v-if="assignedValue || selected"
<b-button v-if="value || selected"
style="width: 100%; justify-content: left;"
@click="clearSelection(true)">
{{ getDisplayText() }} (click to change)

View file

@ -3,6 +3,7 @@
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy:
<script type="text/javascript">
var vendormap = {
@ -50,6 +51,29 @@
});
</script>
% endif
</%def>
<%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()}
<script type="text/javascript">
${form.component_studly}Data.parsers = ${json.dumps(parsers_data)|n}
${form.component_studly}Data.vendorName = null
${form.component_studly}.watch.field_model_parser_key = function(val) {
let parser = this.parsers[val]
if (parser.vendor_uuid) {
if (this.field_model_vendor_uuid != parser.vendor_uuid) {
this.field_model_vendor_uuid = parser.vendor_uuid
this.vendorName = parser.vendor_name
}
}
}
</script>
</%def>
${parent.body()}

View file

@ -110,7 +110,8 @@
<tailbone-autocomplete name="${name}"
service-url="${url}"
v-model="${vmodel}"
initial-label="${field_display}">
initial-label="${field_display}"
tal:attributes=":assigned-label assigned_label or 'null';">
</tailbone-autocomplete>
</div>

View file

@ -76,6 +76,8 @@
template: '#${form.component}-template',
components: {},
props: {},
watch: {},
computed: {},
methods: {
## TODO: deprecate / remove the latter option here

View file

@ -6,11 +6,11 @@
<h3 class="block is-size-3">Display</h3>
<div class="block" style="padding-left: 2rem;">
<b-field message="If not set, vendor chooser is a dropdown field.">
<b-checkbox name="rattail.vendor.use_autocomplete"
v-model="simpleSettings['rattail.vendor.use_autocomplete']"
<b-field message="If not set, vendor chooser is an autocomplete field.">
<b-checkbox name="rattail.vendors.choice_uses_dropdown"
v-model="simpleSettings['rattail.vendors.choice_uses_dropdown']"
@input="settingsNeedSaved = true">
Show vendor chooser as autocomplete field
Show vendor chooser as dropdown (select) element
</b-checkbox>
</b-field>

View file

@ -30,15 +30,13 @@ import logging
import six
from rattail.db import model, api
from rattail.vendors.catalogs import iter_catalog_parsers
from rattail.db import model
import colander
from deform import widget as dfwidget
from webhelpers2.html import tags
from tailbone import forms
from tailbone.db import Session
from tailbone.views.batch import FileBatchMasterView
from tailbone.diffs import Diff
@ -139,13 +137,9 @@ class VendorCatalogView(FileBatchMasterView):
def get_parsers(self):
if not hasattr(self, 'parsers'):
parsers = sorted(iter_catalog_parsers(), key=lambda p: p.display)
supported = self.rattail_config.getlist(
'tailbone', 'batch.vendorcatalog.supported_parsers')
if supported:
parsers = [parser for parser in parsers
if parser.key in supported]
self.parsers = parsers
app = self.get_rattail_app()
vendor_handler = app.get_vendor_handler()
self.parsers = vendor_handler.get_supported_catalog_parsers()
return self.parsers
def configure_grid(self, g):
@ -160,24 +154,8 @@ class VendorCatalogView(FileBatchMasterView):
def configure_form(self, f):
super(VendorCatalogView, self).configure_form(f)
# vendor
f.set_renderer('vendor', self.render_vendor)
if self.creating and 'vendor' in f:
f.replace('vendor', 'vendor_uuid')
f.set_node('vendor_uuid', colander.String())
vendor_display = ""
if self.request.method == 'POST':
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)
vendors_url = self.request.route_url('vendors.autocomplete')
f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, service_url=vendors_url))
f.set_label('vendor_uuid', "Vendor")
else:
f.set_readonly('vendor')
app = self.get_rattail_app()
vendor_handler = app.get_vendor_handler()
# filename
f.set_label('filename', "Catalog File")
@ -196,12 +174,75 @@ class VendorCatalogView(FileBatchMasterView):
f.set_widget('parser_key', dfwidget.SelectWidget(values=values))
f.set_label('parser_key', "File Type")
# vendor
f.set_renderer('vendor', self.render_vendor)
if self.creating and 'vendor' in f:
f.replace('vendor', 'vendor_uuid')
f.set_label('vendor_uuid', "Vendor")
use_dropdown = vendor_handler.choice_uses_dropdown()
if use_dropdown:
vendors = self.Session.query(model.Vendor)\
.order_by(model.Vendor.id)
vendor_values = [(vendor.uuid, "({}) {}".format(vendor.id,
vendor.name))
for vendor in vendors]
f.set_widget('vendor_uuid',
dfwidget.SelectWidget(values=vendor_values))
else:
vendor_display = ""
if self.request.method == 'POST':
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)
vendors_url = self.request.route_url('vendors.autocomplete')
f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, service_url=vendors_url,
assigned_label='vendorName'))
else:
f.set_readonly('vendor')
# effective
if self.creating:
f.remove('effective')
else:
f.set_readonly('effective')
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'
kwargs['parsers'] = parsers
kwargs['parsers_data'] = parsers_data
return kwargs
def get_batch_kwargs(self, batch):
kwargs = super(VendorCatalogView, self).get_batch_kwargs(batch)
kwargs['parser_key'] = batch.parser_key
@ -275,23 +316,6 @@ class VendorCatalogView(FileBatchMasterView):
return kwargs
def template_kwargs_create(self, **kwargs):
parsers = self.get_parsers()
for parser in parsers:
if parser.vendor_key:
vendor = api.get_vendor(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'
kwargs['parsers'] = parsers
return kwargs
# TODO: deprecate / remove this
VendorCatalogsView = VendorCatalogView

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar
# Copyright © 2010-2022 Lance Edgar
#
# This file is part of Rattail.
#
@ -29,7 +29,6 @@ from __future__ import unicode_literals, absolute_import
import six
from rattail.db import model, api
from rattail.time import localtime
import colander
from deform import widget as dfwidget
@ -230,7 +229,8 @@ class PurchasingBatchView(BatchMasterView):
super(PurchasingBatchView, self).configure_form(f)
model = self.model
batch = f.model_instance
today = localtime(self.rattail_config).date()
app = self.get_rattail_app()
today = app.localtime().date()
use_buefy = self.get_use_buefy()
# mode
@ -265,9 +265,15 @@ class PurchasingBatchView(BatchMasterView):
if self.creating:
f.replace('vendor', 'vendor_uuid')
f.set_label('vendor_uuid', "Vendor")
use_autocomplete = self.rattail_config.getbool(
'rattail', 'vendor.use_autocomplete', default=True)
if use_autocomplete:
vendor_handler = app.get_vendor_handler()
use_dropdown = vendor_handler.choice_uses_dropdown()
if use_dropdown:
vendors = self.Session.query(model.Vendor)\
.order_by(model.Vendor.id)
vendor_values = [(vendor.uuid, "({}) {}".format(vendor.id, vendor.name))
for vendor in vendors]
f.set_widget('vendor_uuid', dfwidget.SelectWidget(values=vendor_values))
else:
vendor_display = ""
if self.request.method == 'POST':
if self.request.POST.get('vendor_uuid'):
@ -277,12 +283,6 @@ class PurchasingBatchView(BatchMasterView):
vendors_url = self.request.route_url('vendors.autocomplete')
f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, service_url=vendors_url))
else:
vendors = self.Session.query(model.Vendor)\
.order_by(model.Vendor.id)
vendor_values = [(vendor.uuid, "({}) {}".format(vendor.id, vendor.name))
for vendor in vendors]
f.set_widget('vendor_uuid', dfwidget.SelectWidget(values=vendor_values))
elif self.editing:
f.set_readonly('vendor')

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar
# Copyright © 2010-2022 Lance Edgar
#
# This file is part of Rattail.
#
@ -200,9 +200,19 @@ class CostingBatchView(PurchasingBatchView):
form.set_default('workflow', valid_workflows[0])
# configure vendor field
use_autocomplete = self.rattail_config.getbool(
'rattail', 'vendor.use_autocomplete', default=True)
if use_autocomplete:
app = self.get_rattail_app()
vendor_handler = app.get_vendor_handler()
use_dropdown = vendor_handler.choice_uses_dropdown()
if use_dropdown:
vendors = self.Session.query(model.Vendor)\
.order_by(model.Vendor.id)
vendor_values = [(vendor.uuid, "({}) {}".format(vendor.id, vendor.name))
for vendor in vendors]
if use_buefy:
form.set_widget('vendor', dfwidget.SelectWidget(values=vendor_values))
else:
form.set_widget('vendor', forms.widgets.JQuerySelectWidget(values=vendor_values))
else:
vendor_display = ""
if self.request.method == 'POST':
if self.request.POST.get('vendor'):
@ -212,15 +222,6 @@ class CostingBatchView(PurchasingBatchView):
vendors_url = self.request.route_url('vendors.autocomplete')
form.set_widget('vendor', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, service_url=vendors_url))
else:
vendors = self.Session.query(model.Vendor)\
.order_by(model.Vendor.id)
vendor_values = [(vendor.uuid, "({}) {}".format(vendor.id, vendor.name))
for vendor in vendors]
if use_buefy:
form.set_widget('vendor', dfwidget.SelectWidget(values=vendor_values))
else:
form.set_widget('vendor', forms.widgets.JQuerySelectWidget(values=vendor_values))
# configure workflow field
values = [(workflow['workflow_key'], workflow['display'])

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar
# Copyright © 2010-2022 Lance Edgar
#
# This file is part of Rattail.
#
@ -294,9 +294,19 @@ class ReceivingBatchView(PurchasingBatchView):
use_buefy=use_buefy)
# configure vendor field
use_autocomplete = self.rattail_config.getbool(
'rattail', 'vendor.use_autocomplete', default=True)
if use_autocomplete:
app = self.get_rattail_app()
vendor_handler = app.get_vendor_handler()
use_dropdown = vendor_handler.choice_uses_dropdown()
if use_dropdown:
vendors = self.Session.query(model.Vendor)\
.order_by(model.Vendor.id)
vendor_values = [(vendor.uuid, "({}) {}".format(vendor.id, vendor.name))
for vendor in vendors]
if use_buefy:
form.set_widget('vendor', dfwidget.SelectWidget(values=vendor_values))
else:
form.set_widget('vendor', forms.widgets.JQuerySelectWidget(values=vendor_values))
else:
vendor_display = ""
if self.request.method == 'POST':
if self.request.POST.get('vendor'):
@ -306,15 +316,6 @@ class ReceivingBatchView(PurchasingBatchView):
vendors_url = self.request.route_url('vendors.autocomplete')
form.set_widget('vendor', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, service_url=vendors_url))
else:
vendors = self.Session.query(model.Vendor)\
.order_by(model.Vendor.id)
vendor_values = [(vendor.uuid, "({}) {}".format(vendor.id, vendor.name))
for vendor in vendors]
if use_buefy:
form.set_widget('vendor', dfwidget.SelectWidget(values=vendor_values))
else:
form.set_widget('vendor', forms.widgets.JQuerySelectWidget(values=vendor_values))
# configure workflow field
values = [(workflow['workflow_key'], workflow['display'])

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar
# Copyright © 2010-2022 Lance Edgar
#
# This file is part of Rattail.
#
@ -175,7 +175,7 @@ class VendorView(MasterView):
# display
{'section': 'rattail',
'option': 'vendor.use_autocomplete',
'option': 'vendors.choice_uses_dropdown',
'type': bool},
]