Show events instead of notes, in field subgrid for custorder item
This commit is contained in:
		
							parent
							
								
									e930199f83
								
							
						
					
					
						commit
						1cad8b2481
					
				
					 2 changed files with 77 additions and 123 deletions
				
			
		| 
						 | 
				
			
			@ -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"
 | 
			
		||||
            })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue