fix: add optional Transactions tab for profile view

showing Trainwreck data by default
This commit is contained in:
Lance Edgar 2024-07-05 14:45:35 -05:00
parent b7d26b6b8c
commit 16bf13787d
3 changed files with 210 additions and 0 deletions

View file

@ -33,6 +33,20 @@
</b-field>
</div>
<h3 class="block is-size-3">Profile View</h3>
<div class="block" style="padding-left: 2rem; width: 50%;">
<b-field>
<b-checkbox name="tailbone.people.profile.expose_transactions"
v-model="simpleSettings['tailbone.people.profile.expose_transactions']"
native-value="true"
@input="settingsNeedSaved = true">
Show tab for Customer POS Transactions
</b-checkbox>
</b-field>
</div>
</%def>

View file

@ -1656,6 +1656,34 @@
</${b}-tab-item>
</%def>
% if expose_transactions:
<%def name="render_transactions_tab_template()">
<script type="text/x-template" id="transactions-tab-template">
<div>
<transactions-grid
ref="transactionsGrid"
/>
</div>
</script>
</%def>
<%def name="render_transactions_tab()">
<${b}-tab-item label="Transactions"
value="transactions"
% if not request.use_oruga:
icon-pack="fas"
% endif
icon="bars">
<transactions-tab ref="tab_transactions"
:person="person"
@profile-changed="profileChanged" />
</${b}-tab-item>
</%def>
% endif
<%def name="render_user_tab_template()">
<script type="text/x-template" id="user-tab-template">
<div>
@ -1806,6 +1834,9 @@
% endif
${self.render_employee_tab()}
${self.render_notes_tab()}
% if expose_transactions:
${self.render_transactions_tab()}
% endif
${self.render_user_tab()}
</%def>
@ -1941,6 +1972,12 @@
% endif
${self.render_employee_tab_template()}
${self.render_notes_tab_template()}
% if expose_transactions:
${transactions_grid.render_complete(allow_save_defaults=False)|n}
${self.render_transactions_tab_template()}
% endif
${self.render_user_tab_template()}
${self.render_profile_info_template()}
</%def>
@ -2824,6 +2861,49 @@
</script>
</%def>
% if expose_transactions:
<%def name="declare_transactions_tab_vars()">
<script type="text/javascript">
let TransactionsTabData = {}
let TransactionsTab = {
template: '#transactions-tab-template',
mixins: [TabMixin, SimpleRequestMixin],
props: {
person: Object,
},
computed: {},
methods: {
// nb. we override this completely, just tell the grid to refresh
refreshTab() {
this.refreshingTab = true
this.$refs.transactionsGrid.loadAsyncData(null, () => {
this.refreshed = Date.now()
this.refreshingTab = false
})
}
},
}
</script>
</%def>
<%def name="make_transactions_tab_component()">
${self.declare_transactions_tab_vars()}
<script type="text/javascript">
TransactionsTab.data = function() { return TransactionsTabData }
Vue.component('transactions-tab', TransactionsTab)
<% request.register_component('transactions-tab', 'TransactionsTab') %>
</script>
</%def>
% endif
<%def name="declare_user_tab_vars()">
<script type="text/javascript">
@ -3086,6 +3166,19 @@
% endif
${self.make_employee_tab_component()}
${self.make_notes_tab_component()}
% if expose_transactions:
<script type="text/javascript">
TransactionsGrid.data = function() { return TransactionsGridData }
Vue.component('transactions-grid', TransactionsGrid)
## TODO: why is this line not needed?
## <% request.register_component('transactions-grid', 'TransactionsGrid') %>
</script>
${self.make_transactions_tab_component()}
% endif
${self.make_user_tab_component()}
${self.make_profile_info_component()}
</%def>

View file

@ -40,6 +40,7 @@ import colander
from webhelpers2.html import HTML, tags
from tailbone import forms, grids
from tailbone.db import TrainwreckSession
from tailbone.views import MasterView
from tailbone.util import raw_datetime
@ -487,13 +488,101 @@ class PersonView(MasterView):
'expose_customer_shoppers': self.customers_should_expose_shoppers(),
'max_one_member': app.get_membership_handler().max_one_per_person(),
'use_preferred_first_name': self.people_handler.should_use_preferred_first_name(),
'expose_transactions': self.should_expose_profile_transactions(),
}
if context['expose_transactions']:
context['transactions_grid'] = self.profile_transactions_grid(person, empty=True)
if self.request.has_perm('people_profile.view_versions'):
context['revisions_grid'] = self.profile_revisions_grid(person)
return self.render_to_response('view_profile', context)
def should_expose_profile_transactions(self):
return self.rattail_config.get_bool('tailbone.people.profile.expose_transactions',
default=False)
def profile_transactions_grid(self, person, empty=False):
app = self.get_rattail_app()
trainwreck = app.get_trainwreck_handler()
model = trainwreck.get_model()
route_prefix = self.get_route_prefix()
if empty:
# TODO: surely there is a better way to have empty data..? but so
# much logic depends on a query, can't just pass empty list here
data = TrainwreckSession.query(model.Transaction)\
.filter(model.Transaction.uuid == 'bogus')
else:
data = self.profile_transactions_query(person)
factory = self.get_grid_factory()
g = factory(
f'{route_prefix}.profile.transactions.{person.uuid}',
data,
request=self.request,
model_class=model.Transaction,
ajax_data_url=self.get_action_url('view_profile_transactions', person),
columns=[
'start_time',
'end_time',
'system',
'terminal_id',
'receipt_number',
'cashier_name',
'customer_id',
'customer_name',
'total',
],
labels={
'terminal_id': "Terminal",
'customer_id': "Customer " + app.get_customer_key_label(),
},
filterable=True,
sortable=True,
pageable=True,
default_sortkey='end_time',
default_sortdir='desc',
component='transactions-grid',
)
if self.request.has_perm('trainwreck.transactions.view'):
url = lambda row, i: self.request.route_url('trainwreck.transactions.view',
uuid=row.uuid)
g.main_actions.append(grids.GridAction('view', icon='eye', url=url))
g.load_settings()
g.set_enum('system', self.enum.TRAINWRECK_SYSTEM)
g.set_type('total', 'currency')
return g
def profile_transactions_query(self, person):
"""
Method which must return the base query for the profile's POS
Transactions grid data.
"""
app = self.get_rattail_app()
customer = app.get_customer(person)
key_field = app.get_customer_key_field()
customer_key = getattr(customer, key_field)
if customer_key is not None:
customer_key = str(customer_key)
trainwreck = app.get_trainwreck_handler()
model = trainwreck.get_model()
query = TrainwreckSession.query(model.Transaction)\
.filter(model.Transaction.customer_id == customer_key)
return query
def profile_transactions_data(self):
"""
AJAX view to return new sorted, filtered data for transactions
grid within profile view.
"""
person = self.get_instance()
grid = self.profile_transactions_grid(person)
return grid.get_table_data()
def get_context_tabchecks(self, person):
app = self.get_rattail_app()
membership = app.get_membership_handler()
@ -1605,6 +1694,11 @@ class PersonView(MasterView):
{'section': 'rattail',
'option': 'people.handler'},
# Profile View
{'section': 'tailbone',
'option': 'people.profile.expose_transactions',
'type': bool},
]
@classmethod
@ -1873,6 +1967,15 @@ class PersonView(MasterView):
permission='people_profile.delete_note',
renderer='json')
# profile - transactions data
config.add_route(f'{route_prefix}.view_profile_transactions',
f'{instance_url_prefix}/profile/transactions',
request_method='GET')
config.add_view(cls, attr='profile_transactions_data',
route_name=f'{route_prefix}.view_profile_transactions',
permission=f'{permission_prefix}.view_profile',
renderer='json')
# make user for person
config.add_route('{}.make_user'.format(route_prefix), '{}/make-user'.format(url_prefix),
request_method='POST')