Show events instead of notes, in field subgrid for custorder item

This commit is contained in:
Lance Edgar 2023-09-12 12:35:53 -05:00
parent e930199f83
commit 1cad8b2481
2 changed files with 77 additions and 123 deletions

View file

@ -280,7 +280,7 @@
:disabled="addNoteSaveDisabled"
icon-pack="fas"
icon-left="save">
{{ addNoteSubmitText }}
{{ addNoteSubmitting ? "Working, please wait..." : "Save Note" }}
</b-button>
<b-button @click="showAddNoteDialog = false">
Cancel
@ -295,7 +295,7 @@
${parent.modify_this_page_vars()}
<script type="text/javascript">
${form.component_studly}Data.notesData = ${json.dumps(notes_data)|n}
${form.component_studly}Data.eventsData = ${json.dumps(events_data)|n}
% if master.has_perm('confirm_price'):
@ -406,7 +406,6 @@
ThisPageData.newNoteText = null
ThisPageData.newNoteApplyAll = false
ThisPageData.addNoteSubmitting = false
ThisPageData.addNoteSubmitText = "Save Note"
ThisPage.computed.addNoteSaveDisabled = function() {
if (!this.newNoteText) {
@ -429,43 +428,19 @@
ThisPage.methods.addNoteSave = function() {
this.addNoteSubmitting = true
this.addNoteSubmitText = "Working, please wait..."
let url = '${url('{}.add_note'.format(route_prefix), uuid=instance.uuid)}'
let params = {
note: this.newNoteText,
apply_all: this.newNoteApplyAll,
}
let headers = {
## TODO: should find a better way to handle CSRF token
'X-CSRF-TOKEN': this.csrftoken,
}
## TODO: should find a better way to handle CSRF token
this.$http.post(url, params, {headers: headers}).then(({ data }) => {
if (data.success) {
this.$refs.mainForm.notesData = data.notes
this.showAddNoteDialog = false
} else {
this.$buefy.toast.open({
message: "Save failed: " + (data.error || "(unknown error)"),
type: 'is-danger',
duration: 4000, // 4 seconds
})
}
this.simplePOST(url, params, response => {
this.$refs.mainForm.eventsData = response.data.events
this.showAddNoteDialog = false
this.addNoteSubmitting = false
this.addNoteSubmitText = "Save Note"
}).catch((error) => {
// TODO: should handle this better somehow..?
this.$buefy.toast.open({
message: "Save failed: (unknown error)",
type: 'is-danger',
duration: 4000, // 4 seconds
})
}, response => {
this.addNoteSubmitting = false
this.addNoteSubmitText = "Save Note"
})
}

View file

@ -28,8 +28,7 @@ import datetime
from sqlalchemy import orm
from rattail.db import model
from rattail.time import localtime
from rattail.db.model import CustomerOrderItem
from webhelpers2.html import HTML, tags
@ -41,7 +40,7 @@ class CustomerOrderItemView(MasterView):
"""
Master view for customer order items
"""
model_class = model.CustomerOrderItem
model_class = CustomerOrderItem
route_prefix = 'custorders.items'
url_prefix = '/custorders/items'
creatable = False
@ -72,21 +71,6 @@ class CustomerOrderItemView(MasterView):
'flagged',
]
has_rows = True
model_row_class = model.CustomerOrderItemEvent
rows_title = "Event History"
rows_filterable = False
rows_sortable = False
rows_pageable = False
rows_viewable = False
row_grid_columns = [
'occurred',
'type_code',
'user',
'note',
]
form_fields = [
'order',
'customer',
@ -98,20 +82,32 @@ class CustomerOrderItemView(MasterView):
'product_brand',
'product_description',
'product_size',
'case_quantity',
'order_quantity',
'order_uom',
'case_quantity',
'unit_price',
'total_price',
'special_order',
'price_needs_confirmation',
'paid_amount',
'payment_transaction_number',
'status_code',
'flagged',
'notes',
'contact_attempts',
'last_contacted',
'events',
]
def __init__(self, request):
super().__init__(request)
app = self.get_rattail_app()
self.custorder_handler = app.get_custorder_handler()
self.batch_handler = app.get_batch_handler(
'custorder',
default='rattail.batch.custorder:CustomerOrderBatchHandler')
def query(self, session):
model = self.model
return session.query(model.CustomerOrderItem)\
.join(model.CustomerOrder)\
.options(orm.joinedload(model.CustomerOrderItem.order)\
@ -119,7 +115,7 @@ class CustomerOrderItemView(MasterView):
def configure_grid(self, g):
super().configure_grid(g)
batch_handler = self.get_batch_handler()
model = self.model
# order_id
g.set_renderer('order_id', self.render_order_id)
@ -155,7 +151,7 @@ class CustomerOrderItemView(MasterView):
# order_uom
# nb. this is not relevant if "case orders only"
if not batch_handler.allow_unit_orders():
if not self.batch_handler.allow_unit_orders():
g.remove('order_uom')
else:
g.set_enum('order_uom', self.enum.UNIT_OF_MEASURE)
@ -168,6 +164,19 @@ class CustomerOrderItemView(MasterView):
# status_code
g.set_renderer('status_code', self.render_status_code_column)
# abbreviate some labels, only in grid header
g.set_label('case_quantity', "Case Qty")
g.filters['case_quantity'].label = "Case Quantity"
g.set_label('order_quantity', "Order Qty")
g.filters['order_quantity'].label = "Order Quantity"
g.set_label('department_name', "Department")
g.filters['department_name'].label = "Department Name"
g.set_label('total_price', "Total")
g.filters['total_price'].label = "Total Price"
g.set_label('order_created', "Ordered")
if 'order_created' in g.filters:
g.filters['order_created'].label = "Order Created"
def render_order_id(self, item, field):
return item.order.id
@ -178,7 +187,8 @@ class CustomerOrderItemView(MasterView):
return text
def render_order_created(self, item, column):
value = localtime(self.rattail_config, item.order.created, from_utc=True)
app = self.get_rattail_app()
value = app.localtime(item.order.created, from_utc=True)
return raw_datetime(self.rattail_config, value)
def render_status_code_column(self, item, field):
@ -188,12 +198,6 @@ class CustomerOrderItemView(MasterView):
return HTML.tag('span', title=item.status_text, c=[text])
return text
def get_batch_handler(self):
app = self.get_rattail_app()
return app.get_batch_handler(
'custorder',
default='rattail.batch.custorder:CustomerOrderBatchHandler')
def configure_form(self, f):
super().configure_form(f)
item = f.model_instance
@ -202,8 +206,7 @@ class CustomerOrderItemView(MasterView):
f.set_renderer('order', self.render_order)
# contact
batch_handler = self.get_batch_handler()
if batch_handler.new_order_requires_customer():
if self.batch_handler.new_order_requires_customer():
f.remove('person')
else:
f.remove('customer')
@ -221,7 +224,9 @@ class CustomerOrderItemView(MasterView):
elif item.pending_product and not item.product:
f.remove('product')
# product uom
# product*
if not self.creating and item.product:
f.remove('product_brand', 'product_description')
f.set_enum('product_unit_of_measure', self.enum.UNIT_OF_MEASURE)
# highlight pending fields
@ -251,8 +256,8 @@ class CustomerOrderItemView(MasterView):
# flagged
f.set_renderer('flagged', self.render_flagged)
# notes
f.set_renderer('notes', self.render_notes)
# events
f.set_renderer('events', self.render_events)
def render_flagged(self, item, field):
text = "Yes" if item.flagged else "No"
@ -375,27 +380,28 @@ class CustomerOrderItemView(MasterView):
return False
def render_notes(self, item, field):
def render_events(self, item, field):
route_prefix = self.get_route_prefix()
factory = self.get_grid_factory()
g = factory(
key=f'{route_prefix}.notes',
key=f'{route_prefix}.events',
data=[],
columns=[
'created',
'created_by',
'text',
'occurred',
'type_code',
'user',
'note',
],
labels={
'created': "Date/Time",
'created_by': "Added by",
'text': "Note",
'occurred': "When",
'type_code': "What",
'user': "Who",
},
)
table = HTML.literal(
g.render_buefy_table_element(data_prop='notesData'))
g.render_buefy_table_element(data_prop='eventsData'))
elements = [table]
if self.has_perm('add_note'):
@ -412,12 +418,13 @@ class CustomerOrderItemView(MasterView):
c=elements)
def template_kwargs_view(self, **kwargs):
kwargs = super(CustomerOrderItemView, self).template_kwargs_view(**kwargs)
kwargs = super().template_kwargs_view(**kwargs)
model = self.model
app = self.get_rattail_app()
item = kwargs['instance']
# fetch notes for current item
kwargs['notes_data'] = self.get_context_notes(item)
# fetch events for current item
kwargs['events_data'] = self.get_context_events(item)
# fetch "other" order items, siblings of current one
order = item.order
@ -431,7 +438,7 @@ class CustomerOrderItemView(MasterView):
order_date = None
if order.created:
order_date = localtime(self.rattail_config, order.created, from_utc=True).date()
order_date = app.localtime(order.created, from_utc=True).date()
other_data.append({
'uuid': other.uuid,
@ -454,16 +461,18 @@ class CustomerOrderItemView(MasterView):
return kwargs
def get_context_notes(self, item):
notes = []
for note in reversed(item.notes):
created = localtime(self.rattail_config, note.created, from_utc=True)
notes.append({
'created': raw_datetime(self.rattail_config, created),
'created_by': note.created_by.display_name,
'text': note.text,
def get_context_events(self, item):
app = self.get_rattail_app()
events = []
for event in item.events:
occurred = app.localtime(event.occurred, from_utc=True)
events.append({
'occurred': raw_datetime(self.rattail_config, occurred),
'type_code': self.enum.CUSTORDER_ITEM_EVENT.get(event.type_code, event.type_code),
'user': str(event.user),
'note': event.note,
})
return notes
return events
def confirm_price(self):
"""
@ -517,6 +526,7 @@ class CustomerOrderItemView(MasterView):
"""
View for changing status of one or more order items.
"""
model = self.model
order_item = self.get_instance()
redirect = self.redirect(self.get_action_url('view', order_item))
@ -570,30 +580,15 @@ class CustomerOrderItemView(MasterView):
View for adding a new note to current order item, optinally
also adding it to all other items under the parent order.
"""
order_item = self.get_instance()
item = self.get_instance()
data = self.request.json_body
new_note = data['note']
apply_all = data['apply_all'] == True
user = self.request.user
if apply_all:
order_items = order_item.order.items
else:
order_items = [order_item]
for item in order_items:
item.notes.append(model.CustomerOrderItemNote(
created_by=user, text=new_note))
# # attach event
# item.events.append(model.CustomerOrderItemEvent(
# type_code=self.enum.CUSTORDER_ITEM_EVENT_ADDED_NOTE,
# user=user, note=new_note))
self.custorder_handler.add_note(item, data['note'], self.request.user,
apply_all=data['apply_all'] == True)
self.Session.flush()
self.Session.refresh(order_item)
return {'success': True,
'notes': self.get_context_notes(order_item)}
self.Session.refresh(item)
return {'events': self.get_context_events(item)}
def render_order(self, item, field):
order = item.order
@ -610,22 +605,6 @@ class CustomerOrderItemView(MasterView):
url = self.request.route_url('people.view', uuid=person.uuid)
return tags.link_to(text, url)
def get_row_data(self, item):
return self.Session.query(model.CustomerOrderItemEvent)\
.filter(model.CustomerOrderItemEvent.item == item)\
.order_by(model.CustomerOrderItemEvent.occurred,
model.CustomerOrderItemEvent.type_code)
def configure_row_grid(self, g):
super(CustomerOrderItemView, self).configure_row_grid(g)
g.set_enum('type_code', self.enum.CUSTORDER_ITEM_EVENT)
g.set_label('occurred', "When")
g.set_label('type_code', "What") # TODO: enum renderer
g.set_label('user', "Who")
g.set_label('note', "Notes")
@classmethod
def defaults(cls, config):
cls._order_item_defaults(config)