Add basic "price needs confirmation" support for custorder

This commit is contained in:
Lance Edgar 2021-10-18 18:28:28 -05:00
parent 93b752f436
commit 8b044dbb22
4 changed files with 214 additions and 11 deletions

View file

@ -98,6 +98,7 @@ class CustomerOrderItemView(MasterView):
'case_quantity',
'unit_price',
'total_price',
'price_needs_confirmation',
'paid_amount',
'status_code',
'notes',
@ -135,7 +136,7 @@ class CustomerOrderItemView(MasterView):
g.set_renderer('person', self.render_person_text)
g.set_renderer('order_created', self.render_order_created)
g.set_enum('status_code', self.enum.CUSTORDER_ITEM_STATUS)
g.set_renderer('status_code', self.render_status_code_column)
g.set_label('person', "Person Name")
g.set_label('product_brand', "Brand")
@ -160,6 +161,13 @@ class CustomerOrderItemView(MasterView):
value = localtime(self.rattail_config, item.order.created, from_utc=True)
return raw_datetime(self.rattail_config, value)
def render_status_code_column(self, item, field):
text = self.enum.CUSTORDER_ITEM_STATUS.get(item.status_code,
six.text_type(item.status_code))
if item.status_text:
return HTML.tag('span', title=item.status_text, c=[text])
return text
def configure_form(self, f):
super(CustomerOrderItemView, self).configure_form(f)
use_buefy = self.get_use_buefy()
@ -178,12 +186,12 @@ class CustomerOrderItemView(MasterView):
f.set_type('cases_ordered', 'quantity')
f.set_type('units_ordered', 'quantity')
f.set_type('order_quantity', 'quantity')
f.set_enum('order_uom', self.enum.UNIT_OF_MEASURE)
# currency fields
f.set_type('unit_price', 'currency')
f.set_type('total_price', 'currency')
# price fields
f.set_renderer('unit_price', self.render_price_with_confirmation)
f.set_renderer('total_price', self.render_price_with_confirmation)
f.set_renderer('price_needs_confirmation', self.render_price_needs_confirmation)
f.set_type('paid_amount', 'currency')
# person
@ -198,9 +206,37 @@ class CustomerOrderItemView(MasterView):
else:
f.remove('notes')
def render_price_with_confirmation(self, item, field):
price = getattr(item, field)
app = self.get_rattail_app()
text = app.render_currency(price)
if item.price_needs_confirmation:
return HTML.tag('span', class_='has-background-warning',
c=[text])
return text
def render_price_needs_confirmation(self, item, field):
value = item.price_needs_confirmation
text = "Yes" if value else "No"
items = [text]
if value and self.has_perm('confirm_price'):
button = HTML.tag('b-button', type='is-primary', c="Confirm Price",
style='margin-left: 1rem;',
icon_pack='fas', icon_left='check',
**{'@click': "$emit('confirm-price')"})
items.append(button)
left = HTML.tag('div', class_='level-left', c=items)
outer = HTML.tag('div', class_='level', c=[left])
return outer
def render_status_code(self, item, field):
use_buefy = self.get_use_buefy()
text = self.enum.CUSTORDER_ITEM_STATUS[item.status_code]
if item.status_text:
text = "{} ({})".format(text, item.status_text)
items = [HTML.tag('span', c=[text])]
if use_buefy and self.has_perm('change_status'):
@ -298,6 +334,32 @@ class CustomerOrderItemView(MasterView):
})
return notes
def confirm_price(self):
"""
View for confirming price of an order item.
"""
item = self.get_instance()
redirect = self.redirect(self.get_action_url('view', item))
# locate user responsible for change
user = self.request.user
# grab user-provided note to attach to event
note = self.request.POST.get('note')
# declare item no longer in need of price confirmation
item.price_needs_confirmation = False
item.add_event(self.enum.CUSTORDER_ITEM_EVENT_PRICE_CONFIRMED,
user, note=note)
# advance item to next status
if item.status_code == self.enum.CUSTORDER_ITEM_STATUS_INITIATED:
item.status_code = self.enum.CUSTORDER_ITEM_STATUS_READY
item.status_text = "price has been confirmed"
self.request.session.flash("Price has been confirmed.")
return redirect
def change_status(self):
"""
View for changing status of one or more order items.
@ -342,6 +404,9 @@ class CustomerOrderItemView(MasterView):
# change status
item.status_code = new_status_code
# nb. must blank this out, b/c user cannot specify new
# text and the old text no longer applies
item.status_text = None
self.request.session.flash("Status has been updated to: {}".format(
self.enum.CUSTORDER_ITEM_STATUS[new_status_code]))
@ -418,11 +483,23 @@ class CustomerOrderItemView(MasterView):
route_prefix = cls.get_route_prefix()
instance_url_prefix = cls.get_instance_url_prefix()
permission_prefix = cls.get_permission_prefix()
model_title = cls.get_model_title()
model_title_plural = cls.get_model_title_plural()
# fix permission group name
config.add_tailbone_permission_group(permission_prefix, model_title_plural)
# confirm price
config.add_tailbone_permission(permission_prefix,
'{}.confirm_price'.format(permission_prefix),
"Confirm price for a {}".format(model_title))
config.add_route('{}.confirm_price'.format(route_prefix),
'{}/confirm-price'.format(instance_url_prefix),
request_method='POST')
config.add_view(cls, attr='confirm_price',
route_name='{}.confirm_price'.format(route_prefix),
permission='{}.confirm_price'.format(permission_prefix))
# change status
config.add_tailbone_permission(permission_prefix,
'{}.change_status'.format(permission_prefix),

View file

@ -36,7 +36,7 @@ from rattail.db import model
from rattail.util import pretty_quantity
from rattail.batch import get_batch_handler
from webhelpers2.html import tags
from webhelpers2.html import tags, HTML
from tailbone.db import Session
from tailbone.views import MasterView
@ -189,10 +189,10 @@ class CustomerOrderView(MasterView):
g.set_type('order_quantity', 'quantity')
g.set_type('cases_ordered', 'quantity')
g.set_type('units_ordered', 'quantity')
g.set_type('total_price', 'currency')
g.set_renderer('total_price', self.render_price_with_confirmation)
g.set_enum('order_uom', self.enum.UNIT_OF_MEASURE)
g.set_enum('status_code', self.enum.CUSTORDER_ITEM_STATUS)
g.set_renderer('status_code', self.render_row_status_code)
g.set_label('sequence', "Seq.")
g.filters['sequence'].label = "Sequence"
@ -206,6 +206,22 @@ class CustomerOrderView(MasterView):
g.set_link('product_brand')
g.set_link('product_description')
def render_price_with_confirmation(self, item, field):
price = getattr(item, field)
app = self.get_rattail_app()
text = app.render_currency(price)
if item.price_needs_confirmation:
return HTML.tag('span', class_='has-background-warning',
c=[text])
return text
def render_row_status_code(self, item, field):
text = self.enum.CUSTORDER_ITEM_STATUS.get(item.status_code,
six.text_type(item.status_code))
if item.status_text:
return HTML.tag('span', title=item.status_text, c=[text])
return text
def get_batch_handler(self):
return get_batch_handler(
self.rattail_config, 'custorder',
@ -641,6 +657,7 @@ class CustomerOrderView(MasterView):
'unit_price_display': "${:0.2f}".format(row.unit_price) if row.unit_price is not None else None,
'total_price': six.text_type(row.total_price) if row.total_price is not None else None,
'total_price_display': "${:0.2f}".format(row.total_price) if row.total_price is not None else None,
'price_needs_confirmation': row.price_needs_confirmation,
'status_code': row.status_code,
'status_text': row.status_text,
@ -684,7 +701,8 @@ class CustomerOrderView(MasterView):
row = self.handler.add_product(batch, product,
decimal.Decimal(data.get('order_quantity') or '0'),
data.get('order_uom'))
data.get('order_uom'),
price_needs_confirmation=data.get('price_needs_confirmation'))
self.Session.flush()
else: # product is not known
@ -719,6 +737,7 @@ class CustomerOrderView(MasterView):
row.product = product
row.order_quantity = decimal.Decimal(data.get('order_quantity') or '0')
row.order_uom = data.get('order_uom')
row.price_needs_confirmation = data.get('price_needs_confirmation')
self.handler.refresh_row(row)
self.Session.flush()
self.Session.refresh(row)