Remove several references to "buefy" name
class methods, template filenames, etc. also made various edits per newer conventions
This commit is contained in:
parent
96ba039299
commit
c036932ce4
|
@ -33,10 +33,9 @@ from collections import OrderedDict
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
from sqlalchemy.ext.associationproxy import AssociationProxy, ASSOCIATION_PROXY
|
from sqlalchemy.ext.associationproxy import AssociationProxy, ASSOCIATION_PROXY
|
||||||
|
from wuttjamaican.util import UNSPECIFIED
|
||||||
|
|
||||||
from rattail.time import localtime
|
from rattail.util import prettify, pretty_boolean
|
||||||
from rattail.util import prettify, pretty_boolean, pretty_quantity
|
|
||||||
from rattail.core import UNSPECIFIED
|
|
||||||
from rattail.db.util import get_fieldnames
|
from rattail.db.util import get_fieldnames
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
|
@ -50,8 +49,8 @@ from webhelpers2.html import tags, HTML
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.util import raw_datetime, get_form_data, render_markdown
|
from tailbone.util import raw_datetime, get_form_data, render_markdown
|
||||||
from . import types
|
from tailbone.forms import types
|
||||||
from .widgets import (ReadonlyWidget, PlainDateWidget,
|
from tailbone.forms.widgets import (ReadonlyWidget, PlainDateWidget,
|
||||||
JQueryDateWidget, JQueryTimeWidget,
|
JQueryDateWidget, JQueryTimeWidget,
|
||||||
MultiFileUploadWidget)
|
MultiFileUploadWidget)
|
||||||
from tailbone.exceptions import TailboneJSONFieldError
|
from tailbone.exceptions import TailboneJSONFieldError
|
||||||
|
@ -225,7 +224,7 @@ class CustomSchemaNode(SQLAlchemySchemaNode):
|
||||||
if excludes:
|
if excludes:
|
||||||
overrides['excludes'] = excludes
|
overrides['excludes'] = excludes
|
||||||
|
|
||||||
return super(CustomSchemaNode, self).get_schema_from_relationship(prop, overrides)
|
return super().get_schema_from_relationship(prop, overrides)
|
||||||
|
|
||||||
def dictify(self, obj):
|
def dictify(self, obj):
|
||||||
""" Return a dictified version of `obj` using schema information.
|
""" Return a dictified version of `obj` using schema information.
|
||||||
|
@ -234,7 +233,7 @@ class CustomSchemaNode(SQLAlchemySchemaNode):
|
||||||
This method was copied from upstream and modified to add automatic
|
This method was copied from upstream and modified to add automatic
|
||||||
handling of "association proxy" fields.
|
handling of "association proxy" fields.
|
||||||
"""
|
"""
|
||||||
dict_ = super(CustomSchemaNode, self).dictify(obj)
|
dict_ = super().dictify(obj)
|
||||||
for node in self:
|
for node in self:
|
||||||
|
|
||||||
name = node.name
|
name = node.name
|
||||||
|
@ -967,7 +966,7 @@ class Form(object):
|
||||||
kwargs.setdefault(':configure-fields-help', 'configureFieldsHelp')
|
kwargs.setdefault(':configure-fields-help', 'configureFieldsHelp')
|
||||||
return HTML.tag(self.component, **kwargs)
|
return HTML.tag(self.component, **kwargs)
|
||||||
|
|
||||||
def render_buefy_field(self, fieldname, bfield_attrs={}):
|
def render_field_complete(self, fieldname, bfield_attrs={}):
|
||||||
"""
|
"""
|
||||||
Render the given field in a Buefy-compatible way. Note that
|
Render the given field in a Buefy-compatible way. Note that
|
||||||
this is meant to render *editable* fields, i.e. showing a
|
this is meant to render *editable* fields, i.e. showing a
|
||||||
|
@ -1131,7 +1130,8 @@ class Form(object):
|
||||||
value = self.obtain_value(record, field_name)
|
value = self.obtain_value(record, field_name)
|
||||||
if value is None:
|
if value is None:
|
||||||
return ""
|
return ""
|
||||||
value = localtime(self.request.rattail_config, value)
|
app = self.get_rattail_app()
|
||||||
|
value = app.localtime(value)
|
||||||
return raw_datetime(self.request.rattail_config, value)
|
return raw_datetime(self.request.rattail_config, value)
|
||||||
|
|
||||||
def render_duration(self, record, field_name):
|
def render_duration(self, record, field_name):
|
||||||
|
@ -1160,7 +1160,8 @@ class Form(object):
|
||||||
value = self.obtain_value(obj, field)
|
value = self.obtain_value(obj, field)
|
||||||
if value is None:
|
if value is None:
|
||||||
return ""
|
return ""
|
||||||
return pretty_quantity(value)
|
app = self.get_rattail_app()
|
||||||
|
return app.render_quantity(value)
|
||||||
|
|
||||||
def render_percent(self, obj, field):
|
def render_percent(self, obj, field):
|
||||||
app = self.request.rattail_config.get_app()
|
app = self.request.rattail_config.get_app()
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -153,6 +153,7 @@ class DynamicCheckboxWidget(dfwidget.CheckboxWidget):
|
||||||
template = 'checkbox_dynamic'
|
template = 'checkbox_dynamic'
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: deprecate / remove this
|
||||||
class PlainSelectWidget(dfwidget.SelectWidget):
|
class PlainSelectWidget(dfwidget.SelectWidget):
|
||||||
template = 'select_plain'
|
template = 'select_plain'
|
||||||
|
|
||||||
|
|
|
@ -1339,10 +1339,10 @@ class Grid(object):
|
||||||
includes the context menu items and grid tools.
|
includes the context menu items and grid tools.
|
||||||
"""
|
"""
|
||||||
if 'grid_columns' not in kwargs:
|
if 'grid_columns' not in kwargs:
|
||||||
kwargs['grid_columns'] = self.get_buefy_columns()
|
kwargs['grid_columns'] = self.get_table_columns()
|
||||||
|
|
||||||
if 'grid_data' not in kwargs:
|
if 'grid_data' not in kwargs:
|
||||||
kwargs['grid_data'] = self.get_buefy_data()
|
kwargs['grid_data'] = self.get_table_data()
|
||||||
|
|
||||||
if 'static_data' not in kwargs:
|
if 'static_data' not in kwargs:
|
||||||
kwargs['static_data'] = self.has_static_data()
|
kwargs['static_data'] = self.has_static_data()
|
||||||
|
@ -1364,8 +1364,9 @@ class Grid(object):
|
||||||
warnings.warn("Grid.render_buefy() is deprecated; "
|
warnings.warn("Grid.render_buefy() is deprecated; "
|
||||||
"please use Grid.render_complete() instead",
|
"please use Grid.render_complete() instead",
|
||||||
DeprecationWarning, stacklevel=2)
|
DeprecationWarning, stacklevel=2)
|
||||||
|
return self.render_complete(**kwargs)
|
||||||
|
|
||||||
def render_buefy_table_element(self, template='/grids/b-table.mako',
|
def render_table_element(self, template='/grids/b-table.mako',
|
||||||
data_prop='gridData', empty_labels=False,
|
data_prop='gridData', empty_labels=False,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -1377,7 +1378,7 @@ class Grid(object):
|
||||||
context['data_prop'] = data_prop
|
context['data_prop'] = data_prop
|
||||||
context['empty_labels'] = empty_labels
|
context['empty_labels'] = empty_labels
|
||||||
if 'grid_columns' not in context:
|
if 'grid_columns' not in context:
|
||||||
context['grid_columns'] = self.get_buefy_columns()
|
context['grid_columns'] = self.get_table_columns()
|
||||||
context.setdefault('paginated', False)
|
context.setdefault('paginated', False)
|
||||||
if context['paginated']:
|
if context['paginated']:
|
||||||
context.setdefault('per_page', 20)
|
context.setdefault('per_page', 20)
|
||||||
|
@ -1572,10 +1573,10 @@ class Grid(object):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_buefy_columns(self):
|
def get_table_columns(self):
|
||||||
"""
|
"""
|
||||||
Return a list of dicts representing all grid columns. Meant for use
|
Return a list of dicts representing all grid columns. Meant
|
||||||
with Buefy table.
|
for use with the client-side JS table.
|
||||||
"""
|
"""
|
||||||
columns = []
|
columns = []
|
||||||
for name in self.columns:
|
for name in self.columns:
|
||||||
|
@ -1597,9 +1598,10 @@ class Grid(object):
|
||||||
if hasattr(rowobj, 'uuid'):
|
if hasattr(rowobj, 'uuid'):
|
||||||
return rowobj.uuid
|
return rowobj.uuid
|
||||||
|
|
||||||
def get_buefy_data(self):
|
def get_table_data(self):
|
||||||
"""
|
"""
|
||||||
Returns a list of data rows for the grid, for use with Buefy table.
|
Returns a list of data rows for the grid, for use with
|
||||||
|
client-side JS table.
|
||||||
"""
|
"""
|
||||||
# filter / sort / paginate to get "visible" data
|
# filter / sort / paginate to get "visible" data
|
||||||
raw_data = self.make_visible_data()
|
raw_data = self.make_visible_data()
|
||||||
|
@ -1635,8 +1637,8 @@ class Grid(object):
|
||||||
# instance, when the "display" version is different than raw data.
|
# instance, when the "display" version is different than raw data.
|
||||||
# here is the hack we use for that.
|
# here is the hack we use for that.
|
||||||
columns = list(self.columns)
|
columns = list(self.columns)
|
||||||
if hasattr(self, 'buefy_data_columns'):
|
if hasattr(self, 'raw_data_columns'):
|
||||||
columns.extend(self.buefy_data_columns)
|
columns.extend(self.raw_data_columns)
|
||||||
|
|
||||||
# iterate over data fields
|
# iterate over data fields
|
||||||
for name in columns:
|
for name in columns:
|
||||||
|
|
|
@ -154,7 +154,7 @@
|
||||||
${parent.modify_this_page_vars()}
|
${parent.modify_this_page_vars()}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
ThisPageData.groups = ${json.dumps(buefy_data)|n}
|
ThisPageData.groups = ${json.dumps(settings_data)|n}
|
||||||
ThisPageData.showingGroup = ${json.dumps(current_group or '')|n}
|
ThisPageData.showingGroup = ${json.dumps(current_group or '')|n}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<tailbone-form></tailbone-form>
|
<tailbone-form></tailbone-form>
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
</nav>
|
</nav>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_form()">
|
<%def name="render_form_template()">
|
||||||
<script type="text/x-template" id="${form.component}-template">
|
<script type="text/x-template" id="${form.component}-template">
|
||||||
<div class="product-info">
|
<div class="product-info">
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
## -*- coding: utf-8; -*-
|
## -*- coding: utf-8; -*-
|
||||||
<%inherit file="/master/view_row.mako" />
|
<%inherit file="/master/view_row.mako" />
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<tailbone-form></tailbone-form>
|
<tailbone-form></tailbone-form>
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
</div>
|
</div>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_form()">
|
<%def name="render_form_template()">
|
||||||
## TODO: should use self.render_form_buttons()
|
## TODO: should use self.render_form_buttons()
|
||||||
## ${form.render_deform(form_id='batch-form', buttons=capture(self.render_form_buttons))|n}
|
## ${form.render_deform(form_id='batch-form', buttons=capture(self.render_form_buttons))|n}
|
||||||
${form.render_deform(form_id='batch-form', buttons=capture(buttons))|n}
|
${form.render_deform(form_id='batch-form', buttons=capture(buttons))|n}
|
||||||
|
@ -206,7 +206,7 @@
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<${form.component} @show-upload="showUploadDialog = true">
|
<${form.component} @show-upload="showUploadDialog = true">
|
||||||
</${form.component}>
|
</${form.component}>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<tailbone-form @detach-person="detachPerson">
|
<tailbone-form @detach-person="detachPerson">
|
||||||
</tailbone-form>
|
</tailbone-form>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
## -*- coding: utf-8; -*-
|
## -*- coding: utf-8; -*-
|
||||||
<%inherit file="/master/view.mako" />
|
<%inherit file="/master/view.mako" />
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<${form.component} ref="mainForm"
|
<${form.component} ref="mainForm"
|
||||||
% if master.has_perm('confirm_price'):
|
% if master.has_perm('confirm_price'):
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
|
|
||||||
<%def name="render_form_buttons()"></%def>
|
<%def name="render_form_buttons()"></%def>
|
||||||
|
|
||||||
<%def name="render_form()">
|
<%def name="render_form_template()">
|
||||||
${form.render_deform(buttons=capture(self.render_form_buttons))|n}
|
${form.render_deform(buttons=capture(self.render_form_buttons))|n}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
${form.render_vuejs_component()}
|
${form.render_vuejs_component()}
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
<%def name="page_content()">
|
<%def name="page_content()">
|
||||||
<div class="form-wrapper">
|
<div class="form-wrapper">
|
||||||
<br />
|
<br />
|
||||||
${self.render_buefy_form()}
|
${self.render_form()}
|
||||||
</div>
|
</div>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
|
|
||||||
<%def name="render_this_page_template()">
|
<%def name="render_this_page_template()">
|
||||||
% if form is not Undefined:
|
% if form is not Undefined:
|
||||||
${self.render_form()}
|
${self.render_form_template()}
|
||||||
% endif
|
% endif
|
||||||
${parent.render_this_page_template()}
|
${parent.render_this_page_template()}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<div class="panel-block">
|
<div class="panel-block">
|
||||||
<div>
|
<div>
|
||||||
% for field in form.grouping[group]:
|
% for field in form.grouping[group]:
|
||||||
${form.render_buefy_field(field)}
|
${form.render_field_complete(field)}
|
||||||
% endfor
|
% endfor
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
% endfor
|
% endfor
|
||||||
% else:
|
% else:
|
||||||
% for field in form.fields:
|
% for field in form.fields:
|
||||||
${form.render_buefy_field(field)}
|
${form.render_field_complete(field)}
|
||||||
% endfor
|
% endfor
|
||||||
% endif
|
% endif
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
## -*- coding: utf-8; -*-
|
|
||||||
|
|
||||||
## TODO: deprecate / remove this
|
|
||||||
## (tried to add deprecation warning here but it didn't seem to work)
|
|
||||||
<%def name="render_buefy_field(field, bfield_kwargs={})">
|
|
||||||
${form.render_buefy_field(field.name, bfield_attrs=bfield_kwargs)}
|
|
||||||
</%def>
|
|
|
@ -3,12 +3,12 @@
|
||||||
|
|
||||||
<%def name="title()">Clone ${model_title}: ${instance_title}</%def>
|
<%def name="title()">Clone ${model_title}: ${instance_title}</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<br />
|
<br />
|
||||||
<b-notification :closable="false">
|
<b-notification :closable="false">
|
||||||
You are about to clone the following ${model_title} as a new record:
|
You are about to clone the following ${model_title} as a new record:
|
||||||
</b-notification>
|
</b-notification>
|
||||||
${parent.render_buefy_form()}
|
${parent.render_form()}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_form_buttons()">
|
<%def name="render_form_buttons()">
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
|
|
||||||
<%def name="title()">Delete ${model_title}: ${instance_title}</%def>
|
<%def name="title()">Delete ${model_title}: ${instance_title}</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<br />
|
<br />
|
||||||
<b-notification type="is-danger" :closable="false">
|
<b-notification type="is-danger" :closable="false">
|
||||||
You are about to delete the following ${model_title} and all associated data:
|
You are about to delete the following ${model_title} and all associated data:
|
||||||
</b-notification>
|
</b-notification>
|
||||||
${parent.render_buefy_form()}
|
${parent.render_form()}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_form_buttons()">
|
<%def name="render_form_buttons()">
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
${view_profiles_helper([instance])}
|
${view_profiles_helper([instance])}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<tailbone-form v-on:make-user="makeUser"></tailbone-form>
|
<tailbone-form v-on:make-user="makeUser"></tailbone-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1403,7 +1403,7 @@
|
||||||
|
|
||||||
% if request.has_perm('people_profile.view_versions'):
|
% if request.has_perm('people_profile.view_versions'):
|
||||||
|
|
||||||
${revisions_grid.render_buefy_table_element(data_prop='revisions',
|
${revisions_grid.render_table_element(data_prop='revisions',
|
||||||
show_footer=True,
|
show_footer=True,
|
||||||
vshow='viewingHistory',
|
vshow='viewingHistory',
|
||||||
loading='gettingRevisions')|n}
|
loading='gettingRevisions')|n}
|
||||||
|
|
|
@ -95,8 +95,8 @@
|
||||||
${parent.modify_this_page_vars()}
|
${parent.modify_this_page_vars()}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
ThisPageData.permissionGroups = ${json.dumps(buefy_perms)|n}
|
ThisPageData.permissionGroups = ${json.dumps(perms_data)|n}
|
||||||
ThisPageData.sortedGroups = ${json.dumps(buefy_sorted_groups)|n}
|
ThisPageData.sortedGroups = ${json.dumps(sorted_groups_data)|n}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</%def>
|
</%def>
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
groupPermissions: ${json.dumps(buefy_perms.get(selected_group, {}).get('permissions', []))|n},
|
groupPermissions: ${json.dumps(perms_data.get(selected_group, {}).get('permissions', []))|n},
|
||||||
permissionGroupTerm: '',
|
permissionGroupTerm: '',
|
||||||
permissionTerm: '',
|
permissionTerm: '',
|
||||||
selectedGroup: ${json.dumps(selected_group)|n},
|
selectedGroup: ${json.dumps(selected_group)|n},
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
${h.end_form()}
|
${h.end_form()}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_form()">
|
<%def name="render_form_template()">
|
||||||
<script type="text/x-template" id="${form.component}-template">
|
<script type="text/x-template" id="${form.component}-template">
|
||||||
${self.render_form_innards()}
|
${self.render_form_innards()}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -108,7 +108,7 @@
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="lookup_codes_grid()">
|
<%def name="lookup_codes_grid()">
|
||||||
${lookup_codes['grid'].render_buefy_table_element(data_prop='lookupCodesData')|n}
|
${lookup_codes['grid'].render_table_element(data_prop='lookupCodesData')|n}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="lookup_codes_panel()">
|
<%def name="lookup_codes_panel()">
|
||||||
|
@ -121,7 +121,7 @@
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="sources_grid()">
|
<%def name="sources_grid()">
|
||||||
${vendor_sources['grid'].render_buefy_table_element(data_prop='vendorSourcesData')|n}
|
${vendor_sources['grid'].render_table_element(data_prop='vendorSourcesData')|n}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="sources_panel()">
|
<%def name="sources_panel()">
|
||||||
|
@ -175,7 +175,7 @@
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
<section class="modal-card-body">
|
<section class="modal-card-body">
|
||||||
${regular_price_history_grid.render_buefy_table_element(data_prop='regularPriceHistoryData', loading='regularPriceHistoryLoading', paginated=True, per_page=10)|n}
|
${regular_price_history_grid.render_table_element(data_prop='regularPriceHistoryData', loading='regularPriceHistoryLoading', paginated=True, per_page=10)|n}
|
||||||
</section>
|
</section>
|
||||||
<footer class="modal-card-foot">
|
<footer class="modal-card-foot">
|
||||||
<b-button @click="showingPriceHistory_regular = false">
|
<b-button @click="showingPriceHistory_regular = false">
|
||||||
|
@ -194,7 +194,7 @@
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
<section class="modal-card-body">
|
<section class="modal-card-body">
|
||||||
${current_price_history_grid.render_buefy_table_element(data_prop='currentPriceHistoryData', loading='currentPriceHistoryLoading', paginated=True, per_page=10)|n}
|
${current_price_history_grid.render_table_element(data_prop='currentPriceHistoryData', loading='currentPriceHistoryLoading', paginated=True, per_page=10)|n}
|
||||||
</section>
|
</section>
|
||||||
<footer class="modal-card-foot">
|
<footer class="modal-card-foot">
|
||||||
<b-button @click="showingPriceHistory_current = false">
|
<b-button @click="showingPriceHistory_current = false">
|
||||||
|
@ -213,7 +213,7 @@
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
<section class="modal-card-body">
|
<section class="modal-card-body">
|
||||||
${suggested_price_history_grid.render_buefy_table_element(data_prop='suggestedPriceHistoryData', loading='suggestedPriceHistoryLoading', paginated=True, per_page=10)|n}
|
${suggested_price_history_grid.render_table_element(data_prop='suggestedPriceHistoryData', loading='suggestedPriceHistoryLoading', paginated=True, per_page=10)|n}
|
||||||
</section>
|
</section>
|
||||||
<footer class="modal-card-foot">
|
<footer class="modal-card-foot">
|
||||||
<b-button @click="showingPriceHistory_suggested = false">
|
<b-button @click="showingPriceHistory_suggested = false">
|
||||||
|
@ -232,7 +232,7 @@
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
<section class="modal-card-body">
|
<section class="modal-card-body">
|
||||||
${cost_history_grid.render_buefy_table_element(data_prop='costHistoryData', loading='costHistoryLoading', paginated=True, per_page=10)|n}
|
${cost_history_grid.render_table_element(data_prop='costHistoryData', loading='costHistoryLoading', paginated=True, per_page=10)|n}
|
||||||
</section>
|
</section>
|
||||||
<footer class="modal-card-foot">
|
<footer class="modal-card-foot">
|
||||||
<b-button @click="showingCostHistory = false">
|
<b-button @click="showingCostHistory = false">
|
||||||
|
@ -289,7 +289,7 @@
|
||||||
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
|
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
|
||||||
|
|
||||||
ThisPageData.showingPriceHistory_regular = false
|
ThisPageData.showingPriceHistory_regular = false
|
||||||
ThisPageData.regularPriceHistoryDataRaw = ${json.dumps(regular_price_history_grid.get_buefy_data()['data'])|n}
|
ThisPageData.regularPriceHistoryDataRaw = ${json.dumps(regular_price_history_grid.get_table_data()['data'])|n}
|
||||||
ThisPageData.regularPriceHistoryLoading = false
|
ThisPageData.regularPriceHistoryLoading = false
|
||||||
|
|
||||||
ThisPage.computed.regularPriceHistoryData = function() {
|
ThisPage.computed.regularPriceHistoryData = function() {
|
||||||
|
@ -318,7 +318,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
ThisPageData.showingPriceHistory_current = false
|
ThisPageData.showingPriceHistory_current = false
|
||||||
ThisPageData.currentPriceHistoryDataRaw = ${json.dumps(current_price_history_grid.get_buefy_data()['data'])|n}
|
ThisPageData.currentPriceHistoryDataRaw = ${json.dumps(current_price_history_grid.get_table_data()['data'])|n}
|
||||||
ThisPageData.currentPriceHistoryLoading = false
|
ThisPageData.currentPriceHistoryLoading = false
|
||||||
|
|
||||||
ThisPage.computed.currentPriceHistoryData = function() {
|
ThisPage.computed.currentPriceHistoryData = function() {
|
||||||
|
@ -348,7 +348,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
ThisPageData.showingPriceHistory_suggested = false
|
ThisPageData.showingPriceHistory_suggested = false
|
||||||
ThisPageData.suggestedPriceHistoryDataRaw = ${json.dumps(suggested_price_history_grid.get_buefy_data()['data'])|n}
|
ThisPageData.suggestedPriceHistoryDataRaw = ${json.dumps(suggested_price_history_grid.get_table_data()['data'])|n}
|
||||||
ThisPageData.suggestedPriceHistoryLoading = false
|
ThisPageData.suggestedPriceHistoryLoading = false
|
||||||
|
|
||||||
ThisPage.computed.suggestedPriceHistoryData = function() {
|
ThisPage.computed.suggestedPriceHistoryData = function() {
|
||||||
|
@ -377,7 +377,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
ThisPageData.showingCostHistory = false
|
ThisPageData.showingCostHistory = false
|
||||||
ThisPageData.costHistoryDataRaw = ${json.dumps(cost_history_grid.get_buefy_data()['data'])|n}
|
ThisPageData.costHistoryDataRaw = ${json.dumps(cost_history_grid.get_table_data()['data'])|n}
|
||||||
ThisPageData.costHistoryLoading = false
|
ThisPageData.costHistoryLoading = false
|
||||||
|
|
||||||
ThisPage.computed.costHistoryData = function() {
|
ThisPage.computed.costHistoryData = function() {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
## -*- coding: utf-8; -*-
|
## -*- coding: utf-8; -*-
|
||||||
<%inherit file="/form.mako" />
|
<%inherit file="/form.mako" />
|
||||||
<%namespace file="/forms/util.mako" import="render_buefy_field" />
|
|
||||||
|
|
||||||
<%def name="title()">Declare Credit for Row #${row.sequence}</%def>
|
<%def name="title()">Declare Credit for Row #${row.sequence}</%def>
|
||||||
|
|
||||||
|
@ -11,7 +10,7 @@
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
|
|
||||||
<p class="block">
|
<p class="block">
|
||||||
Please select the "state" of the product, and enter the
|
Please select the "state" of the product, and enter the
|
||||||
|
@ -31,22 +30,22 @@
|
||||||
if you need to "receive" instead of "convert" the product.
|
if you need to "receive" instead of "convert" the product.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
${parent.render_buefy_form()}
|
${parent.render_form()}
|
||||||
|
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="buefy_form_body()">
|
<%def name="form_body()">
|
||||||
|
|
||||||
${render_buefy_field(dform['credit_type'])}
|
${form.render_field_complete('credit_type')}
|
||||||
|
|
||||||
${render_buefy_field(dform['quantity'])}
|
${form.render_field_complete('quantity')}
|
||||||
|
|
||||||
${render_buefy_field(dform['expiration_date'], bfield_kwargs={'v-show': "field_model_credit_type == 'expired'"})}
|
${form.render_field_complete('expiration_date', bfield_attrs={'v-show': "field_model_credit_type == 'expired'"})}
|
||||||
|
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_form()">
|
<%def name="render_form_template()">
|
||||||
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
|
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.form_body))|n}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
## -*- coding: utf-8; -*-
|
## -*- coding: utf-8; -*-
|
||||||
<%inherit file="/form.mako" />
|
<%inherit file="/form.mako" />
|
||||||
<%namespace file="/forms/util.mako" import="render_buefy_field" />
|
|
||||||
|
|
||||||
<%def name="title()">Receive for Row #${row.sequence}</%def>
|
<%def name="title()">Receive for Row #${row.sequence}</%def>
|
||||||
|
|
||||||
|
@ -11,7 +10,7 @@
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
|
|
||||||
<p class="block">
|
<p class="block">
|
||||||
Please select the "state" of the product, and enter the appropriate
|
Please select the "state" of the product, and enter the appropriate
|
||||||
|
@ -28,22 +27,22 @@
|
||||||
if you need to "convert" some already-received amount, into a credit.
|
if you need to "convert" some already-received amount, into a credit.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
${parent.render_buefy_form()}
|
${parent.render_form()}
|
||||||
|
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="buefy_form_body()">
|
<%def name="form_body()">
|
||||||
|
|
||||||
${render_buefy_field(dform['mode'])}
|
${form.render_field_complete('mode')}
|
||||||
|
|
||||||
${render_buefy_field(dform['quantity'])}
|
${form.render_field_complete('quantity')}
|
||||||
|
|
||||||
${render_buefy_field(dform['expiration_date'], bfield_kwargs={'v-show': "field_model_mode == 'expired'"})}
|
${form.render_field_complete('expiration_date', bfield_attrs={'v-show': "field_model_mode == 'expired'"})}
|
||||||
|
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_form()">
|
<%def name="render_form_template()">
|
||||||
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.buefy_form_body))|n}
|
${form.render_deform(buttons=capture(self.render_form_buttons), form_body=capture(self.form_body))|n}
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
</style>
|
</style>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<p>Please select the type of report you wish to generate.</p>
|
<p>Please select the type of report you wish to generate.</p>
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
<%def name="content_title()">New Report: ${report.name}</%def>
|
<%def name="content_title()">New Report: ${report.name}</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<p class="block">
|
<p class="block">
|
||||||
${report.__doc__}
|
${report.__doc__}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
## -*- coding: utf-8; -*-
|
## -*- coding: utf-8; -*-
|
||||||
<%inherit file="/master/view.mako" />
|
<%inherit file="/master/view.mako" />
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
${parent.render_buefy_form()}
|
${parent.render_form()}
|
||||||
<email-preview-tools></email-preview-tools>
|
<email-preview-tools></email-preview-tools>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
<%def name="render_buefy_form()">
|
<%def name="render_form()">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<${form.component}
|
<${form.component}
|
||||||
% if master.has_perm('execute'):
|
% if master.has_perm('execute'):
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<b-select name="tailbone.${user.uuid}.buefy_css"
|
<b-select name="tailbone.${user.uuid}.buefy_css"
|
||||||
v-model="simpleSettings['tailbone.${user.uuid}.buefy_css']"
|
v-model="simpleSettings['tailbone.${user.uuid}.buefy_css']"
|
||||||
@input="settingsNeedSaved = true">
|
@input="settingsNeedSaved = true">
|
||||||
<option v-for="option in buefyCSSOptions"
|
<option v-for="option in themeStyleOptions"
|
||||||
:key="option.value"
|
:key="option.value"
|
||||||
:value="option.value">
|
:value="option.value">
|
||||||
{{ option.label }}
|
{{ option.label }}
|
||||||
|
@ -46,7 +46,7 @@
|
||||||
${parent.modify_this_page_vars()}
|
${parent.modify_this_page_vars()}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
ThisPageData.buefyCSSOptions = ${json.dumps(buefy_css_options)|n}
|
ThisPageData.themeStyleOptions = ${json.dumps(theme_style_options)|n}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -32,23 +32,18 @@ import logging
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import warnings
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import markdown
|
import markdown
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
|
|
||||||
from rattail.db import model, Session as RattailSession
|
|
||||||
from rattail.db.util import short_session
|
|
||||||
from rattail.threads import Thread
|
from rattail.threads import Thread
|
||||||
from rattail.util import prettify, simple_error
|
from rattail.util import simple_error
|
||||||
from rattail.progress import SocketProgress
|
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
import deform
|
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
from pyramid.renderers import render_to_response
|
|
||||||
from pyramid.response import FileResponse
|
|
||||||
from webhelpers2.html import HTML, tags
|
from webhelpers2.html import HTML, tags
|
||||||
|
|
||||||
from tailbone import forms, grids
|
from tailbone import forms, grids
|
||||||
|
@ -115,7 +110,7 @@ class BatchMasterView(MasterView):
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
super(BatchMasterView, self).__init__(request)
|
super().__init__(request)
|
||||||
self.batch_handler = self.get_handler()
|
self.batch_handler = self.get_handler()
|
||||||
# TODO: deprecate / remove this (?)
|
# TODO: deprecate / remove this (?)
|
||||||
self.handler = self.batch_handler
|
self.handler = self.batch_handler
|
||||||
|
@ -167,7 +162,7 @@ class BatchMasterView(MasterView):
|
||||||
return self.rattail_config.batch_filepath(batch.batch_key, batch.uuid, filename)
|
return self.rattail_config.batch_filepath(batch.batch_key, batch.uuid, filename)
|
||||||
|
|
||||||
def template_kwargs_view(self, **kwargs):
|
def template_kwargs_view(self, **kwargs):
|
||||||
kwargs = super(BatchMasterView, self).template_kwargs_view(**kwargs)
|
kwargs = super().template_kwargs_view(**kwargs)
|
||||||
batch = kwargs['instance']
|
batch = kwargs['instance']
|
||||||
kwargs['batch'] = batch
|
kwargs['batch'] = batch
|
||||||
kwargs['handler'] = self.handler
|
kwargs['handler'] = self.handler
|
||||||
|
@ -195,7 +190,7 @@ class BatchMasterView(MasterView):
|
||||||
g.set_click_handler('title', "autoFilterStatus(props.row)")
|
g.set_click_handler('title', "autoFilterStatus(props.row)")
|
||||||
kwargs['status_breakdown_data'] = breakdown
|
kwargs['status_breakdown_data'] = breakdown
|
||||||
kwargs['status_breakdown_grid'] = HTML.literal(
|
kwargs['status_breakdown_grid'] = HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='statusBreakdownData',
|
g.render_table_element(data_prop='statusBreakdownData',
|
||||||
empty_labels=True))
|
empty_labels=True))
|
||||||
|
|
||||||
return kwargs
|
return kwargs
|
||||||
|
@ -288,7 +283,8 @@ class BatchMasterView(MasterView):
|
||||||
return not batch.executed and not batch.complete
|
return not batch.executed and not batch.complete
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
super(BatchMasterView, self).configure_grid(g)
|
super().configure_grid(g)
|
||||||
|
model = self.model
|
||||||
|
|
||||||
# created_by
|
# created_by
|
||||||
CreatedBy = orm.aliased(model.User)
|
CreatedBy = orm.aliased(model.User)
|
||||||
|
@ -337,7 +333,7 @@ class BatchMasterView(MasterView):
|
||||||
return batch.id_str
|
return batch.id_str
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(BatchMasterView, self).configure_form(f)
|
super().configure_form(f)
|
||||||
|
|
||||||
# id
|
# id
|
||||||
f.set_readonly('id')
|
f.set_readonly('id')
|
||||||
|
@ -436,7 +432,7 @@ class BatchMasterView(MasterView):
|
||||||
|
|
||||||
label = HTML.literal(
|
label = HTML.literal(
|
||||||
'{{{{ togglingBatchComplete ? "Working, please wait..." : "{}" }}}}'.format(label))
|
'{{{{ togglingBatchComplete ? "Working, please wait..." : "{}" }}}}'.format(label))
|
||||||
submit = self.make_buefy_button(label, is_primary=True,
|
submit = self.make_button(label, is_primary=True,
|
||||||
native_type='submit',
|
native_type='submit',
|
||||||
**{':disabled': 'togglingBatchComplete'})
|
**{':disabled': 'togglingBatchComplete'})
|
||||||
|
|
||||||
|
@ -603,7 +599,7 @@ class BatchMasterView(MasterView):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def configure_row_grid(self, g):
|
def configure_row_grid(self, g):
|
||||||
super(BatchMasterView, self).configure_row_grid(g)
|
super().configure_row_grid(g)
|
||||||
|
|
||||||
g.set_sort_defaults('sequence')
|
g.set_sort_defaults('sequence')
|
||||||
g.set_link('sequence')
|
g.set_link('sequence')
|
||||||
|
@ -644,7 +640,7 @@ class BatchMasterView(MasterView):
|
||||||
if batch.executed:
|
if batch.executed:
|
||||||
self.request.session.flash("You cannot add new rows to a batch which has been executed")
|
self.request.session.flash("You cannot add new rows to a batch which has been executed")
|
||||||
return self.redirect(self.get_action_url('view', batch))
|
return self.redirect(self.get_action_url('view', batch))
|
||||||
return super(BatchMasterView, self).create_row()
|
return super().create_row()
|
||||||
|
|
||||||
def save_create_row_form(self, form):
|
def save_create_row_form(self, form):
|
||||||
batch = self.get_instance()
|
batch = self.get_instance()
|
||||||
|
@ -657,7 +653,7 @@ class BatchMasterView(MasterView):
|
||||||
self.handler.refresh_row(row)
|
self.handler.refresh_row(row)
|
||||||
|
|
||||||
def configure_row_form(self, f):
|
def configure_row_form(self, f):
|
||||||
super(BatchMasterView, self).configure_row_form(f)
|
super().configure_row_form(f)
|
||||||
|
|
||||||
# sequence
|
# sequence
|
||||||
f.set_readonly('sequence')
|
f.set_readonly('sequence')
|
||||||
|
@ -681,7 +677,7 @@ class BatchMasterView(MasterView):
|
||||||
permission_prefix = self.get_permission_prefix()
|
permission_prefix = self.get_permission_prefix()
|
||||||
if self.request.has_perm('{}.create_row'.format(permission_prefix)):
|
if self.request.has_perm('{}.create_row'.format(permission_prefix)):
|
||||||
url = self.get_action_url('create_row', batch)
|
url = self.get_action_url('create_row', batch)
|
||||||
return self.make_buefy_button("New Row", url=url,
|
return self.make_button("New Row", url=url,
|
||||||
is_primary=True,
|
is_primary=True,
|
||||||
icon_left='plus')
|
icon_left='plus')
|
||||||
|
|
||||||
|
@ -719,7 +715,7 @@ class BatchMasterView(MasterView):
|
||||||
|
|
||||||
kwargs['main_actions'] = actions
|
kwargs['main_actions'] = actions
|
||||||
|
|
||||||
return super(BatchMasterView, self).make_row_grid_kwargs(**kwargs)
|
return super().make_row_grid_kwargs(**kwargs)
|
||||||
|
|
||||||
def make_row_grid_tools(self, batch):
|
def make_row_grid_tools(self, batch):
|
||||||
return (self.make_default_row_grid_tools(batch) or '') + (self.make_batch_row_grid_tools(batch) or '')
|
return (self.make_default_row_grid_tools(batch) or '') + (self.make_batch_row_grid_tools(batch) or '')
|
||||||
|
@ -852,8 +848,11 @@ class BatchMasterView(MasterView):
|
||||||
labels = kwargs.setdefault('labels', {})
|
labels = kwargs.setdefault('labels', {})
|
||||||
labels[field.name] = field.title
|
labels[field.name] = field.title
|
||||||
|
|
||||||
# auto-convert select widgets for buefy theme
|
# auto-convert select widgets for theme
|
||||||
if isinstance(field.widget, forms.widgets.PlainSelectWidget):
|
if isinstance(field.widget, forms.widgets.PlainSelectWidget):
|
||||||
|
warnings.warn("PlainSelectWidget is deprecated; "
|
||||||
|
"please use deform.widget.SelectWidget instead",
|
||||||
|
DeprecationWarning)
|
||||||
field.widget = dfwidget.SelectWidget(values=field.widget.values)
|
field.widget = dfwidget.SelectWidget(values=field.widget.values)
|
||||||
|
|
||||||
if not schema:
|
if not schema:
|
||||||
|
@ -1022,7 +1021,8 @@ class BatchMasterView(MasterView):
|
||||||
cxn.close()
|
cxn.close()
|
||||||
|
|
||||||
def catchup_versions(self, port, batch_uuid, username, *models):
|
def catchup_versions(self, port, batch_uuid, username, *models):
|
||||||
with short_session() as s:
|
app = self.get_rattail_app()
|
||||||
|
with app.short_session() as s:
|
||||||
batch = s.get(self.model_class, batch_uuid)
|
batch = s.get(self.model_class, batch_uuid)
|
||||||
batch_id = batch.id_str
|
batch_id = batch.id_str
|
||||||
description = str(batch)
|
description = str(batch)
|
||||||
|
@ -1048,8 +1048,10 @@ class BatchMasterView(MasterView):
|
||||||
"""
|
"""
|
||||||
Thread target for populating batch data with progress indicator.
|
Thread target for populating batch data with progress indicator.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
# mustn't use tailbone web session here
|
# mustn't use tailbone web session here
|
||||||
session = RattailSession()
|
session = app.make_session()
|
||||||
batch = session.get(self.model_class, batch_uuid)
|
batch = session.get(self.model_class, batch_uuid)
|
||||||
user = session.get(model.User, user_uuid)
|
user = session.get(model.User, user_uuid)
|
||||||
try:
|
try:
|
||||||
|
@ -1107,7 +1109,9 @@ class BatchMasterView(MasterView):
|
||||||
# Refresh data for the batch, with progress. Note that we must use the
|
# Refresh data for the batch, with progress. Note that we must use the
|
||||||
# rattail session here; can't use tailbone because it has web request
|
# rattail session here; can't use tailbone because it has web request
|
||||||
# transaction binding etc.
|
# transaction binding etc.
|
||||||
session = RattailSession()
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
|
session = app.make_session()
|
||||||
batch = session.get(self.model_class, batch_uuid)
|
batch = session.get(self.model_class, batch_uuid)
|
||||||
cognizer = session.get(model.User, user_uuid) if user_uuid else None
|
cognizer = session.get(model.User, user_uuid) if user_uuid else None
|
||||||
try:
|
try:
|
||||||
|
@ -1160,7 +1164,9 @@ class BatchMasterView(MasterView):
|
||||||
"""
|
"""
|
||||||
Thread target for refreshing multiple batches with progress indicator.
|
Thread target for refreshing multiple batches with progress indicator.
|
||||||
"""
|
"""
|
||||||
session = RattailSession()
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
|
session = app.make_session()
|
||||||
batches = batches.with_session(session).all()
|
batches = batches.with_session(session).all()
|
||||||
user = session.get(model.User, user_uuid)
|
user = session.get(model.User, user_uuid)
|
||||||
try:
|
try:
|
||||||
|
@ -1257,7 +1263,7 @@ class BatchMasterView(MasterView):
|
||||||
self.handler.do_remove_row(row)
|
self.handler.do_remove_row(row)
|
||||||
|
|
||||||
def delete_row_objects(self, rows):
|
def delete_row_objects(self, rows):
|
||||||
deleted = super(BatchMasterView, self).delete_row_objects(rows)
|
deleted = super().delete_row_objects(rows)
|
||||||
batch = self.get_instance()
|
batch = self.get_instance()
|
||||||
|
|
||||||
# decrement rowcount for batch
|
# decrement rowcount for batch
|
||||||
|
@ -1300,7 +1306,9 @@ class BatchMasterView(MasterView):
|
||||||
# Execute the batch, with progress. Note that we must use the rattail
|
# Execute the batch, with progress. Note that we must use the rattail
|
||||||
# session here; can't use tailbone because it has web request
|
# session here; can't use tailbone because it has web request
|
||||||
# transaction binding etc.
|
# transaction binding etc.
|
||||||
session = RattailSession()
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
|
session = app.make_session()
|
||||||
batch = self.get_instance_for_key(key, session)
|
batch = self.get_instance_for_key(key, session)
|
||||||
user = session.get(model.User, user_uuid)
|
user = session.get(model.User, user_uuid)
|
||||||
try:
|
try:
|
||||||
|
@ -1375,7 +1383,9 @@ class BatchMasterView(MasterView):
|
||||||
"""
|
"""
|
||||||
Thread target for executing multiple batches with progress indicator.
|
Thread target for executing multiple batches with progress indicator.
|
||||||
"""
|
"""
|
||||||
session = RattailSession()
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
|
session = app.make_session()
|
||||||
batches = batches.with_session(session).all()
|
batches = batches.with_session(session).all()
|
||||||
user = session.get(model.User, user_uuid)
|
user = session.get(model.User, user_uuid)
|
||||||
try:
|
try:
|
||||||
|
@ -1415,7 +1425,7 @@ class BatchMasterView(MasterView):
|
||||||
return self.get_index_url()
|
return self.get_index_url()
|
||||||
|
|
||||||
def get_row_csv_fields(self):
|
def get_row_csv_fields(self):
|
||||||
fields = super(BatchMasterView, self).get_row_csv_fields()
|
fields = super().get_row_csv_fields()
|
||||||
fields = [field for field in fields
|
fields = [field for field in fields
|
||||||
if field not in ('uuid', 'batch_uuid', 'removed')]
|
if field not in ('uuid', 'batch_uuid', 'removed')]
|
||||||
return fields
|
return fields
|
||||||
|
@ -1538,7 +1548,7 @@ class FileBatchMasterView(BatchMasterView):
|
||||||
return uploads
|
return uploads
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(FileBatchMasterView, self).configure_form(f)
|
super().configure_form(f)
|
||||||
batch = f.model_instance
|
batch = f.model_instance
|
||||||
|
|
||||||
# filename
|
# filename
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -26,12 +26,12 @@ Views for handheld batches
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db.model import HandheldBatch, HandheldBatchRow
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
|
from deform import widget as dfwidget
|
||||||
from webhelpers2.html import tags
|
from webhelpers2.html import tags
|
||||||
|
|
||||||
from tailbone import forms
|
|
||||||
from tailbone.views.batch import FileBatchMasterView
|
from tailbone.views.batch import FileBatchMasterView
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,14 +46,14 @@ class ExecutionOptions(colander.Schema):
|
||||||
action = colander.SchemaNode(
|
action = colander.SchemaNode(
|
||||||
colander.String(),
|
colander.String(),
|
||||||
validator=colander.OneOf(ACTION_OPTIONS),
|
validator=colander.OneOf(ACTION_OPTIONS),
|
||||||
widget=forms.widgets.PlainSelectWidget(values=ACTION_OPTIONS.items()))
|
widget=dfwidget.SelectWidget(values=ACTION_OPTIONS.items()))
|
||||||
|
|
||||||
|
|
||||||
class HandheldBatchView(FileBatchMasterView):
|
class HandheldBatchView(FileBatchMasterView):
|
||||||
"""
|
"""
|
||||||
Master view for handheld batches.
|
Master view for handheld batches.
|
||||||
"""
|
"""
|
||||||
model_class = model.HandheldBatch
|
model_class = HandheldBatch
|
||||||
default_handler_spec = 'rattail.batch.handheld:HandheldBatchHandler'
|
default_handler_spec = 'rattail.batch.handheld:HandheldBatchHandler'
|
||||||
model_title_plural = "Handheld Batches"
|
model_title_plural = "Handheld Batches"
|
||||||
route_prefix = 'batch.handheld'
|
route_prefix = 'batch.handheld'
|
||||||
|
@ -61,7 +61,7 @@ class HandheldBatchView(FileBatchMasterView):
|
||||||
execution_options_schema = ExecutionOptions
|
execution_options_schema = ExecutionOptions
|
||||||
editable = False
|
editable = False
|
||||||
|
|
||||||
model_row_class = model.HandheldBatchRow
|
model_row_class = HandheldBatchRow
|
||||||
rows_creatable = False
|
rows_creatable = False
|
||||||
rows_editable = True
|
rows_editable = True
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ class HandheldBatchView(FileBatchMasterView):
|
||||||
]
|
]
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
super(HandheldBatchView, self).configure_grid(g)
|
super().configure_grid(g)
|
||||||
device_types = OrderedDict(sorted(self.enum.HANDHELD_DEVICE_TYPE.items(),
|
device_types = OrderedDict(sorted(self.enum.HANDHELD_DEVICE_TYPE.items(),
|
||||||
key=lambda item: item[1]))
|
key=lambda item: item[1]))
|
||||||
g.set_enum('device_type', device_types)
|
g.set_enum('device_type', device_types)
|
||||||
|
@ -126,7 +126,7 @@ class HandheldBatchView(FileBatchMasterView):
|
||||||
return 'notice'
|
return 'notice'
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(HandheldBatchView, self).configure_form(f)
|
super().configure_form(f)
|
||||||
batch = f.model_instance
|
batch = f.model_instance
|
||||||
|
|
||||||
# device_type
|
# device_type
|
||||||
|
@ -156,13 +156,13 @@ class HandheldBatchView(FileBatchMasterView):
|
||||||
return tags.link_to(text, url)
|
return tags.link_to(text, url)
|
||||||
|
|
||||||
def get_batch_kwargs(self, batch):
|
def get_batch_kwargs(self, batch):
|
||||||
kwargs = super(HandheldBatchView, self).get_batch_kwargs(batch)
|
kwargs = super().get_batch_kwargs(batch)
|
||||||
kwargs['device_type'] = batch.device_type
|
kwargs['device_type'] = batch.device_type
|
||||||
kwargs['device_name'] = batch.device_name
|
kwargs['device_name'] = batch.device_name
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def configure_row_grid(self, g):
|
def configure_row_grid(self, g):
|
||||||
super(HandheldBatchView, self).configure_row_grid(g)
|
super().configure_row_grid(g)
|
||||||
g.set_type('cases', 'quantity')
|
g.set_type('cases', 'quantity')
|
||||||
g.set_type('units', 'quantity')
|
g.set_type('units', 'quantity')
|
||||||
g.set_label('brand_name', "Brand")
|
g.set_label('brand_name', "Brand")
|
||||||
|
@ -172,7 +172,7 @@ class HandheldBatchView(FileBatchMasterView):
|
||||||
return 'warning'
|
return 'warning'
|
||||||
|
|
||||||
def configure_row_form(self, f):
|
def configure_row_form(self, f):
|
||||||
super(HandheldBatchView, self).configure_row_form(f)
|
super().configure_row_form(f)
|
||||||
|
|
||||||
# readonly fields
|
# readonly fields
|
||||||
f.set_readonly('upc')
|
f.set_readonly('upc')
|
||||||
|
@ -188,7 +188,7 @@ class HandheldBatchView(FileBatchMasterView):
|
||||||
return self.request.route_url('batch.inventory.view', uuid=result.uuid)
|
return self.request.route_url('batch.inventory.view', uuid=result.uuid)
|
||||||
elif kwargs['action'] == 'make_label_batch':
|
elif kwargs['action'] == 'make_label_batch':
|
||||||
return self.request.route_url('labels.batch.view', uuid=result.uuid)
|
return self.request.route_url('labels.batch.view', uuid=result.uuid)
|
||||||
return super(HandheldBatchView, self).get_execute_success_url(batch)
|
return super().get_execute_success_url(batch)
|
||||||
|
|
||||||
def get_execute_results_success_url(self, result, **kwargs):
|
def get_execute_results_success_url(self, result, **kwargs):
|
||||||
if result is True:
|
if result is True:
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -206,7 +206,7 @@ class POSBatchView(BatchMasterView):
|
||||||
)
|
)
|
||||||
|
|
||||||
return HTML.literal(
|
return HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='taxesData'))
|
g.render_table_element(data_prop='taxesData'))
|
||||||
|
|
||||||
def template_kwargs_view(self, **kwargs):
|
def template_kwargs_view(self, **kwargs):
|
||||||
kwargs = super().template_kwargs_view(**kwargs)
|
kwargs = super().template_kwargs_view(**kwargs)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -26,12 +26,12 @@ Views for generic product batches
|
||||||
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db.model import ProductBatch, ProductBatchRow
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
|
from deform import widget as dfwidget
|
||||||
from webhelpers2.html import HTML
|
from webhelpers2.html import HTML
|
||||||
|
|
||||||
from tailbone import forms
|
|
||||||
from tailbone.views.batch import BatchMasterView
|
from tailbone.views.batch import BatchMasterView
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,15 +46,15 @@ class ExecutionOptions(colander.Schema):
|
||||||
action = colander.SchemaNode(
|
action = colander.SchemaNode(
|
||||||
colander.String(),
|
colander.String(),
|
||||||
validator=colander.OneOf(ACTION_OPTIONS),
|
validator=colander.OneOf(ACTION_OPTIONS),
|
||||||
widget=forms.widgets.PlainSelectWidget(values=ACTION_OPTIONS.items()))
|
widget=dfwidget.SelectWidget(values=ACTION_OPTIONS.items()))
|
||||||
|
|
||||||
|
|
||||||
class ProductBatchView(BatchMasterView):
|
class ProductBatchView(BatchMasterView):
|
||||||
"""
|
"""
|
||||||
Master view for product batches.
|
Master view for product batches.
|
||||||
"""
|
"""
|
||||||
model_class = model.ProductBatch
|
model_class = ProductBatch
|
||||||
model_row_class = model.ProductBatchRow
|
model_row_class = ProductBatchRow
|
||||||
default_handler_spec = 'rattail.batch.product:ProductBatchHandler'
|
default_handler_spec = 'rattail.batch.product:ProductBatchHandler'
|
||||||
route_prefix = 'batch.product'
|
route_prefix = 'batch.product'
|
||||||
url_prefix = '/batches/product'
|
url_prefix = '/batches/product'
|
||||||
|
@ -129,7 +129,7 @@ class ProductBatchView(BatchMasterView):
|
||||||
]
|
]
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(ProductBatchView, self).configure_form(f)
|
super().configure_form(f)
|
||||||
|
|
||||||
# input_filename
|
# input_filename
|
||||||
if self.creating:
|
if self.creating:
|
||||||
|
@ -139,7 +139,8 @@ class ProductBatchView(BatchMasterView):
|
||||||
f.set_renderer('input_filename', self.render_downloadable_file)
|
f.set_renderer('input_filename', self.render_downloadable_file)
|
||||||
|
|
||||||
def configure_row_grid(self, g):
|
def configure_row_grid(self, g):
|
||||||
super(ProductBatchView, self).configure_row_grid(g)
|
super().configure_row_grid(g)
|
||||||
|
model = self.model
|
||||||
|
|
||||||
g.set_joiner('vendor', lambda q: q.outerjoin(model.Vendor))
|
g.set_joiner('vendor', lambda q: q.outerjoin(model.Vendor))
|
||||||
g.set_sorter('vendor', model.Vendor.name)
|
g.set_sorter('vendor', model.Vendor.name)
|
||||||
|
@ -165,7 +166,7 @@ class ProductBatchView(BatchMasterView):
|
||||||
return 'warning'
|
return 'warning'
|
||||||
|
|
||||||
def configure_row_form(self, f):
|
def configure_row_form(self, f):
|
||||||
super(ProductBatchView, self).configure_row_form(f)
|
super().configure_row_form(f)
|
||||||
|
|
||||||
f.set_type('upc', 'gpc')
|
f.set_type('upc', 'gpc')
|
||||||
|
|
||||||
|
@ -204,10 +205,10 @@ class ProductBatchView(BatchMasterView):
|
||||||
return self.request.route_url('labels.batch.view', uuid=result.uuid)
|
return self.request.route_url('labels.batch.view', uuid=result.uuid)
|
||||||
elif kwargs['action'] == 'make_pricing_batch':
|
elif kwargs['action'] == 'make_pricing_batch':
|
||||||
return self.request.route_url('batch.pricing.view', uuid=result.uuid)
|
return self.request.route_url('batch.pricing.view', uuid=result.uuid)
|
||||||
return super(ProductBatchView, self).get_execute_success_url(batch)
|
return super().get_execute_success_url(batch)
|
||||||
|
|
||||||
def get_row_csv_fields(self):
|
def get_row_csv_fields(self):
|
||||||
fields = super(ProductBatchView, self).get_row_csv_fields()
|
fields = super().get_row_csv_fields()
|
||||||
|
|
||||||
if 'vendor_uuid' in fields:
|
if 'vendor_uuid' in fields:
|
||||||
i = fields.index('vendor_uuid')
|
i = fields.index('vendor_uuid')
|
||||||
|
@ -273,12 +274,12 @@ class ProductBatchView(BatchMasterView):
|
||||||
data['report_name'] = (report.name or '') if report else ''
|
data['report_name'] = (report.name or '') if report else ''
|
||||||
|
|
||||||
def get_row_csv_row(self, row, fields):
|
def get_row_csv_row(self, row, fields):
|
||||||
csvrow = super(ProductBatchView, self).get_row_csv_row(row, fields)
|
csvrow = super().get_row_csv_row(row, fields)
|
||||||
self.supplement_row_data(row, fields, csvrow)
|
self.supplement_row_data(row, fields, csvrow)
|
||||||
return csvrow
|
return csvrow
|
||||||
|
|
||||||
def get_row_xlsx_row(self, row, fields):
|
def get_row_xlsx_row(self, row, fields):
|
||||||
xlrow = super(ProductBatchView, self).get_row_xlsx_row(row, fields)
|
xlrow = super().get_row_xlsx_row(row, fields)
|
||||||
self.supplement_row_data(row, fields, xlrow)
|
self.supplement_row_data(row, fields, xlrow)
|
||||||
return xlrow
|
return xlrow
|
||||||
|
|
||||||
|
|
|
@ -341,7 +341,7 @@ class CustomerView(MasterView):
|
||||||
# people
|
# people
|
||||||
if self.should_expose_people():
|
if self.should_expose_people():
|
||||||
if self.viewing:
|
if self.viewing:
|
||||||
f.set_renderer('people', self.render_people_buefy)
|
f.set_renderer('people', self.render_people)
|
||||||
else:
|
else:
|
||||||
f.remove('people')
|
f.remove('people')
|
||||||
else:
|
else:
|
||||||
|
@ -463,20 +463,6 @@ class CustomerView(MasterView):
|
||||||
url = self.request.route_url('people.view', uuid=person.uuid)
|
url = self.request.route_url('people.view', uuid=person.uuid)
|
||||||
return tags.link_to(text, url)
|
return tags.link_to(text, url)
|
||||||
|
|
||||||
# TODO: remove if no longer used
|
|
||||||
def render_people(self, customer, field):
|
|
||||||
people = customer.people
|
|
||||||
if not people:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
items = []
|
|
||||||
for person in people:
|
|
||||||
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)
|
|
||||||
|
|
||||||
def render_shoppers(self, customer, field):
|
def render_shoppers(self, customer, field):
|
||||||
route_prefix = self.get_route_prefix()
|
route_prefix = self.get_route_prefix()
|
||||||
permission_prefix = self.get_permission_prefix()
|
permission_prefix = self.get_permission_prefix()
|
||||||
|
@ -504,9 +490,9 @@ class CustomerView(MasterView):
|
||||||
)
|
)
|
||||||
|
|
||||||
return HTML.literal(
|
return HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='shoppers'))
|
g.render_table_element(data_prop='shoppers'))
|
||||||
|
|
||||||
def render_people_buefy(self, customer, field):
|
def render_people(self, customer, field):
|
||||||
route_prefix = self.get_route_prefix()
|
route_prefix = self.get_route_prefix()
|
||||||
permission_prefix = self.get_permission_prefix()
|
permission_prefix = self.get_permission_prefix()
|
||||||
|
|
||||||
|
@ -533,7 +519,7 @@ class CustomerView(MasterView):
|
||||||
click_handler="$emit('detach-person', props.row._action_url_detach)"))
|
click_handler="$emit('detach-person', props.row._action_url_detach)"))
|
||||||
|
|
||||||
return HTML.literal(
|
return HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='peopleData'))
|
g.render_table_element(data_prop='peopleData'))
|
||||||
|
|
||||||
def render_groups(self, customer, field):
|
def render_groups(self, customer, field):
|
||||||
groups = customer.groups
|
groups = customer.groups
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -401,7 +401,7 @@ class CustomerOrderItemView(MasterView):
|
||||||
)
|
)
|
||||||
|
|
||||||
table = HTML.literal(
|
table = HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='eventsData'))
|
g.render_table_element(data_prop='eventsData'))
|
||||||
elements = [table]
|
elements = [table]
|
||||||
|
|
||||||
if self.has_perm('add_note'):
|
if self.has_perm('add_note'):
|
||||||
|
|
|
@ -144,7 +144,7 @@ class DepartmentView(MasterView):
|
||||||
g.main_actions.append(self.make_action('edit', icon='edit'))
|
g.main_actions.append(self.make_action('edit', icon='edit'))
|
||||||
|
|
||||||
return HTML.literal(
|
return HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='employeesData'))
|
g.render_table_element(data_prop='employeesData'))
|
||||||
|
|
||||||
def template_kwargs_view(self, **kwargs):
|
def template_kwargs_view(self, **kwargs):
|
||||||
kwargs = super().template_kwargs_view(**kwargs)
|
kwargs = super().template_kwargs_view(**kwargs)
|
||||||
|
|
|
@ -30,7 +30,6 @@ import csv
|
||||||
import datetime
|
import datetime
|
||||||
import getpass
|
import getpass
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
|
||||||
import logging
|
import logging
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
@ -40,12 +39,10 @@ from sqlalchemy import orm
|
||||||
import sqlalchemy_continuum as continuum
|
import sqlalchemy_continuum as continuum
|
||||||
from sqlalchemy_utils.functions import get_primary_keys, get_columns
|
from sqlalchemy_utils.functions import get_primary_keys, get_columns
|
||||||
|
|
||||||
from rattail.db import model, Session as RattailSession
|
|
||||||
from rattail.db.continuum import model_transaction_query
|
from rattail.db.continuum import model_transaction_query
|
||||||
from rattail.util import simple_error, get_class_hierarchy
|
from rattail.util import simple_error, get_class_hierarchy
|
||||||
from rattail.threads import Thread
|
from rattail.threads import Thread
|
||||||
from rattail.csvutil import UnicodeDictWriter
|
from rattail.csvutil import UnicodeDictWriter
|
||||||
from rattail.files import temp_path
|
|
||||||
from rattail.excel import ExcelWriter
|
from rattail.excel import ExcelWriter
|
||||||
from rattail.gpc import GPC
|
from rattail.gpc import GPC
|
||||||
|
|
||||||
|
@ -54,7 +51,6 @@ import deform
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
from pyramid import httpexceptions
|
from pyramid import httpexceptions
|
||||||
from pyramid.renderers import get_renderer, render_to_response, render
|
from pyramid.renderers import get_renderer, render_to_response, render
|
||||||
from pyramid.response import FileResponse
|
|
||||||
from webhelpers2.html import HTML, tags
|
from webhelpers2.html import HTML, tags
|
||||||
from webob.compat import cgi_FieldStorage
|
from webob.compat import cgi_FieldStorage
|
||||||
|
|
||||||
|
@ -220,7 +216,8 @@ class MasterView(View):
|
||||||
to the current thread (one per request), this method should instead
|
to the current thread (one per request), this method should instead
|
||||||
return e.g. a new independent ``rattail.db.Session`` instance.
|
return e.g. a new independent ``rattail.db.Session`` instance.
|
||||||
"""
|
"""
|
||||||
return RattailSession()
|
app = self.get_rattail_app()
|
||||||
|
return app.make_session()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_grid_factory(cls):
|
def get_grid_factory(cls):
|
||||||
|
@ -348,7 +345,7 @@ class MasterView(View):
|
||||||
|
|
||||||
# return grid data only, if partial page was requested
|
# return grid data only, if partial page was requested
|
||||||
if self.request.params.get('partial'):
|
if self.request.params.get('partial'):
|
||||||
return self.json_response(grid.get_buefy_data())
|
return self.json_response(grid.get_table_data())
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'grid': grid,
|
'grid': grid,
|
||||||
|
@ -719,10 +716,11 @@ class MasterView(View):
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def normalize_uploads(self, form, skip=None):
|
def normalize_uploads(self, form, skip=None):
|
||||||
|
app = self.get_rattail_app()
|
||||||
uploads = {}
|
uploads = {}
|
||||||
|
|
||||||
def normalize(filedict):
|
def normalize(filedict):
|
||||||
tempdir = tempfile.mkdtemp()
|
tempdir = app.make_temp_dir()
|
||||||
filepath = os.path.join(tempdir, filedict['filename'])
|
filepath = os.path.join(tempdir, filedict['filename'])
|
||||||
tmpinfo = form.deform_form[node.name].widget.tmpstore.get(filedict['uid'])
|
tmpinfo = form.deform_form[node.name].widget.tmpstore.get(filedict['uid'])
|
||||||
tmpdata = tmpinfo['fp'].read()
|
tmpdata = tmpinfo['fp'].read()
|
||||||
|
@ -1114,7 +1112,8 @@ class MasterView(View):
|
||||||
Thread target for populating new object with progress indicator.
|
Thread target for populating new object with progress indicator.
|
||||||
"""
|
"""
|
||||||
# mustn't use tailbone web session here
|
# mustn't use tailbone web session here
|
||||||
session = RattailSession()
|
app = self.get_rattail_app()
|
||||||
|
session = app.make_session()
|
||||||
obj = session.get(self.model_class, uuid)
|
obj = session.get(self.model_class, uuid)
|
||||||
try:
|
try:
|
||||||
self.populate_object(session, obj, progress=progress)
|
self.populate_object(session, obj, progress=progress)
|
||||||
|
@ -1175,7 +1174,7 @@ class MasterView(View):
|
||||||
# return grid only, if partial page was requested
|
# return grid only, if partial page was requested
|
||||||
if self.request.params.get('partial'):
|
if self.request.params.get('partial'):
|
||||||
# render grid data only, as JSON
|
# render grid data only, as JSON
|
||||||
return self.json_response(grid.get_buefy_data())
|
return self.json_response(grid.get_table_data())
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'instance': instance,
|
'instance': instance,
|
||||||
|
@ -1308,7 +1307,7 @@ class MasterView(View):
|
||||||
# return grid only, if partial page was requested
|
# return grid only, if partial page was requested
|
||||||
if self.request.params.get('partial'):
|
if self.request.params.get('partial'):
|
||||||
# render grid data only, as JSON
|
# render grid data only, as JSON
|
||||||
return self.json_response(grid.get_buefy_data())
|
return self.json_response(grid.get_table_data())
|
||||||
|
|
||||||
return self.render_to_response('versions', {
|
return self.render_to_response('versions', {
|
||||||
'instance': instance,
|
'instance': instance,
|
||||||
|
@ -1360,6 +1359,7 @@ class MasterView(View):
|
||||||
return classes
|
return classes
|
||||||
|
|
||||||
def make_revisions_grid(self, obj, empty_data=False):
|
def make_revisions_grid(self, obj, empty_data=False):
|
||||||
|
model = self.model
|
||||||
route_prefix = self.get_route_prefix()
|
route_prefix = self.get_route_prefix()
|
||||||
row_url = lambda txn, i: self.request.route_url(f'{route_prefix}.version',
|
row_url = lambda txn, i: self.request.route_url(f'{route_prefix}.version',
|
||||||
uuid=obj.uuid,
|
uuid=obj.uuid,
|
||||||
|
@ -1396,8 +1396,8 @@ class MasterView(View):
|
||||||
|
|
||||||
grid = self.make_version_grid(**kwargs)
|
grid = self.make_version_grid(**kwargs)
|
||||||
|
|
||||||
grid.set_joiner('user', lambda q: q.outerjoin(self.model.User))
|
grid.set_joiner('user', lambda q: q.outerjoin(model.User))
|
||||||
grid.set_sorter('user', self.model.User.username)
|
grid.set_sorter('user', model.User.username)
|
||||||
|
|
||||||
grid.set_link('remote_addr')
|
grid.set_link('remote_addr')
|
||||||
|
|
||||||
|
@ -1465,7 +1465,7 @@ class MasterView(View):
|
||||||
else: # no txnid, return grid data
|
else: # no txnid, return grid data
|
||||||
obj = self.get_instance()
|
obj = self.get_instance()
|
||||||
grid = self.make_revisions_grid(obj)
|
grid = self.make_revisions_grid(obj)
|
||||||
return grid.get_buefy_data()
|
return grid.get_table_data()
|
||||||
|
|
||||||
def view_version(self):
|
def view_version(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1770,16 +1770,10 @@ class MasterView(View):
|
||||||
path = self.download_path(obj, filename)
|
path = self.download_path(obj, filename)
|
||||||
if not path or not os.path.exists(path):
|
if not path or not os.path.exists(path):
|
||||||
raise self.notfound()
|
raise self.notfound()
|
||||||
response = FileResponse(path, request=self.request)
|
response = self.file_response(path)
|
||||||
response.content_length = os.path.getsize(path)
|
|
||||||
content_type = self.download_content_type(path, filename)
|
content_type = self.download_content_type(path, filename)
|
||||||
if content_type:
|
if content_type:
|
||||||
response.content_type = content_type
|
response.content_type = content_type
|
||||||
|
|
||||||
# content-disposition
|
|
||||||
filename = os.path.basename(path)
|
|
||||||
response.content_disposition = str('attachment; filename="{}"'.format(filename))
|
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def download_content_type(self, path, filename):
|
def download_content_type(self, path, filename):
|
||||||
|
@ -1856,7 +1850,7 @@ class MasterView(View):
|
||||||
View for deleting an existing model record.
|
View for deleting an existing model record.
|
||||||
"""
|
"""
|
||||||
if not self.deletable:
|
if not self.deletable:
|
||||||
raise httpexceptions.HTTPForbidden()
|
raise self.forbidden()
|
||||||
|
|
||||||
self.deleting = True
|
self.deleting = True
|
||||||
instance = self.get_instance()
|
instance = self.get_instance()
|
||||||
|
@ -2111,7 +2105,9 @@ class MasterView(View):
|
||||||
"""
|
"""
|
||||||
Thread target for executing an object.
|
Thread target for executing an object.
|
||||||
"""
|
"""
|
||||||
session = RattailSession()
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
|
session = app.make_session()
|
||||||
obj = self.get_instance_for_key(key, session)
|
obj = self.get_instance_for_key(key, session)
|
||||||
user = session.get(model.User, user_uuid)
|
user = session.get(model.User, user_uuid)
|
||||||
try:
|
try:
|
||||||
|
@ -2926,7 +2922,7 @@ class MasterView(View):
|
||||||
normal.append(button)
|
normal.append(button)
|
||||||
return normal
|
return normal
|
||||||
|
|
||||||
def make_buefy_button(self, label,
|
def make_button(self, label,
|
||||||
type=None, is_primary=False,
|
type=None, is_primary=False,
|
||||||
url=None, target=None, is_external=False,
|
url=None, target=None, is_external=False,
|
||||||
icon_left=None,
|
icon_left=None,
|
||||||
|
@ -2983,7 +2979,7 @@ class MasterView(View):
|
||||||
assumed to be external, which affects the icon and causes
|
assumed to be external, which affects the icon and causes
|
||||||
button click to open link in a new tab.
|
button click to open link in a new tab.
|
||||||
"""
|
"""
|
||||||
# TODO: this should call make_buefy_button()
|
# TODO: this should call make_button()
|
||||||
|
|
||||||
# nb. unfortunately HTML.tag() calls its first arg 'tag' and
|
# nb. unfortunately HTML.tag() calls its first arg 'tag' and
|
||||||
# so we can't pass a kwarg with that name...so instead we
|
# so we can't pass a kwarg with that name...so instead we
|
||||||
|
@ -4067,10 +4063,11 @@ class MasterView(View):
|
||||||
"""
|
"""
|
||||||
Download current *row* results as XLSX.
|
Download current *row* results as XLSX.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
obj = self.get_instance()
|
obj = self.get_instance()
|
||||||
results = self.get_effective_row_data(sort=True)
|
results = self.get_effective_row_data(sort=True)
|
||||||
fields = self.get_row_xlsx_fields()
|
fields = self.get_row_xlsx_fields()
|
||||||
path = temp_path(suffix='.xlsx')
|
path = app.make_temp_file(suffix='.xlsx')
|
||||||
writer = ExcelWriter(path, fields, sheet_title=self.get_row_model_title_plural())
|
writer = ExcelWriter(path, fields, sheet_title=self.get_row_model_title_plural())
|
||||||
writer.write_header()
|
writer.write_header()
|
||||||
|
|
||||||
|
@ -5039,6 +5036,7 @@ class MasterView(View):
|
||||||
"""
|
"""
|
||||||
Generic view for configuring some aspect of the software.
|
Generic view for configuring some aspect of the software.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
if self.request.method == 'POST':
|
if self.request.method == 'POST':
|
||||||
if self.request.POST.get('remove_settings'):
|
if self.request.POST.get('remove_settings'):
|
||||||
self.configure_remove_settings()
|
self.configure_remove_settings()
|
||||||
|
@ -5053,7 +5051,7 @@ class MasterView(View):
|
||||||
uploads = {}
|
uploads = {}
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
if isinstance(value, cgi_FieldStorage):
|
if isinstance(value, cgi_FieldStorage):
|
||||||
tempdir = tempfile.mkdtemp()
|
tempdir = app.make_temp_dir()
|
||||||
filename = os.path.basename(value.filename)
|
filename = os.path.basename(value.filename)
|
||||||
filepath = os.path.join(tempdir, filename)
|
filepath = os.path.join(tempdir, filename)
|
||||||
with open(filepath, 'wb') as f:
|
with open(filepath, 'wb') as f:
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -29,10 +29,8 @@ from rattail.time import localtime
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
from pyramid import httpexceptions
|
|
||||||
from webhelpers2.html import tags, HTML
|
from webhelpers2.html import tags, HTML
|
||||||
|
|
||||||
# from tailbone import forms
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import MasterView
|
from tailbone.views import MasterView
|
||||||
from tailbone.util import raw_datetime
|
from tailbone.util import raw_datetime
|
||||||
|
@ -83,15 +81,15 @@ class MessageView(MasterView):
|
||||||
|
|
||||||
def index(self):
|
def index(self):
|
||||||
if not self.request.user:
|
if not self.request.user:
|
||||||
raise httpexceptions.HTTPForbidden
|
raise self.forbidden()
|
||||||
return super().index()
|
return super().index()
|
||||||
|
|
||||||
def get_instance(self):
|
def get_instance(self):
|
||||||
if not self.request.user:
|
if not self.request.user:
|
||||||
raise httpexceptions.HTTPForbidden
|
raise self.forbidden()
|
||||||
message = super().get_instance()
|
message = super().get_instance()
|
||||||
if not self.associated_with(message):
|
if not self.associated_with(message):
|
||||||
raise httpexceptions.HTTPForbidden
|
raise self.forbidden()
|
||||||
return message
|
return message
|
||||||
|
|
||||||
def associated_with(self, message):
|
def associated_with(self, message):
|
||||||
|
@ -395,7 +393,7 @@ class MessageView(MasterView):
|
||||||
message = self.get_instance()
|
message = self.get_instance()
|
||||||
recipient = self.get_recipient(message)
|
recipient = self.get_recipient(message)
|
||||||
if not recipient:
|
if not recipient:
|
||||||
raise httpexceptions.HTTPForbidden
|
raise self.forbidden()
|
||||||
|
|
||||||
dest = self.request.GET.get('dest')
|
dest = self.request.GET.get('dest')
|
||||||
if dest not in ('inbox', 'archive'):
|
if dest not in ('inbox', 'archive'):
|
||||||
|
@ -520,7 +518,7 @@ class RecipientsWidgetBuefy(dfwidget.Widget):
|
||||||
"""
|
"""
|
||||||
Custom "message recipients" widget, for use with Buefy / Vue.js themes.
|
Custom "message recipients" widget, for use with Buefy / Vue.js themes.
|
||||||
"""
|
"""
|
||||||
template = 'message_recipients_buefy'
|
template = 'message_recipients'
|
||||||
|
|
||||||
def deserialize(self, field, pstruct):
|
def deserialize(self, field, pstruct):
|
||||||
if pstruct is colander.null:
|
if pstruct is colander.null:
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -43,7 +43,7 @@ class PrincipalMasterView(MasterView):
|
||||||
def get_fallback_templates(self, template, **kwargs):
|
def get_fallback_templates(self, template, **kwargs):
|
||||||
return [
|
return [
|
||||||
'/principal/{}.mako'.format(template),
|
'/principal/{}.mako'.format(template),
|
||||||
] + super(PrincipalMasterView, self).get_fallback_templates(template, **kwargs)
|
] + super().get_fallback_templates(template, **kwargs)
|
||||||
|
|
||||||
def perm_sortkey(self, item):
|
def perm_sortkey(self, item):
|
||||||
key, value = item
|
key, value = item
|
||||||
|
@ -74,9 +74,9 @@ class PrincipalMasterView(MasterView):
|
||||||
|
|
||||||
context = {'permissions': sorted_perms, 'principals': principals}
|
context = {'permissions': sorted_perms, 'principals': principals}
|
||||||
|
|
||||||
perms = self.get_buefy_perms_data(sorted_perms)
|
perms = self.get_perms_data(sorted_perms)
|
||||||
context['buefy_perms'] = perms
|
context['perms_data'] = perms
|
||||||
context['buefy_sorted_groups'] = list(perms)
|
context['sorted_groups_data'] = list(perms)
|
||||||
|
|
||||||
if permission_group and permission_group not in perms:
|
if permission_group and permission_group not in perms:
|
||||||
permission_group = None
|
permission_group = None
|
||||||
|
@ -95,7 +95,7 @@ class PrincipalMasterView(MasterView):
|
||||||
|
|
||||||
return self.render_to_response('find_by_perm', context)
|
return self.render_to_response('find_by_perm', context)
|
||||||
|
|
||||||
def get_buefy_perms_data(self, sorted_perms):
|
def get_perms_data(self, sorted_perms):
|
||||||
data = OrderedDict()
|
data = OrderedDict()
|
||||||
for gkey, group in sorted_perms:
|
for gkey, group in sorted_perms:
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -37,8 +37,7 @@ from rattail.db import model, api, auth, Session as RattailSession
|
||||||
from rattail.gpc import GPC
|
from rattail.gpc import GPC
|
||||||
from rattail.threads import Thread
|
from rattail.threads import Thread
|
||||||
from rattail.exceptions import LabelPrintingError
|
from rattail.exceptions import LabelPrintingError
|
||||||
from rattail.util import load_object, pretty_quantity, simple_error
|
from rattail.util import simple_error
|
||||||
from rattail.time import localtime, make_utc
|
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
|
@ -417,13 +416,13 @@ class ProductView(MasterView):
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
|
|
||||||
if price.starts:
|
if price.starts:
|
||||||
starts = localtime(self.rattail_config, price.starts, from_utc=True)
|
starts = app.localtime(price.starts, from_utc=True)
|
||||||
starts = app.render_date(starts.date())
|
starts = app.render_date(starts.date())
|
||||||
else:
|
else:
|
||||||
starts = "??"
|
starts = "??"
|
||||||
|
|
||||||
if price.ends:
|
if price.ends:
|
||||||
ends = localtime(self.rattail_config, price.ends, from_utc=True)
|
ends = app.localtime(price.ends, from_utc=True)
|
||||||
ends = app.render_date(ends.date())
|
ends = app.render_date(ends.date())
|
||||||
else:
|
else:
|
||||||
ends = "??"
|
ends = "??"
|
||||||
|
@ -456,23 +455,25 @@ class ProductView(MasterView):
|
||||||
default=True)
|
default=True)
|
||||||
|
|
||||||
def render_regular_price(self, product, field):
|
def render_regular_price(self, product, field):
|
||||||
|
app = self.get_rattail_app()
|
||||||
text = self.render_price(product, field)
|
text = self.render_price(product, field)
|
||||||
|
|
||||||
if text and self.show_price_effective_dates():
|
if text and self.show_price_effective_dates():
|
||||||
history = self.get_regular_price_history(product)
|
history = self.get_regular_price_history(product)
|
||||||
if history:
|
if history:
|
||||||
date = localtime(self.rattail_config, history[0]['changed'], from_utc=True).date()
|
date = app.localtime(history[0]['changed'], from_utc=True).date()
|
||||||
text = "{} (as of {})".format(text, date)
|
text = "{} (as of {})".format(text, date)
|
||||||
|
|
||||||
return self.add_price_history_link(text, 'regular')
|
return self.add_price_history_link(text, 'regular')
|
||||||
|
|
||||||
def render_current_price(self, product, field):
|
def render_current_price(self, product, field):
|
||||||
|
app = self.get_rattail_app()
|
||||||
text = self.render_price(product, field)
|
text = self.render_price(product, field)
|
||||||
|
|
||||||
if text and self.show_price_effective_dates():
|
if text and self.show_price_effective_dates():
|
||||||
history = self.get_current_price_history(product)
|
history = self.get_current_price_history(product)
|
||||||
if history:
|
if history:
|
||||||
date = localtime(self.rattail_config, history[0]['changed'], from_utc=True).date()
|
date = app.localtime(history[0]['changed'], from_utc=True).date()
|
||||||
text = "{} (as of {})".format(text, date)
|
text = "{} (as of {})".format(text, date)
|
||||||
|
|
||||||
return self.add_price_history_link(text, 'current')
|
return self.add_price_history_link(text, 'current')
|
||||||
|
@ -489,10 +490,11 @@ class ProductView(MasterView):
|
||||||
if not text:
|
if not text:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
app = self.get_rattail_app()
|
||||||
if self.show_price_effective_dates():
|
if self.show_price_effective_dates():
|
||||||
history = self.get_suggested_price_history(product)
|
history = self.get_suggested_price_history(product)
|
||||||
if history:
|
if history:
|
||||||
date = localtime(self.rattail_config, history[0]['changed'], from_utc=True).date()
|
date = app.localtime(history[0]['changed'], from_utc=True).date()
|
||||||
text = "{} (as of {})".format(text, date)
|
text = "{} (as of {})".format(text, date)
|
||||||
|
|
||||||
text = self.warn_if_regprice_more_than_srp(product, text)
|
text = self.warn_if_regprice_more_than_srp(product, text)
|
||||||
|
@ -526,13 +528,15 @@ class ProductView(MasterView):
|
||||||
inventory = product.inventory
|
inventory = product.inventory
|
||||||
if not inventory:
|
if not inventory:
|
||||||
return ""
|
return ""
|
||||||
return pretty_quantity(inventory.on_hand)
|
app = self.get_rattail_app()
|
||||||
|
return app.render_quantity(inventory.on_hand)
|
||||||
|
|
||||||
def render_on_order(self, product, column):
|
def render_on_order(self, product, column):
|
||||||
inventory = product.inventory
|
inventory = product.inventory
|
||||||
if not inventory:
|
if not inventory:
|
||||||
return ""
|
return ""
|
||||||
return pretty_quantity(inventory.on_order)
|
app = self.get_rattail_app()
|
||||||
|
return app.render_quantity(inventory.on_order)
|
||||||
|
|
||||||
def template_kwargs_index(self, **kwargs):
|
def template_kwargs_index(self, **kwargs):
|
||||||
kwargs = super().template_kwargs_index(**kwargs)
|
kwargs = super().template_kwargs_index(**kwargs)
|
||||||
|
@ -1105,7 +1109,8 @@ class ProductView(MasterView):
|
||||||
value = product.inventory.on_hand
|
value = product.inventory.on_hand
|
||||||
if not value:
|
if not value:
|
||||||
return ""
|
return ""
|
||||||
return pretty_quantity(value)
|
app = self.get_rattail_app()
|
||||||
|
return app.render_quantity(value)
|
||||||
|
|
||||||
def render_inventory_on_order(self, product, field):
|
def render_inventory_on_order(self, product, field):
|
||||||
if not product.inventory:
|
if not product.inventory:
|
||||||
|
@ -1113,7 +1118,8 @@ class ProductView(MasterView):
|
||||||
value = product.inventory.on_order
|
value = product.inventory.on_order
|
||||||
if not value:
|
if not value:
|
||||||
return ""
|
return ""
|
||||||
return pretty_quantity(value)
|
app = self.get_rattail_app()
|
||||||
|
return app.render_quantity(value)
|
||||||
|
|
||||||
def price_history(self):
|
def price_history(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1136,7 +1142,7 @@ class ProductView(MasterView):
|
||||||
if price is not None:
|
if price is not None:
|
||||||
history['price'] = float(price)
|
history['price'] = float(price)
|
||||||
history['price_display'] = app.render_currency(price)
|
history['price_display'] = app.render_currency(price)
|
||||||
changed = localtime(self.rattail_config, history['changed'], from_utc=True)
|
changed = app.localtime(history['changed'], from_utc=True)
|
||||||
history['changed'] = str(changed)
|
history['changed'] = str(changed)
|
||||||
history['changed_display_html'] = raw_datetime(self.rattail_config, changed)
|
history['changed_display_html'] = raw_datetime(self.rattail_config, changed)
|
||||||
user = history.pop('changed_by')
|
user = history.pop('changed_by')
|
||||||
|
@ -1149,6 +1155,7 @@ class ProductView(MasterView):
|
||||||
"""
|
"""
|
||||||
AJAX view for fetching cost history for a product.
|
AJAX view for fetching cost history for a product.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
product = self.get_instance()
|
product = self.get_instance()
|
||||||
data = self.get_cost_history(product)
|
data = self.get_cost_history(product)
|
||||||
|
|
||||||
|
@ -1162,7 +1169,7 @@ class ProductView(MasterView):
|
||||||
history['cost_display'] = "${:0.2f}".format(cost)
|
history['cost_display'] = "${:0.2f}".format(cost)
|
||||||
else:
|
else:
|
||||||
history['cost_display'] = None
|
history['cost_display'] = None
|
||||||
changed = localtime(self.rattail_config, history['changed'], from_utc=True)
|
changed = app.localtime(history['changed'], from_utc=True)
|
||||||
history['changed'] = str(changed)
|
history['changed'] = str(changed)
|
||||||
history['changed_display_html'] = raw_datetime(self.rattail_config, changed)
|
history['changed_display_html'] = raw_datetime(self.rattail_config, changed)
|
||||||
user = history.pop('changed_by')
|
user = history.pop('changed_by')
|
||||||
|
@ -1388,10 +1395,11 @@ class ProductView(MasterView):
|
||||||
Returns a sequence of "records" which corresponds to the given
|
Returns a sequence of "records" which corresponds to the given
|
||||||
product's regular price history.
|
product's regular price history.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
Transaction = continuum.transaction_class(model.Product)
|
Transaction = continuum.transaction_class(model.Product)
|
||||||
ProductVersion = continuum.version_class(model.Product)
|
ProductVersion = continuum.version_class(model.Product)
|
||||||
ProductPriceVersion = continuum.version_class(model.ProductPrice)
|
ProductPriceVersion = continuum.version_class(model.ProductPrice)
|
||||||
now = make_utc()
|
now = app.make_utc()
|
||||||
history = []
|
history = []
|
||||||
|
|
||||||
# first we find all relevant ProductVersion records
|
# first we find all relevant ProductVersion records
|
||||||
|
@ -1457,10 +1465,11 @@ class ProductView(MasterView):
|
||||||
Returns a sequence of "records" which corresponds to the given
|
Returns a sequence of "records" which corresponds to the given
|
||||||
product's current price history.
|
product's current price history.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
Transaction = continuum.transaction_class(model.Product)
|
Transaction = continuum.transaction_class(model.Product)
|
||||||
ProductVersion = continuum.version_class(model.Product)
|
ProductVersion = continuum.version_class(model.Product)
|
||||||
ProductPriceVersion = continuum.version_class(model.ProductPrice)
|
ProductPriceVersion = continuum.version_class(model.ProductPrice)
|
||||||
now = make_utc()
|
now = app.make_utc()
|
||||||
history = []
|
history = []
|
||||||
|
|
||||||
# first we find all relevant ProductVersion records
|
# first we find all relevant ProductVersion records
|
||||||
|
@ -1599,10 +1608,11 @@ class ProductView(MasterView):
|
||||||
Returns a sequence of "records" which corresponds to the given
|
Returns a sequence of "records" which corresponds to the given
|
||||||
product's SRP history.
|
product's SRP history.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
Transaction = continuum.transaction_class(model.Product)
|
Transaction = continuum.transaction_class(model.Product)
|
||||||
ProductVersion = continuum.version_class(model.Product)
|
ProductVersion = continuum.version_class(model.Product)
|
||||||
ProductPriceVersion = continuum.version_class(model.ProductPrice)
|
ProductPriceVersion = continuum.version_class(model.ProductPrice)
|
||||||
now = make_utc()
|
now = app.make_utc()
|
||||||
history = []
|
history = []
|
||||||
|
|
||||||
# first we find all relevant ProductVersion records
|
# first we find all relevant ProductVersion records
|
||||||
|
@ -1668,10 +1678,11 @@ class ProductView(MasterView):
|
||||||
Returns a sequence of "records" which corresponds to the given
|
Returns a sequence of "records" which corresponds to the given
|
||||||
product's cost history.
|
product's cost history.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
Transaction = continuum.transaction_class(model.Product)
|
Transaction = continuum.transaction_class(model.Product)
|
||||||
ProductVersion = continuum.version_class(model.Product)
|
ProductVersion = continuum.version_class(model.Product)
|
||||||
ProductCostVersion = continuum.version_class(model.ProductCost)
|
ProductCostVersion = continuum.version_class(model.ProductCost)
|
||||||
now = make_utc()
|
now = app.make_utc()
|
||||||
history = []
|
history = []
|
||||||
|
|
||||||
# we just find all relevant (preferred!) ProductCostVersion records
|
# we just find all relevant (preferred!) ProductCostVersion records
|
||||||
|
@ -1948,10 +1959,11 @@ class ProductView(MasterView):
|
||||||
"""
|
"""
|
||||||
View for making a new batch from current product grid query.
|
View for making a new batch from current product grid query.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
supported = self.get_supported_batches()
|
supported = self.get_supported_batches()
|
||||||
batch_options = []
|
batch_options = []
|
||||||
for key, info in list(supported.items()):
|
for key, info in list(supported.items()):
|
||||||
handler = load_object(info['spec'])(self.rattail_config)
|
handler = app.load_object(info['spec'])(self.rattail_config)
|
||||||
handler.spec = info['spec']
|
handler.spec = info['spec']
|
||||||
handler.option_key = key
|
handler.option_key = key
|
||||||
handler.option_title = info.get('title', handler.get_model_title())
|
handler.option_title = info.get('title', handler.get_model_title())
|
||||||
|
@ -2448,7 +2460,7 @@ class PendingProductView(MasterView):
|
||||||
if (self.has_perm('ignore_product')
|
if (self.has_perm('ignore_product')
|
||||||
and status in (self.enum.PENDING_PRODUCT_STATUS_PENDING,
|
and status in (self.enum.PENDING_PRODUCT_STATUS_PENDING,
|
||||||
self.enum.PENDING_PRODUCT_STATUS_READY)):
|
self.enum.PENDING_PRODUCT_STATUS_READY)):
|
||||||
buttons.append(self.make_buefy_button("Ignore Product",
|
buttons.append(self.make_button("Ignore Product",
|
||||||
type='is-warning',
|
type='is-warning',
|
||||||
icon_left='ban',
|
icon_left='ban',
|
||||||
**{'@click': "$emit('ignore-product')"}))
|
**{'@click': "$emit('ignore-product')"}))
|
||||||
|
@ -2457,7 +2469,7 @@ class PendingProductView(MasterView):
|
||||||
and status in (self.enum.PENDING_PRODUCT_STATUS_PENDING,
|
and status in (self.enum.PENDING_PRODUCT_STATUS_PENDING,
|
||||||
self.enum.PENDING_PRODUCT_STATUS_READY,
|
self.enum.PENDING_PRODUCT_STATUS_READY,
|
||||||
self.enum.PENDING_PRODUCT_STATUS_IGNORED)):
|
self.enum.PENDING_PRODUCT_STATUS_IGNORED)):
|
||||||
buttons.append(self.make_buefy_button("Resolve Product",
|
buttons.append(self.make_button("Resolve Product",
|
||||||
is_primary=True,
|
is_primary=True,
|
||||||
icon_left='object-ungroup',
|
icon_left='object-ungroup',
|
||||||
**{'@click': "$emit('resolve-product')"}))
|
**{'@click': "$emit('resolve-product')"}))
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -28,10 +28,9 @@ from rattail.db.model import PurchaseBatch, PurchaseBatchRow
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
from pyramid import httpexceptions
|
|
||||||
from webhelpers2.html import tags, HTML
|
from webhelpers2.html import tags, HTML
|
||||||
|
|
||||||
from tailbone import forms, grids
|
from tailbone import forms
|
||||||
from tailbone.views.batch import BatchMasterView
|
from tailbone.views.batch import BatchMasterView
|
||||||
|
|
||||||
|
|
||||||
|
@ -826,7 +825,7 @@ class PurchasingBatchView(BatchMasterView):
|
||||||
def render_row_credits(self, row, field):
|
def render_row_credits(self, row, field):
|
||||||
g = self.make_row_credits_grid(row)
|
g = self.make_row_credits_grid(row)
|
||||||
return HTML.literal(
|
return HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='rowData.credits'))
|
g.render_table_element(data_prop='rowData.credits'))
|
||||||
|
|
||||||
# def before_create_row(self, form):
|
# def before_create_row(self, form):
|
||||||
# row = form.fieldset.model
|
# row = form.fieldset.model
|
||||||
|
|
|
@ -310,8 +310,6 @@ class OrderingBatchView(PurchasingBatchView):
|
||||||
if not order_date:
|
if not order_date:
|
||||||
order_date = localtime(self.rattail_config).date()
|
order_date = localtime(self.rattail_config).date()
|
||||||
|
|
||||||
buefy_data = self.get_worksheet_buefy_data(departments)
|
|
||||||
|
|
||||||
return self.render_to_response('worksheet', {
|
return self.render_to_response('worksheet', {
|
||||||
'batch': batch,
|
'batch': batch,
|
||||||
'order_date': order_date,
|
'order_date': order_date,
|
||||||
|
@ -324,10 +322,10 @@ class OrderingBatchView(PurchasingBatchView):
|
||||||
'get_upc': lambda p: p.upc.pretty() if p.upc else '',
|
'get_upc': lambda p: p.upc.pretty() if p.upc else '',
|
||||||
'header_columns': self.order_form_header_columns,
|
'header_columns': self.order_form_header_columns,
|
||||||
'ignore_cases': not self.handler.allow_cases(),
|
'ignore_cases': not self.handler.allow_cases(),
|
||||||
'worksheet_data': buefy_data,
|
'worksheet_data': self.get_worksheet_data(departments),
|
||||||
})
|
})
|
||||||
|
|
||||||
def get_worksheet_buefy_data(self, departments):
|
def get_worksheet_data(self, departments):
|
||||||
data = {}
|
data = {}
|
||||||
for department in departments.values():
|
for department in departments.values():
|
||||||
for subdepartment in department._order_subdepartments.values():
|
for subdepartment in department._order_subdepartments.values():
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -33,12 +33,10 @@ from collections import OrderedDict
|
||||||
import humanize
|
import humanize
|
||||||
|
|
||||||
from rattail import pod
|
from rattail import pod
|
||||||
from rattail.time import localtime, make_utc
|
from rattail.util import prettify, simple_error
|
||||||
from rattail.util import pretty_quantity, prettify, simple_error
|
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
from deform import widget as dfwidget
|
from deform import widget as dfwidget
|
||||||
from pyramid import httpexceptions
|
|
||||||
from webhelpers2.html import tags, HTML
|
from webhelpers2.html import tags, HTML
|
||||||
|
|
||||||
from tailbone import forms, grids
|
from tailbone import forms, grids
|
||||||
|
@ -781,7 +779,7 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
g.set_click_handler('title', "autoFilterPoVsInvoice(props.row)")
|
g.set_click_handler('title', "autoFilterPoVsInvoice(props.row)")
|
||||||
kwargs['po_vs_invoice_breakdown_data'] = breakdown
|
kwargs['po_vs_invoice_breakdown_data'] = breakdown
|
||||||
kwargs['po_vs_invoice_breakdown_grid'] = HTML.literal(
|
kwargs['po_vs_invoice_breakdown_grid'] = HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='poVsInvoiceBreakdownData',
|
g.render_table_element(data_prop='poVsInvoiceBreakdownData',
|
||||||
empty_labels=True))
|
empty_labels=True))
|
||||||
|
|
||||||
kwargs['allow_edit_catalog_unit_cost'] = self.allow_edit_catalog_unit_cost(batch)
|
kwargs['allow_edit_catalog_unit_cost'] = self.allow_edit_catalog_unit_cost(batch)
|
||||||
|
@ -1137,6 +1135,7 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
"""
|
"""
|
||||||
Primary desktop view for row-level receiving.
|
Primary desktop view for row-level receiving.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
# TODO: this code was largely copied from mobile_receive_row() but it
|
# TODO: this code was largely copied from mobile_receive_row() but it
|
||||||
# tries to pave the way for shared logic, i.e. where the latter would
|
# tries to pave the way for shared logic, i.e. where the latter would
|
||||||
# simply invoke this method and return the result. however we're not
|
# simply invoke this method and return the result. however we're not
|
||||||
|
@ -1270,7 +1269,7 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
if accounted_for:
|
if accounted_for:
|
||||||
# some product accounted for; button should receive "remainder" only
|
# some product accounted for; button should receive "remainder" only
|
||||||
if remainder:
|
if remainder:
|
||||||
remainder = pretty_quantity(remainder)
|
remainder = app.render_quantity(remainder)
|
||||||
context['quick_receive_quantity'] = remainder
|
context['quick_receive_quantity'] = remainder
|
||||||
context['quick_receive_text'] = "Receive Remainder ({} {})".format(remainder, context['unit_uom'])
|
context['quick_receive_text'] = "Receive Remainder ({} {})".format(remainder, context['unit_uom'])
|
||||||
else:
|
else:
|
||||||
|
@ -1280,7 +1279,7 @@ class ReceivingBatchView(PurchasingBatchView):
|
||||||
else: # nothing yet accounted for, button should receive "all"
|
else: # nothing yet accounted for, button should receive "all"
|
||||||
if not remainder:
|
if not remainder:
|
||||||
raise ValueError("why is remainder empty?")
|
raise ValueError("why is remainder empty?")
|
||||||
remainder = pretty_quantity(remainder)
|
remainder = app.render_quantity(remainder)
|
||||||
context['quick_receive_quantity'] = remainder
|
context['quick_receive_quantity'] = remainder
|
||||||
context['quick_receive_text'] = "Receive ALL ({} {})".format(remainder, context['unit_uom'])
|
context['quick_receive_text'] = "Receive ALL ({} {})".format(remainder, context['unit_uom'])
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -32,9 +32,8 @@ import logging
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import rattail
|
import rattail
|
||||||
from rattail.db import model, Session as RattailSession
|
from rattail.db.model import ReportOutput
|
||||||
from rattail.files import resource_path
|
from rattail.files import resource_path
|
||||||
from rattail.time import localtime
|
|
||||||
from rattail.threads import Thread
|
from rattail.threads import Thread
|
||||||
from rattail.util import simple_error
|
from rattail.util import simple_error
|
||||||
|
|
||||||
|
@ -81,6 +80,7 @@ class OrderingWorksheet(View):
|
||||||
upc_getter = staticmethod(get_upc)
|
upc_getter = staticmethod(get_upc)
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
|
model = self.model
|
||||||
if self.request.params.get('vendor'):
|
if self.request.params.get('vendor'):
|
||||||
vendor = Session.get(model.Vendor, self.request.params['vendor'])
|
vendor = Session.get(model.Vendor, self.request.params['vendor'])
|
||||||
if vendor:
|
if vendor:
|
||||||
|
@ -104,7 +104,8 @@ class OrderingWorksheet(View):
|
||||||
"""
|
"""
|
||||||
Rendering engine for the ordering worksheet report.
|
Rendering engine for the ordering worksheet report.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
q = Session.query(model.ProductCost)
|
q = Session.query(model.ProductCost)
|
||||||
q = q.join(model.Product)
|
q = q.join(model.Product)
|
||||||
q = q.filter(model.Product.deleted == False)
|
q = q.filter(model.Product.deleted == False)
|
||||||
|
@ -127,7 +128,7 @@ class OrderingWorksheet(View):
|
||||||
key = '{0} {1}'.format(brand, product.description)
|
key = '{0} {1}'.format(brand, product.description)
|
||||||
return key
|
return key
|
||||||
|
|
||||||
now = localtime(self.request.rattail_config)
|
now = app.localtime()
|
||||||
data = dict(
|
data = dict(
|
||||||
vendor=vendor,
|
vendor=vendor,
|
||||||
costs=costs,
|
costs=costs,
|
||||||
|
@ -157,7 +158,7 @@ class InventoryWorksheet(View):
|
||||||
"""
|
"""
|
||||||
This is the "Inventory Worksheet" report.
|
This is the "Inventory Worksheet" report.
|
||||||
"""
|
"""
|
||||||
|
model = self.model
|
||||||
departments = Session.query(model.Department)
|
departments = Session.query(model.Department)
|
||||||
|
|
||||||
if self.request.params.get('department'):
|
if self.request.params.get('department'):
|
||||||
|
@ -178,6 +179,8 @@ class InventoryWorksheet(View):
|
||||||
"""
|
"""
|
||||||
Generates the Inventory Worksheet report.
|
Generates the Inventory Worksheet report.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
|
|
||||||
def get_products(subdepartment):
|
def get_products(subdepartment):
|
||||||
q = Session.query(model.Product)
|
q = Session.query(model.Product)
|
||||||
|
@ -191,7 +194,7 @@ class InventoryWorksheet(View):
|
||||||
q = q.order_by(model.Brand.name, model.Product.description)
|
q = q.order_by(model.Brand.name, model.Product.description)
|
||||||
return q.all()
|
return q.all()
|
||||||
|
|
||||||
now = localtime(self.request.rattail_config)
|
now = app.localtime()
|
||||||
data = dict(
|
data = dict(
|
||||||
date=now.strftime('%a %d %b %Y'),
|
date=now.strftime('%a %d %b %Y'),
|
||||||
time=now.strftime('%I:%M %p'),
|
time=now.strftime('%I:%M %p'),
|
||||||
|
@ -209,7 +212,7 @@ class ReportOutputView(ExportMasterView):
|
||||||
"""
|
"""
|
||||||
Master view for report output
|
Master view for report output
|
||||||
"""
|
"""
|
||||||
model_class = model.ReportOutput
|
model_class = ReportOutput
|
||||||
route_prefix = 'report_output'
|
route_prefix = 'report_output'
|
||||||
url_prefix = '/reports/generated'
|
url_prefix = '/reports/generated'
|
||||||
creatable = True
|
creatable = True
|
||||||
|
@ -238,7 +241,7 @@ class ReportOutputView(ExportMasterView):
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
super(ReportOutputView, self).__init__(request)
|
super().__init__(request)
|
||||||
self.report_handler = self.get_report_handler()
|
self.report_handler = self.get_report_handler()
|
||||||
|
|
||||||
def get_report_handler(self):
|
def get_report_handler(self):
|
||||||
|
@ -246,7 +249,7 @@ class ReportOutputView(ExportMasterView):
|
||||||
return app.get_report_handler()
|
return app.get_report_handler()
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
super(ReportOutputView, self).configure_grid(g)
|
super().configure_grid(g)
|
||||||
|
|
||||||
g.filters['report_name'].default_active = True
|
g.filters['report_name'].default_active = True
|
||||||
g.filters['report_name'].default_verb = 'contains'
|
g.filters['report_name'].default_verb = 'contains'
|
||||||
|
@ -254,7 +257,7 @@ class ReportOutputView(ExportMasterView):
|
||||||
g.set_link('filename')
|
g.set_link('filename')
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(ReportOutputView, self).configure_form(f)
|
super().configure_form(f)
|
||||||
|
|
||||||
# report_type
|
# report_type
|
||||||
f.set_renderer('report_type', self.render_report_type)
|
f.set_renderer('report_type', self.render_report_type)
|
||||||
|
@ -282,7 +285,7 @@ class ReportOutputView(ExportMasterView):
|
||||||
# add help button if report has a link
|
# add help button if report has a link
|
||||||
report = self.report_handler.get_report(type_key)
|
report = self.report_handler.get_report(type_key)
|
||||||
if report and report.help_url:
|
if report and report.help_url:
|
||||||
button = self.make_buefy_button("Help for this report",
|
button = self.make_button("Help for this report",
|
||||||
url=report.help_url,
|
url=report.help_url,
|
||||||
is_external=True,
|
is_external=True,
|
||||||
icon_left='question-circle')
|
icon_left='question-circle')
|
||||||
|
@ -311,7 +314,7 @@ class ReportOutputView(ExportMasterView):
|
||||||
labels={'key': "Name"},
|
labels={'key': "Name"},
|
||||||
)
|
)
|
||||||
return HTML.literal(
|
return HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='paramsData'))
|
g.render_table_element(data_prop='paramsData'))
|
||||||
|
|
||||||
def get_params_context(self, report):
|
def get_params_context(self, report):
|
||||||
params_data = []
|
params_data = []
|
||||||
|
@ -323,7 +326,7 @@ class ReportOutputView(ExportMasterView):
|
||||||
return params_data
|
return params_data
|
||||||
|
|
||||||
def template_kwargs_view(self, **kwargs):
|
def template_kwargs_view(self, **kwargs):
|
||||||
kwargs = super(ReportOutputView, self).template_kwargs_view(**kwargs)
|
kwargs = super().template_kwargs_view(**kwargs)
|
||||||
output = kwargs['instance']
|
output = kwargs['instance']
|
||||||
|
|
||||||
kwargs['params_data'] = self.get_params_context(output)
|
kwargs['params_data'] = self.get_params_context(output)
|
||||||
|
@ -339,7 +342,7 @@ class ReportOutputView(ExportMasterView):
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def template_kwargs_delete(self, **kwargs):
|
def template_kwargs_delete(self, **kwargs):
|
||||||
kwargs = super(ReportOutputView, self).template_kwargs_delete(**kwargs)
|
kwargs = super().template_kwargs_delete(**kwargs)
|
||||||
|
|
||||||
report = kwargs['instance']
|
report = kwargs['instance']
|
||||||
kwargs['params_data'] = self.get_params_context(report)
|
kwargs['params_data'] = self.get_params_context(report)
|
||||||
|
@ -496,7 +499,9 @@ class ReportOutputView(ExportMasterView):
|
||||||
resulting :class:`rattail:~rattail.db.model.reports.ReportOutput`
|
resulting :class:`rattail:~rattail.db.model.reports.ReportOutput`
|
||||||
object.
|
object.
|
||||||
"""
|
"""
|
||||||
session = RattailSession()
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
|
session = app.make_session()
|
||||||
user = session.get(model.User, user_uuid)
|
user = session.get(model.User, user_uuid)
|
||||||
try:
|
try:
|
||||||
output = self.report_handler.generate_output(session, report, params, user, progress=progress)
|
output = self.report_handler.generate_output(session, report, params, user, progress=progress)
|
||||||
|
@ -603,7 +608,7 @@ class ProblemReportView(MasterView):
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
super(ProblemReportView, self).__init__(request)
|
super().__init__(request)
|
||||||
|
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
self.problem_handler = app.get_problem_report_handler()
|
self.problem_handler = app.get_problem_report_handler()
|
||||||
|
@ -660,7 +665,7 @@ class ProblemReportView(MasterView):
|
||||||
return ProblemReportSchema()
|
return ProblemReportSchema()
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(ProblemReportView, self).configure_form(f)
|
super().configure_form(f)
|
||||||
|
|
||||||
# email_*
|
# email_*
|
||||||
if self.editing:
|
if self.editing:
|
||||||
|
@ -703,10 +708,10 @@ class ProblemReportView(MasterView):
|
||||||
g = self.get_grid_factory()('days', [],
|
g = self.get_grid_factory()('days', [],
|
||||||
columns=['weekday_name', 'enabled'],
|
columns=['weekday_name', 'enabled'],
|
||||||
labels={'weekday_name': "Weekday"})
|
labels={'weekday_name': "Weekday"})
|
||||||
return HTML.literal(g.render_buefy_table_element(data_prop='weekdaysData'))
|
return HTML.literal(g.render_table_element(data_prop='weekdaysData'))
|
||||||
|
|
||||||
def template_kwargs_view(self, **kwargs):
|
def template_kwargs_view(self, **kwargs):
|
||||||
kwargs = super(ProblemReportView, self).template_kwargs_view(**kwargs)
|
kwargs = super().template_kwargs_view(**kwargs)
|
||||||
report_info = kwargs['instance']
|
report_info = kwargs['instance']
|
||||||
|
|
||||||
data = []
|
data = []
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -29,7 +29,7 @@ import os
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
from openpyxl.styles import Font, PatternFill
|
from openpyxl.styles import Font, PatternFill
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db.model import Role
|
||||||
from rattail.db.auth import administrator_role, guest_role, authenticated_role
|
from rattail.db.auth import administrator_role, guest_role, authenticated_role
|
||||||
from rattail.excel import ExcelWriter
|
from rattail.excel import ExcelWriter
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ class RoleView(PrincipalMasterView):
|
||||||
"""
|
"""
|
||||||
Master view for the Role model.
|
Master view for the Role model.
|
||||||
"""
|
"""
|
||||||
model_class = model.Role
|
model_class = Role
|
||||||
has_versions = True
|
has_versions = True
|
||||||
touchable = True
|
touchable = True
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ class RoleView(PrincipalMasterView):
|
||||||
]
|
]
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
super(RoleView, self).configure_grid(g)
|
super().configure_grid(g)
|
||||||
|
|
||||||
# name
|
# name
|
||||||
g.filters['name'].default_active = True
|
g.filters['name'].default_active = True
|
||||||
|
@ -158,6 +158,7 @@ class RoleView(PrincipalMasterView):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def unique_name(self, node, value):
|
def unique_name(self, node, value):
|
||||||
|
model = self.model
|
||||||
query = self.Session.query(model.Role)\
|
query = self.Session.query(model.Role)\
|
||||||
.filter(model.Role.name == value)
|
.filter(model.Role.name == value)
|
||||||
if self.editing:
|
if self.editing:
|
||||||
|
@ -167,7 +168,7 @@ class RoleView(PrincipalMasterView):
|
||||||
raise colander.Invalid(node, "Name must be unique")
|
raise colander.Invalid(node, "Name must be unique")
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(RoleView, self).configure_form(f)
|
super().configure_form(f)
|
||||||
role = f.model_instance
|
role = f.model_instance
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
auth = app.get_auth_handler()
|
auth = app.get_auth_handler()
|
||||||
|
@ -265,7 +266,7 @@ class RoleView(PrincipalMasterView):
|
||||||
g.main_actions.append(self.make_action('edit', icon='edit'))
|
g.main_actions.append(self.make_action('edit', icon='edit'))
|
||||||
|
|
||||||
return HTML.literal(
|
return HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='usersData'))
|
g.render_table_element(data_prop='usersData'))
|
||||||
|
|
||||||
def get_available_permissions(self):
|
def get_available_permissions(self):
|
||||||
"""
|
"""
|
||||||
|
@ -322,7 +323,7 @@ class RoleView(PrincipalMasterView):
|
||||||
"""
|
"""
|
||||||
if data is None:
|
if data is None:
|
||||||
data = form.validated
|
data = form.validated
|
||||||
role = super(RoleView, self).objectify(form, data)
|
role = super().objectify(form, data)
|
||||||
self.update_permissions(role, data['permissions'])
|
self.update_permissions(role, data['permissions'])
|
||||||
return role
|
return role
|
||||||
|
|
||||||
|
@ -345,6 +346,7 @@ class RoleView(PrincipalMasterView):
|
||||||
auth.revoke_permission(role, pkey)
|
auth.revoke_permission(role, pkey)
|
||||||
|
|
||||||
def template_kwargs_view(self, **kwargs):
|
def template_kwargs_view(self, **kwargs):
|
||||||
|
model = self.model
|
||||||
role = kwargs['instance']
|
role = kwargs['instance']
|
||||||
if role.users:
|
if role.users:
|
||||||
users = sorted(role.users, key=lambda u: u.username)
|
users = sorted(role.users, key=lambda u: u.username)
|
||||||
|
@ -390,6 +392,7 @@ class RoleView(PrincipalMasterView):
|
||||||
|
|
||||||
def find_principals_with_permission(self, session, permission):
|
def find_principals_with_permission(self, session, permission):
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
auth = app.get_auth_handler()
|
auth = app.get_auth_handler()
|
||||||
|
|
||||||
# TODO: this should search Permission table instead, and work backward to Role?
|
# TODO: this should search Permission table instead, and work backward to Role?
|
||||||
|
@ -408,6 +411,7 @@ class RoleView(PrincipalMasterView):
|
||||||
Excel spreadsheet, and returns that file.
|
Excel spreadsheet, and returns that file.
|
||||||
"""
|
"""
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
auth = app.get_auth_handler()
|
auth = app.get_auth_handler()
|
||||||
|
|
||||||
roles = self.Session.query(model.Role)\
|
roles = self.Session.query(model.Role)\
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -32,8 +32,8 @@ from collections import OrderedDict
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from rattail.db import model
|
from rattail.db.model import Setting
|
||||||
from rattail.settings import Setting
|
from rattail.settings import Setting as AppSetting
|
||||||
from rattail.util import import_module_path
|
from rattail.util import import_module_path
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
|
@ -81,7 +81,7 @@ class AppInfoView(MasterView):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
super(AppInfoView, self).configure_grid(g)
|
super().configure_grid(g)
|
||||||
|
|
||||||
g.sorters['name'] = g.make_simple_sorter('name', foldcase=True)
|
g.sorters['name'] = g.make_simple_sorter('name', foldcase=True)
|
||||||
g.set_sort_defaults('name')
|
g.set_sort_defaults('name')
|
||||||
|
@ -94,12 +94,12 @@ class AppInfoView(MasterView):
|
||||||
g.set_searchable('editable_project_location')
|
g.set_searchable('editable_project_location')
|
||||||
|
|
||||||
def template_kwargs_index(self, **kwargs):
|
def template_kwargs_index(self, **kwargs):
|
||||||
kwargs = super(AppInfoView, self).template_kwargs_index(**kwargs)
|
kwargs = super().template_kwargs_index(**kwargs)
|
||||||
kwargs['configure_button_title'] = "Configure App"
|
kwargs['configure_button_title'] = "Configure App"
|
||||||
return kwargs
|
return kwargs
|
||||||
|
|
||||||
def configure_get_context(self, **kwargs):
|
def configure_get_context(self, **kwargs):
|
||||||
context = super(AppInfoView, self).configure_get_context(**kwargs)
|
context = super().configure_get_context(**kwargs)
|
||||||
|
|
||||||
weblibs = OrderedDict([
|
weblibs = OrderedDict([
|
||||||
('vue', "Vue"),
|
('vue', "Vue"),
|
||||||
|
@ -195,7 +195,7 @@ class SettingView(MasterView):
|
||||||
"""
|
"""
|
||||||
Master view for the settings model.
|
Master view for the settings model.
|
||||||
"""
|
"""
|
||||||
model_class = model.Setting
|
model_class = Setting
|
||||||
model_title = "Raw Setting"
|
model_title = "Raw Setting"
|
||||||
model_title_plural = "Raw Settings"
|
model_title_plural = "Raw Settings"
|
||||||
bulk_deletable = True
|
bulk_deletable = True
|
||||||
|
@ -207,18 +207,19 @@ class SettingView(MasterView):
|
||||||
]
|
]
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
super(SettingView, self).configure_grid(g)
|
super().configure_grid(g)
|
||||||
g.filters['name'].default_active = True
|
g.filters['name'].default_active = True
|
||||||
g.filters['name'].default_verb = 'contains'
|
g.filters['name'].default_verb = 'contains'
|
||||||
g.set_sort_defaults('name')
|
g.set_sort_defaults('name')
|
||||||
g.set_link('name')
|
g.set_link('name')
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(SettingView, self).configure_form(f)
|
super().configure_form(f)
|
||||||
if self.creating:
|
if self.creating:
|
||||||
f.set_validator('name', self.unique_name)
|
f.set_validator('name', self.unique_name)
|
||||||
|
|
||||||
def unique_name(self, node, value):
|
def unique_name(self, node, value):
|
||||||
|
model = self.model
|
||||||
setting = self.Session.get(model.Setting, value)
|
setting = self.Session.get(model.Setting, value)
|
||||||
if setting:
|
if setting:
|
||||||
raise colander.Invalid(node, "Setting name must be unique")
|
raise colander.Invalid(node, "Setting name must be unique")
|
||||||
|
@ -245,7 +246,7 @@ class SettingView(MasterView):
|
||||||
self.rattail_config.beaker_invalidate_setting(setting.name)
|
self.rattail_config.beaker_invalidate_setting(setting.name)
|
||||||
|
|
||||||
# otherwise delete like normal
|
# otherwise delete like normal
|
||||||
super(SettingView, self).delete_instance(setting)
|
super().delete_instance(setting)
|
||||||
|
|
||||||
|
|
||||||
# TODO: deprecate / remove this
|
# TODO: deprecate / remove this
|
||||||
|
@ -307,14 +308,14 @@ class AppSettingsView(View):
|
||||||
'settings': settings,
|
'settings': settings,
|
||||||
'config_options': config_options,
|
'config_options': config_options,
|
||||||
}
|
}
|
||||||
context['buefy_data'] = self.get_buefy_data(form, groups, settings)
|
context['settings_data'] = self.get_settings_data(form, groups, settings)
|
||||||
# TODO: this seems hacky, and probably only needed if theme changes?
|
# TODO: this seems hacky, and probably only needed if theme changes?
|
||||||
if current_group == '(All)':
|
if current_group == '(All)':
|
||||||
current_group = ''
|
current_group = ''
|
||||||
context['current_group'] = current_group
|
context['current_group'] = current_group
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_buefy_data(self, form, groups, settings):
|
def get_settings_data(self, form, groups, settings):
|
||||||
dform = form.make_deform_form()
|
dform = form.make_deform_form()
|
||||||
grouped = dict([(label, [])
|
grouped = dict([(label, [])
|
||||||
for label in groups])
|
for label in groups])
|
||||||
|
@ -407,7 +408,7 @@ class AppSettingsView(View):
|
||||||
module = import_module_path(module)
|
module = import_module_path(module)
|
||||||
for name in dir(module):
|
for name in dir(module):
|
||||||
obj = getattr(module, name)
|
obj = getattr(module, name)
|
||||||
if isinstance(obj, type) and issubclass(obj, Setting) and obj is not Setting:
|
if isinstance(obj, type) and issubclass(obj, AppSetting) and obj is not AppSetting:
|
||||||
if core_only and not obj.core:
|
if core_only and not obj.core:
|
||||||
continue
|
continue
|
||||||
# NOTE: we set this here, and reference it elsewhere
|
# NOTE: we set this here, and reference it elsewhere
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -28,9 +28,8 @@ import datetime
|
||||||
|
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from rattail import enum
|
from rattail.db import api
|
||||||
from rattail.db import model, api
|
from rattail.time import get_sunday
|
||||||
from rattail.time import localtime, make_utc, get_sunday
|
|
||||||
from rattail.util import hours_as_decimal
|
from rattail.util import hours_as_decimal
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
|
@ -83,6 +82,8 @@ class TimeSheetView(View):
|
||||||
"""
|
"""
|
||||||
Determine date/store/dept context from user's session and/or defaults.
|
Determine date/store/dept context from user's session and/or defaults.
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
date = None
|
date = None
|
||||||
date_key = 'timesheet.{}.date'.format(self.key)
|
date_key = 'timesheet.{}.date'.format(self.key)
|
||||||
if date_key in self.request.session:
|
if date_key in self.request.session:
|
||||||
|
@ -93,7 +94,7 @@ class TimeSheetView(View):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
if not date:
|
if not date:
|
||||||
date = localtime(self.rattail_config).date()
|
date = app.today()
|
||||||
|
|
||||||
store = None
|
store = None
|
||||||
department = None
|
department = None
|
||||||
|
@ -113,7 +114,7 @@ class TimeSheetView(View):
|
||||||
store = api.get_store(Session(), store)
|
store = api.get_store(Session(), store)
|
||||||
|
|
||||||
employees = Session.query(model.Employee)\
|
employees = Session.query(model.Employee)\
|
||||||
.filter(model.Employee.status == enum.EMPLOYEE_STATUS_CURRENT)
|
.filter(model.Employee.status == self.enum.EMPLOYEE_STATUS_CURRENT)
|
||||||
if store:
|
if store:
|
||||||
employees = employees.join(model.EmployeeStore)\
|
employees = employees.join(model.EmployeeStore)\
|
||||||
.filter(model.EmployeeStore.store == store)
|
.filter(model.EmployeeStore.store == store)
|
||||||
|
@ -132,6 +133,8 @@ class TimeSheetView(View):
|
||||||
"""
|
"""
|
||||||
Determine employee/date context from user's session and/or defaults
|
Determine employee/date context from user's session and/or defaults
|
||||||
"""
|
"""
|
||||||
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
date = None
|
date = None
|
||||||
date_key = 'timesheet.{}.employee.date'.format(self.key)
|
date_key = 'timesheet.{}.employee.date'.format(self.key)
|
||||||
if date_key in self.request.session:
|
if date_key in self.request.session:
|
||||||
|
@ -142,7 +145,7 @@ class TimeSheetView(View):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
if not date:
|
if not date:
|
||||||
date = localtime(self.rattail_config).date()
|
date = app.today()
|
||||||
|
|
||||||
employee = None
|
employee = None
|
||||||
employee_key = 'timesheet.{}.employee'.format(self.key)
|
employee_key = 'timesheet.{}.employee'.format(self.key)
|
||||||
|
@ -191,7 +194,7 @@ class TimeSheetView(View):
|
||||||
stores = self.get_stores()
|
stores = self.get_stores()
|
||||||
store_values = [(s.uuid, "{} - {}".format(s.id, s.name)) for s in stores]
|
store_values = [(s.uuid, "{} - {}".format(s.id, s.name)) for s in stores]
|
||||||
store_values.insert(0, ('', "(all)"))
|
store_values.insert(0, ('', "(all)"))
|
||||||
form.set_widget('store', forms.widgets.PlainSelectWidget(values=store_values))
|
form.set_widget('store', dfwidget.SelectWidget(values=store_values))
|
||||||
if context['store']:
|
if context['store']:
|
||||||
form.set_default('store', context['store'].uuid)
|
form.set_default('store', context['store'].uuid)
|
||||||
else:
|
else:
|
||||||
|
@ -203,7 +206,7 @@ class TimeSheetView(View):
|
||||||
departments = self.get_departments()
|
departments = self.get_departments()
|
||||||
department_values = [(d.uuid, d.name) for d in departments]
|
department_values = [(d.uuid, d.name) for d in departments]
|
||||||
department_values.insert(0, ('', "(all)"))
|
department_values.insert(0, ('', "(all)"))
|
||||||
form.set_widget('department', forms.widgets.PlainSelectWidget(values=department_values))
|
form.set_widget('department', dfwidget.SelectWidget(values=department_values))
|
||||||
if context['department']:
|
if context['department']:
|
||||||
form.set_default('department', context['department'].uuid)
|
form.set_default('department', context['department'].uuid)
|
||||||
else:
|
else:
|
||||||
|
@ -292,6 +295,7 @@ class TimeSheetView(View):
|
||||||
self.request.session['timesheet.{}.{}'.format(mainkey, key)] = value
|
self.request.session['timesheet.{}.{}'.format(mainkey, key)] = value
|
||||||
|
|
||||||
def get_stores(self):
|
def get_stores(self):
|
||||||
|
model = self.model
|
||||||
return Session.query(model.Store).order_by(model.Store.id).all()
|
return Session.query(model.Store).order_by(model.Store.id).all()
|
||||||
|
|
||||||
def get_store_options(self, stores):
|
def get_store_options(self, stores):
|
||||||
|
@ -299,6 +303,7 @@ class TimeSheetView(View):
|
||||||
return tags.Options(options, prompt="(all)")
|
return tags.Options(options, prompt="(all)")
|
||||||
|
|
||||||
def get_departments(self):
|
def get_departments(self):
|
||||||
|
model = self.model
|
||||||
return Session.query(model.Department).order_by(model.Department.name).all()
|
return Session.query(model.Department).order_by(model.Department.name).all()
|
||||||
|
|
||||||
def get_department_options(self, departments):
|
def get_department_options(self, departments):
|
||||||
|
@ -402,6 +407,7 @@ class TimeSheetView(View):
|
||||||
the given params. The cached shift data is attached to each employee.
|
the given params. The cached shift data is attached to each employee.
|
||||||
"""
|
"""
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
|
model = self.model
|
||||||
|
|
||||||
# TODO: a bit hacky, this? display hours as HH:MM by default, but
|
# TODO: a bit hacky, this? display hours as HH:MM by default, but
|
||||||
# check config in order to display as HH.HH for certain users
|
# check config in order to display as HH.HH for certain users
|
||||||
|
@ -413,19 +419,19 @@ class TimeSheetView(View):
|
||||||
hours_style = 'pretty'
|
hours_style = 'pretty'
|
||||||
|
|
||||||
shift_type = 'scheduled' if cls is model.ScheduledShift else 'worked'
|
shift_type = 'scheduled' if cls is model.ScheduledShift else 'worked'
|
||||||
min_time = localtime(self.rattail_config, datetime.datetime.combine(weekdays[0], datetime.time(0)))
|
min_time = app.localtime(datetime.datetime.combine(weekdays[0], datetime.time(0)))
|
||||||
max_time = localtime(self.rattail_config, datetime.datetime.combine(weekdays[-1] + datetime.timedelta(days=1), datetime.time(0)))
|
max_time = app.localtime(datetime.datetime.combine(weekdays[-1] + datetime.timedelta(days=1), datetime.time(0)))
|
||||||
shifts = Session.query(cls)\
|
shifts = Session.query(cls)\
|
||||||
.filter(cls.employee_uuid.in_([e.uuid for e in employees]))\
|
.filter(cls.employee_uuid.in_([e.uuid for e in employees]))\
|
||||||
.filter(sa.or_(
|
.filter(sa.or_(
|
||||||
sa.and_(
|
sa.and_(
|
||||||
cls.start_time >= make_utc(min_time),
|
cls.start_time >= app.make_utc(min_time),
|
||||||
cls.start_time < make_utc(max_time),
|
cls.start_time < app.make_utc(max_time),
|
||||||
),
|
),
|
||||||
sa.and_(
|
sa.and_(
|
||||||
cls.start_time == None,
|
cls.start_time == None,
|
||||||
cls.end_time >= make_utc(min_time),
|
cls.end_time >= app.make_utc(min_time),
|
||||||
cls.end_time < make_utc(max_time),
|
cls.end_time < app.make_utc(max_time),
|
||||||
)))\
|
)))\
|
||||||
.all()
|
.all()
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -80,7 +80,7 @@ class TableView(MasterView):
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
super(TableView, self).__init__(request)
|
super().__init__(request)
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
self.db_handler = app.get_db_handler()
|
self.db_handler = app.get_db_handler()
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ class TableView(MasterView):
|
||||||
for row in result]
|
for row in result]
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
super(TableView, self).configure_grid(g)
|
super().configure_grid(g)
|
||||||
|
|
||||||
# table_name
|
# table_name
|
||||||
g.sorters['table_name'] = g.make_simple_sorter('table_name', foldcase=True)
|
g.sorters['table_name'] = g.make_simple_sorter('table_name', foldcase=True)
|
||||||
|
@ -114,7 +114,7 @@ class TableView(MasterView):
|
||||||
g.sorters['row_count'] = g.make_simple_sorter('row_count')
|
g.sorters['row_count'] = g.make_simple_sorter('row_count')
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(TableView, self).configure_form(f)
|
super().configure_form(f)
|
||||||
|
|
||||||
# TODO: should render this instead, by inspecting table
|
# TODO: should render this instead, by inspecting table
|
||||||
if not self.creating:
|
if not self.creating:
|
||||||
|
@ -169,7 +169,7 @@ class TableView(MasterView):
|
||||||
return TableSchema()
|
return TableSchema()
|
||||||
|
|
||||||
def get_xref_buttons(self, table):
|
def get_xref_buttons(self, table):
|
||||||
buttons = super(TableView, self).get_xref_buttons(table)
|
buttons = super().get_xref_buttons(table)
|
||||||
|
|
||||||
if table.get('model_name'):
|
if table.get('model_name'):
|
||||||
all_views = self.request.registry.settings['tailbone_model_views']
|
all_views = self.request.registry.settings['tailbone_model_views']
|
||||||
|
@ -182,7 +182,7 @@ class TableView(MasterView):
|
||||||
if self.request.has_perm('model_views.create'):
|
if self.request.has_perm('model_views.create'):
|
||||||
url = self.request.route_url('model_views.create',
|
url = self.request.route_url('model_views.create',
|
||||||
_query={'model_name': table['model_name']})
|
_query={'model_name': table['model_name']})
|
||||||
buttons.append(self.make_buefy_button("New View",
|
buttons.append(self.make_button("New View",
|
||||||
is_primary=True,
|
is_primary=True,
|
||||||
url=url,
|
url=url,
|
||||||
icon_left='plus'))
|
icon_left='plus'))
|
||||||
|
@ -190,7 +190,7 @@ class TableView(MasterView):
|
||||||
return buttons
|
return buttons
|
||||||
|
|
||||||
def template_kwargs_create(self, **kwargs):
|
def template_kwargs_create(self, **kwargs):
|
||||||
kwargs = super(TableView, self).template_kwargs_create(**kwargs)
|
kwargs = super().template_kwargs_create(**kwargs)
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
model = self.model
|
model = self.model
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ class TableView(MasterView):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def configure_row_grid(self, g):
|
def configure_row_grid(self, g):
|
||||||
super(TableView, self).configure_row_grid(g)
|
super().configure_row_grid(g)
|
||||||
|
|
||||||
g.sorters['sequence'] = g.make_simple_sorter('sequence')
|
g.sorters['sequence'] = g.make_simple_sorter('sequence')
|
||||||
g.set_sort_defaults('sequence')
|
g.set_sort_defaults('sequence')
|
||||||
|
@ -419,7 +419,7 @@ class TablesView(TableView):
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
warnings.warn("TablesView is deprecated; please use TableView instead",
|
warnings.warn("TablesView is deprecated; please use TableView instead",
|
||||||
DeprecationWarning, stacklevel=2)
|
DeprecationWarning, stacklevel=2)
|
||||||
super(TablesView, self).__init__(request)
|
super().__init__(request)
|
||||||
|
|
||||||
|
|
||||||
class TableSchema(colander.Schema):
|
class TableSchema(colander.Schema):
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -98,4 +98,4 @@ class MasterView(views.MasterView):
|
||||||
main_actions=actions,
|
main_actions=actions,
|
||||||
)
|
)
|
||||||
return HTML.literal(
|
return HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='probesData'))
|
g.render_table_element(data_prop='probesData'))
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -202,7 +202,7 @@ class TransactionView(MasterView):
|
||||||
return 'warning'
|
return 'warning'
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(TransactionView, self).configure_form(f)
|
super().configure_form(f)
|
||||||
|
|
||||||
# system
|
# system
|
||||||
f.set_enum('system', self.enum.TRAINWRECK_SYSTEM)
|
f.set_enum('system', self.enum.TRAINWRECK_SYSTEM)
|
||||||
|
@ -240,10 +240,10 @@ class TransactionView(MasterView):
|
||||||
request=self.request)
|
request=self.request)
|
||||||
|
|
||||||
return HTML.literal(
|
return HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='custorderXrefMarkersData'))
|
g.render_table_element(data_prop='custorderXrefMarkersData'))
|
||||||
|
|
||||||
def template_kwargs_view(self, **kwargs):
|
def template_kwargs_view(self, **kwargs):
|
||||||
kwargs = super(TransactionView, self).template_kwargs_view(**kwargs)
|
kwargs = super().template_kwargs_view(**kwargs)
|
||||||
|
|
||||||
form = kwargs['form']
|
form = kwargs['form']
|
||||||
if 'custorder_xref_markers' in form:
|
if 'custorder_xref_markers' in form:
|
||||||
|
@ -266,7 +266,7 @@ class TransactionView(MasterView):
|
||||||
return item.transaction
|
return item.transaction
|
||||||
|
|
||||||
def configure_row_grid(self, g):
|
def configure_row_grid(self, g):
|
||||||
super(TransactionView, self).configure_row_grid(g)
|
super().configure_row_grid(g)
|
||||||
g.set_sort_defaults('sequence')
|
g.set_sort_defaults('sequence')
|
||||||
|
|
||||||
g.set_type('unit_quantity', 'quantity')
|
g.set_type('unit_quantity', 'quantity')
|
||||||
|
@ -286,7 +286,7 @@ class TransactionView(MasterView):
|
||||||
return "Trainwreck Line Item"
|
return "Trainwreck Line Item"
|
||||||
|
|
||||||
def configure_row_form(self, f):
|
def configure_row_form(self, f):
|
||||||
super(TransactionView, self).configure_row_form(f)
|
super().configure_row_form(f)
|
||||||
|
|
||||||
# transaction
|
# transaction
|
||||||
f.set_renderer('transaction', self.render_transaction)
|
f.set_renderer('transaction', self.render_transaction)
|
||||||
|
@ -325,7 +325,7 @@ class TransactionView(MasterView):
|
||||||
request=self.request)
|
request=self.request)
|
||||||
|
|
||||||
return HTML.literal(
|
return HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='discountsData'))
|
g.render_table_element(data_prop='discountsData'))
|
||||||
|
|
||||||
def template_kwargs_view_row(self, **kwargs):
|
def template_kwargs_view_row(self, **kwargs):
|
||||||
form = kwargs['form']
|
form = kwargs['form']
|
||||||
|
@ -401,7 +401,7 @@ class TransactionView(MasterView):
|
||||||
]
|
]
|
||||||
|
|
||||||
def configure_get_context(self):
|
def configure_get_context(self):
|
||||||
context = super(TransactionView, self).configure_get_context()
|
context = super().configure_get_context()
|
||||||
|
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
trainwreck_handler = app.get_trainwreck_handler()
|
trainwreck_handler = app.get_trainwreck_handler()
|
||||||
|
@ -415,7 +415,7 @@ class TransactionView(MasterView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def configure_gather_settings(self, data):
|
def configure_gather_settings(self, data):
|
||||||
settings = super(TransactionView, self).configure_gather_settings(data)
|
settings = super().configure_gather_settings(data)
|
||||||
|
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
trainwreck_handler = app.get_trainwreck_handler()
|
trainwreck_handler = app.get_trainwreck_handler()
|
||||||
|
@ -432,7 +432,7 @@ class TransactionView(MasterView):
|
||||||
return settings
|
return settings
|
||||||
|
|
||||||
def configure_remove_settings(self):
|
def configure_remove_settings(self):
|
||||||
super(TransactionView, self).configure_remove_settings()
|
super().configure_remove_settings()
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
|
|
||||||
names = [
|
names = [
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2023 Lance Edgar
|
# Copyright © 2010-2024 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -84,7 +84,7 @@ class UserView(PrincipalMasterView):
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, request):
|
def __init__(self, request):
|
||||||
super(UserView, self).__init__(request)
|
super().__init__(request)
|
||||||
app = self.get_rattail_app()
|
app = self.get_rattail_app()
|
||||||
|
|
||||||
# always get a reference to the auth/merge handler
|
# always get a reference to the auth/merge handler
|
||||||
|
@ -92,7 +92,7 @@ class UserView(PrincipalMasterView):
|
||||||
self.merge_handler = self.auth_handler
|
self.merge_handler = self.auth_handler
|
||||||
|
|
||||||
def query(self, session):
|
def query(self, session):
|
||||||
query = super(UserView, self).query(session)
|
query = super().query(session)
|
||||||
model = self.model
|
model = self.model
|
||||||
|
|
||||||
# bring in the related Person(s)
|
# bring in the related Person(s)
|
||||||
|
@ -102,7 +102,7 @@ class UserView(PrincipalMasterView):
|
||||||
return query
|
return query
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
super(UserView, self).configure_grid(g)
|
super().configure_grid(g)
|
||||||
model = self.model
|
model = self.model
|
||||||
|
|
||||||
del g.filters['salt']
|
del g.filters['salt']
|
||||||
|
@ -177,7 +177,7 @@ class UserView(PrincipalMasterView):
|
||||||
raise colander.Invalid(node, "Person not found (you must *select* a record)")
|
raise colander.Invalid(node, "Person not found (you must *select* a record)")
|
||||||
|
|
||||||
def configure_form(self, f):
|
def configure_form(self, f):
|
||||||
super(UserView, self).configure_form(f)
|
super().configure_form(f)
|
||||||
model = self.model
|
model = self.model
|
||||||
user = f.model_instance
|
user = f.model_instance
|
||||||
|
|
||||||
|
@ -290,12 +290,12 @@ class UserView(PrincipalMasterView):
|
||||||
self.make_action('delete', icon='trash',
|
self.make_action('delete', icon='trash',
|
||||||
click_handler="$emit('api-token-delete', props.row)")])
|
click_handler="$emit('api-token-delete', props.row)")])
|
||||||
|
|
||||||
button = self.make_buefy_button("New", is_primary=True,
|
button = self.make_button("New", is_primary=True,
|
||||||
icon_left='plus',
|
icon_left='plus',
|
||||||
**{'@click': "$emit('api-new-token')"})
|
**{'@click': "$emit('api-new-token')"})
|
||||||
|
|
||||||
table = HTML.literal(
|
table = HTML.literal(
|
||||||
g.render_buefy_table_element(data_prop='apiTokens'))
|
g.render_table_element(data_prop='apiTokens'))
|
||||||
|
|
||||||
return HTML.tag('div', c=[button, table])
|
return HTML.tag('div', c=[button, table])
|
||||||
|
|
||||||
|
@ -329,7 +329,7 @@ class UserView(PrincipalMasterView):
|
||||||
'tokens': self.get_api_tokens(user)}
|
'tokens': self.get_api_tokens(user)}
|
||||||
|
|
||||||
def template_kwargs_view(self, **kwargs):
|
def template_kwargs_view(self, **kwargs):
|
||||||
kwargs = super(UserView, self).template_kwargs_view(**kwargs)
|
kwargs = super().template_kwargs_view(**kwargs)
|
||||||
user = kwargs['instance']
|
user = kwargs['instance']
|
||||||
|
|
||||||
kwargs['api_tokens_data'] = self.get_api_tokens(user)
|
kwargs['api_tokens_data'] = self.get_api_tokens(user)
|
||||||
|
@ -377,7 +377,7 @@ class UserView(PrincipalMasterView):
|
||||||
# create/update user as per normal
|
# create/update user as per normal
|
||||||
if data is None:
|
if data is None:
|
||||||
data = form.validated
|
data = form.validated
|
||||||
user = super(UserView, self).objectify(form, data)
|
user = super().objectify(form, data)
|
||||||
|
|
||||||
# create/update person as needed
|
# create/update person as needed
|
||||||
names = {}
|
names = {}
|
||||||
|
@ -487,7 +487,7 @@ class UserView(PrincipalMasterView):
|
||||||
.filter(model.UserEvent.user == user)
|
.filter(model.UserEvent.user == user)
|
||||||
|
|
||||||
def configure_row_grid(self, g):
|
def configure_row_grid(self, g):
|
||||||
super(UserView, self).configure_row_grid(g)
|
super().configure_row_grid(g)
|
||||||
g.width = 'half'
|
g.width = 'half'
|
||||||
g.filterable = False
|
g.filterable = False
|
||||||
g.set_sort_defaults('occurred', 'desc')
|
g.set_sort_defaults('occurred', 'desc')
|
||||||
|
@ -588,7 +588,7 @@ class UserView(PrincipalMasterView):
|
||||||
'themes.style.{}'.format(name))
|
'themes.style.{}'.format(name))
|
||||||
if css:
|
if css:
|
||||||
options.append({'value': css, 'label': name})
|
options.append({'value': css, 'label': name})
|
||||||
context['buefy_css_options'] = options
|
context['theme_style_options'] = options
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@ -699,12 +699,12 @@ class UserEventView(MasterView):
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_data(self, session=None):
|
def get_data(self, session=None):
|
||||||
query = super(UserEventView, self).get_data(session=session)
|
query = super().get_data(session=session)
|
||||||
model = self.model
|
model = self.model
|
||||||
return query.join(model.User)
|
return query.join(model.User)
|
||||||
|
|
||||||
def configure_grid(self, g):
|
def configure_grid(self, g):
|
||||||
super(UserEventView, self).configure_grid(g)
|
super().configure_grid(g)
|
||||||
model = self.model
|
model = self.model
|
||||||
g.set_joiner('person', lambda q: q.outerjoin(model.Person))
|
g.set_joiner('person', lambda q: q.outerjoin(model.Person))
|
||||||
g.set_sorter('user', model.User.username)
|
g.set_sorter('user', model.User.username)
|
||||||
|
|
Loading…
Reference in a new issue