Misc. improvements for ordering batches, purchases

also we now show handler's description when executing batch
This commit is contained in:
Lance Edgar 2021-01-30 13:17:08 -06:00
parent e1e3301fc1
commit fac00e6ecd
8 changed files with 77 additions and 34 deletions

View file

@ -211,6 +211,12 @@
</header> </header>
<section class="modal-card-body"> <section class="modal-card-body">
<p class="block has-text-weight-bold">
What will actually happen when this batch is executed?
</p>
<p class="block">
${handler.describe_execution(batch) or "TODO: handler does not provide a description for this batch"}
</p>
<${execute_form.component} ref="executeBatchForm"></${execute_form.component}> <${execute_form.component} ref="executeBatchForm"></${execute_form.component}>
</section> </section>

View file

@ -1,6 +1,7 @@
## -*- coding: utf-8; -*- ## -*- coding: utf-8; -*-
<script type="text/x-template" id="${form.component}-template"> <script type="text/x-template" id="${form.component}-template">
<div> <div>
% if not form.readonly: % if not form.readonly:
${h.form(form.action_url, id=dform.formid, method='post', enctype='multipart/form-data', **form_kwargs)} ${h.form(form.action_url, id=dform.formid, method='post', enctype='multipart/form-data', **form_kwargs)}
@ -18,19 +19,24 @@
% elif field in dform: % elif field in dform:
<% field = dform[field] %> <% field = dform[field] %>
<b-field horizontal % if form.field_visible(field.name):
label="${form.get_label(field.name)}" <b-field horizontal
## TODO: is this class="file" really needed? label="${form.get_label(field.name)}"
% if isinstance(field.schema.typ, deform.FileData): ## TODO: is this class="file" really needed?
class="file" % if isinstance(field.schema.typ, deform.FileData):
% endif class="file"
% if field.error: % endif
type="is-danger" % if field.error:
:message='${form.messages_json(field.error.messages())|n}' type="is-danger"
% endif :message='${form.messages_json(field.error.messages())|n}'
> % endif
${field.serialize(use_buefy=True)|n} >
</b-field> ${field.serialize(use_buefy=True)|n}
</b-field>
% else:
## hidden field
${field.serialize()|n}
% endif
% endif % endif
% endfor % endfor

View file

@ -3,6 +3,7 @@
<%def name="extra_javascript()"> <%def name="extra_javascript()">
${parent.extra_javascript()} ${parent.extra_javascript()}
% if not use_buefy:
${self.func_show_mode()} ${self.func_show_mode()}
<script type="text/javascript"> <script type="text/javascript">
@ -56,6 +57,7 @@
}); });
</script> </script>
% endif
</%def> </%def>
<%def name="func_show_mode()"> <%def name="func_show_mode()">

View file

@ -3,6 +3,7 @@
<%def name="extra_javascript()"> <%def name="extra_javascript()">
${parent.extra_javascript()} ${parent.extra_javascript()}
% if not use_buefy:
${self.func_show_batch_type()} ${self.func_show_batch_type()}
<script type="text/javascript"> <script type="text/javascript">
@ -26,6 +27,7 @@
}); });
</script> </script>
% endif
</%def> </%def>
<%def name="func_show_batch_type()"> <%def name="func_show_batch_type()">

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2018 Lance Edgar # Copyright © 2010-2021 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -48,8 +48,12 @@ class PurchaseView(MasterView):
model_row_class = model.PurchaseItem model_row_class = model.PurchaseItem
row_model_title = 'Purchase Item' row_model_title = 'Purchase Item'
labels = {
'id': "ID",
}
grid_columns = [ grid_columns = [
'store', 'id',
'vendor', 'vendor',
'department', 'department',
'buyer', 'buyer',
@ -62,6 +66,7 @@ class PurchaseView(MasterView):
] ]
form_fields = [ form_fields = [
'id',
'store', 'store',
'vendor', 'vendor',
'department', 'department',
@ -162,6 +167,9 @@ class PurchaseView(MasterView):
default_active=True, default_verb='contains') default_active=True, default_verb='contains')
g.sorters['buyer'] = g.make_sorter(model.Person.display_name) g.sorters['buyer'] = g.make_sorter(model.Person.display_name)
# id
g.set_renderer('id', self.render_id_str)
# date_ordered # date_ordered
g.filters['date_ordered'].default_active = True g.filters['date_ordered'].default_active = True
g.filters['date_ordered'].default_verb = 'equal' g.filters['date_ordered'].default_verb = 'equal'
@ -182,6 +190,9 @@ class PurchaseView(MasterView):
g.set_type('po_total', 'currency') g.set_type('po_total', 'currency')
g.set_type('invoice_total', 'currency') g.set_type('invoice_total', 'currency')
g.set_label('invoice_number', "Invoice No.") g.set_label('invoice_number', "Invoice No.")
g.set_link('id')
g.set_link('vendor')
g.set_link('date_ordered') g.set_link('date_ordered')
g.set_link('po_total') g.set_link('po_total')
g.set_link('date_received') g.set_link('date_received')
@ -190,6 +201,8 @@ class PurchaseView(MasterView):
def configure_form(self, f): def configure_form(self, f):
super(PurchaseView, self).configure_form(f) super(PurchaseView, self).configure_form(f)
f.set_renderer('id', self.render_id_str)
f.set_renderer('store', self.render_store) f.set_renderer('store', self.render_store)
f.set_renderer('vendor', self.render_vendor) f.set_renderer('vendor', self.render_vendor)
f.set_renderer('department', self.render_department) f.set_renderer('department', self.render_department)
@ -220,14 +233,6 @@ class PurchaseView(MasterView):
url = self.request.route_url('stores.view', uuid=store.uuid) url = self.request.route_url('stores.view', uuid=store.uuid)
return tags.link_to(text, url) return tags.link_to(text, url)
def render_vendor(self, purchase, field):
vendor = purchase.vendor
if not vendor:
return ""
text = "({}) {}".format(vendor.id, vendor.name)
url = self.request.route_url('vendors.view', uuid=vendor.uuid)
return tags.link_to(text, url)
def render_department(self, purchase, field): def render_department(self, purchase, field):
department = purchase.department department = purchase.department
if not department: if not department:
@ -316,6 +321,17 @@ class PurchaseView(MasterView):
def configure_row_form(self, f): def configure_row_form(self, f):
super(PurchaseView, self).configure_row_form(f) super(PurchaseView, self).configure_row_form(f)
# quantity fields
f.set_type('case_quantity', 'quantity')
f.set_type('cases_ordered', 'quantity')
f.set_type('units_ordered', 'quantity')
f.set_type('cases_received', 'quantity')
f.set_type('units_received', 'quantity')
f.set_type('cases_damaged', 'quantity')
f.set_type('units_damaged', 'quantity')
f.set_type('cases_expired', 'quantity')
f.set_type('units_expired', 'quantity')
# currency fields # currency fields
f.set_type('po_unit_cost', 'currency') f.set_type('po_unit_cost', 'currency')
f.set_type('po_total', 'currency') f.set_type('po_total', 'currency')

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2019 Lance Edgar # Copyright © 2010-2021 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -180,11 +180,19 @@ class PurchaseCreditView(MasterView):
@classmethod @classmethod
def defaults(cls, config): def defaults(cls, config):
cls._purchase_credit_defaults(config)
cls._defaults(config)
@classmethod
def _purchase_credit_defaults(cls, config):
route_prefix = cls.get_route_prefix() route_prefix = cls.get_route_prefix()
url_prefix = cls.get_url_prefix() url_prefix = cls.get_url_prefix()
permission_prefix = cls.get_permission_prefix() permission_prefix = cls.get_permission_prefix()
model_title_plural = cls.get_model_title_plural() model_title_plural = cls.get_model_title_plural()
# fix perm group name
config.add_tailbone_permission_group(permission_prefix, model_title_plural, overwrite=False)
# change status # change status
config.add_tailbone_permission(permission_prefix, '{}.change_status'.format(permission_prefix), config.add_tailbone_permission(permission_prefix, '{}.change_status'.format(permission_prefix),
"Change status for {}".format(model_title_plural)) "Change status for {}".format(model_title_plural))
@ -192,8 +200,6 @@ class PurchaseCreditView(MasterView):
config.add_view(cls, attr='change_status', route_name='{}.change_status'.format(route_prefix), config.add_view(cls, attr='change_status', route_name='{}.change_status'.format(route_prefix),
permission='{}.change_status'.format(permission_prefix)) permission='{}.change_status'.format(permission_prefix))
cls._defaults(config)
def includeme(config): def includeme(config):
PurchaseCreditView.defaults(config) PurchaseCreditView.defaults(config)

View file

@ -281,9 +281,9 @@ class PurchasingBatchView(BatchMasterView):
if self.creating: if self.creating:
f.replace('vendor', 'vendor_uuid') f.replace('vendor', 'vendor_uuid')
f.set_label('vendor_uuid', "Vendor") f.set_label('vendor_uuid', "Vendor")
widget_type = self.rattail_config.get('tailbone', 'default_widget.vendor', use_autocomplete = self.rattail_config.getbool(
default='autocomplete') 'rattail', 'vendor.use_autocomplete', default=True)
if widget_type == 'autocomplete': if use_autocomplete:
vendor_display = "" vendor_display = ""
if self.request.method == 'POST': if self.request.method == 'POST':
if self.request.POST.get('vendor_uuid'): if self.request.POST.get('vendor_uuid'):
@ -293,14 +293,12 @@ class PurchasingBatchView(BatchMasterView):
vendors_url = self.request.route_url('vendors.autocomplete') vendors_url = self.request.route_url('vendors.autocomplete')
f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget( f.set_widget('vendor_uuid', forms.widgets.JQueryAutocompleteWidget(
field_display=vendor_display, service_url=vendors_url)) field_display=vendor_display, service_url=vendors_url))
elif widget_type == 'dropdown': else:
vendors = self.Session.query(model.Vendor)\ vendors = self.Session.query(model.Vendor)\
.order_by(model.Vendor.id) .order_by(model.Vendor.id)
vendor_values = [(vendor.uuid, "({}) {}".format(vendor.id, vendor.name)) vendor_values = [(vendor.uuid, "({}) {}".format(vendor.id, vendor.name))
for vendor in vendors] for vendor in vendors]
f.set_widget('vendor_uuid', dfwidget.SelectWidget(values=vendor_values)) f.set_widget('vendor_uuid', dfwidget.SelectWidget(values=vendor_values))
else:
raise NotImplementedError("Unsupported vendor widget type: {}".format(widget_type))
elif self.editing: elif self.editing:
f.set_readonly('vendor') f.set_readonly('vendor')

View file

@ -2,7 +2,7 @@
################################################################################ ################################################################################
# #
# Rattail -- Retail Software Framework # Rattail -- Retail Software Framework
# Copyright © 2010-2020 Lance Edgar # Copyright © 2010-2021 Lance Edgar
# #
# This file is part of Rattail. # This file is part of Rattail.
# #
@ -155,9 +155,11 @@ class OrderingBatchView(PurchasingBatchView):
def configure_form(self, f): def configure_form(self, f):
super(OrderingBatchView, self).configure_form(f) super(OrderingBatchView, self).configure_form(f)
batch = f.model_instance
# purchase # purchase
f.remove_field('purchase') if self.creating or not batch.executed or not batch.purchase:
f.remove_field('purchase')
def get_batch_kwargs(self, batch, mobile=False): def get_batch_kwargs(self, batch, mobile=False):
kwargs = super(OrderingBatchView, self).get_batch_kwargs(batch, mobile=mobile) kwargs = super(OrderingBatchView, self).get_batch_kwargs(batch, mobile=mobile)
@ -468,6 +470,11 @@ class OrderingBatchView(PurchasingBatchView):
return self.file_response(path) return self.file_response(path)
def get_execute_success_url(self, batch, result, **kwargs):
if isinstance(result, model.Purchase):
return self.request.route_url('purchases.view', uuid=result.uuid)
return super(OrderingBatchView, self).get_execute_success_url(batch, result, **kwargs)
@classmethod @classmethod
def _ordering_defaults(cls, config): def _ordering_defaults(cls, config):
route_prefix = cls.get_route_prefix() route_prefix = cls.get_route_prefix()