Defer fetching price, cost history when viewing product details

user can ask for that history if they need it, but it's too expensive to always
fetch by default for initial page load
This commit is contained in:
Lance Edgar 2020-04-06 13:12:38 -05:00
parent f2b5e2302a
commit cc96d9877b
3 changed files with 213 additions and 18 deletions

View file

@ -32,7 +32,8 @@
let ThisPage = { let ThisPage = {
template: '#this-page-template', template: '#this-page-template',
methods: {} computed: {},
methods: {},
} }
let ThisPageData = { let ThisPageData = {

View file

@ -305,7 +305,7 @@
<p class="panel-heading"> <p class="panel-heading">
Vendor Sources Vendor Sources
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'): % if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<a href="#" @click.prevent="showingCostHistory = true"> <a href="#" @click.prevent="showCostHistory()">
(view cost history) (view cost history)
</a> </a>
% endif % endif
@ -380,7 +380,7 @@
</p> </p>
</header> </header>
<section class="modal-card-body"> <section class="modal-card-body">
${regular_price_history_grid.render_buefy_table_element(data_prop='regularPriceHistoryData')|n} ${regular_price_history_grid.render_buefy_table_element(data_prop='regularPriceHistoryData', loading='regularPriceHistoryLoading')|n}
</section> </section>
<footer class="modal-card-foot"> <footer class="modal-card-foot">
<b-button @click="showingPriceHistory_regular = false"> <b-button @click="showingPriceHistory_regular = false">
@ -399,7 +399,7 @@
</p> </p>
</header> </header>
<section class="modal-card-body"> <section class="modal-card-body">
${current_price_history_grid.render_buefy_table_element(data_prop='currentPriceHistoryData')|n} ${current_price_history_grid.render_buefy_table_element(data_prop='currentPriceHistoryData', loading='currentPriceHistoryLoading')|n}
</section> </section>
<footer class="modal-card-foot"> <footer class="modal-card-foot">
<b-button @click="showingPriceHistory_current = false"> <b-button @click="showingPriceHistory_current = false">
@ -418,7 +418,7 @@
</p> </p>
</header> </header>
<section class="modal-card-body"> <section class="modal-card-body">
${suggested_price_history_grid.render_buefy_table_element(data_prop='suggestedPriceHistoryData')|n} ${suggested_price_history_grid.render_buefy_table_element(data_prop='suggestedPriceHistoryData', loading='suggestedPriceHistoryLoading')|n}
</section> </section>
<footer class="modal-card-foot"> <footer class="modal-card-foot">
<b-button @click="showingPriceHistory_suggested = false"> <b-button @click="showingPriceHistory_suggested = false">
@ -437,7 +437,7 @@
</p> </p>
</header> </header>
<section class="modal-card-body"> <section class="modal-card-body">
${cost_history_grid.render_buefy_table_element(data_prop='costHistoryData')|n} ${cost_history_grid.render_buefy_table_element(data_prop='costHistoryData', loading='costHistoryLoading')|n}
</section> </section>
<footer class="modal-card-foot"> <footer class="modal-card-foot">
<b-button @click="showingCostHistory = false"> <b-button @click="showingCostHistory = false">
@ -539,16 +539,121 @@
<script type="text/javascript"> <script type="text/javascript">
ThisPageData.showingPriceHistory_regular = false ThisPageData.showingPriceHistory_regular = false
ThisPageData.regularPriceHistoryData = ${json.dumps(regular_price_history_grid.get_buefy_data()['data'])|n} ThisPageData.regularPriceHistoryDataRaw = ${json.dumps(regular_price_history_grid.get_buefy_data()['data'])|n}
ThisPageData.regularPriceHistoryLoading = false
ThisPage.computed.regularPriceHistoryData = function() {
let data = []
this.regularPriceHistoryDataRaw.forEach(raw => {
data.push({
price: raw.price_display,
since: raw.since,
changed: raw.changed_display_html,
changed_by: raw.changed_by_display,
})
})
return data
}
ThisPage.methods.showPriceHistory_regular = function() {
this.showingPriceHistory_regular = true
this.regularPriceHistoryLoading = true
let url = '${url("products.price_history", uuid=instance.uuid)}'
let params = {'type': 'regular'}
this.$http.get(url, {params: params}).then(response => {
this.regularPriceHistoryDataRaw = response.data
this.regularPriceHistoryLoading = false
})
}
ThisPageData.showingPriceHistory_current = false ThisPageData.showingPriceHistory_current = false
ThisPageData.currentPriceHistoryData = ${json.dumps(current_price_history_grid.get_buefy_data()['data'])|n} ThisPageData.currentPriceHistoryDataRaw = ${json.dumps(current_price_history_grid.get_buefy_data()['data'])|n}
ThisPageData.currentPriceHistoryLoading = false
ThisPage.computed.currentPriceHistoryData = function() {
let data = []
this.currentPriceHistoryDataRaw.forEach(raw => {
data.push({
price: raw.price_display,
price_type: raw.price_type,
since: raw.since,
changed: raw.changed_display_html,
changed_by: raw.changed_by_display,
})
})
return data
}
ThisPage.methods.showPriceHistory_current = function() {
this.showingPriceHistory_current = true
this.currentPriceHistoryLoading = true
let url = '${url("products.price_history", uuid=instance.uuid)}'
let params = {'type': 'current'}
this.$http.get(url, {params: params}).then(response => {
this.currentPriceHistoryDataRaw = response.data
this.currentPriceHistoryLoading = false
})
}
ThisPageData.showingPriceHistory_suggested = false ThisPageData.showingPriceHistory_suggested = false
ThisPageData.suggestedPriceHistoryData = ${json.dumps(suggested_price_history_grid.get_buefy_data()['data'])|n} ThisPageData.suggestedPriceHistoryDataRaw = ${json.dumps(suggested_price_history_grid.get_buefy_data()['data'])|n}
ThisPageData.suggestedPriceHistoryLoading = false
ThisPage.computed.suggestedPriceHistoryData = function() {
let data = []
this.suggestedPriceHistoryDataRaw.forEach(raw => {
data.push({
price: raw.price_display,
since: raw.since,
changed: raw.changed_display_html,
changed_by: raw.changed_by_display,
})
})
return data
}
ThisPage.methods.showPriceHistory_suggested = function() {
this.showingPriceHistory_suggested = true
this.suggestedPriceHistoryLoading = true
let url = '${url("products.price_history", uuid=instance.uuid)}'
let params = {'type': 'suggested'}
this.$http.get(url, {params: params}).then(response => {
this.suggestedPriceHistoryDataRaw = response.data
this.suggestedPriceHistoryLoading = false
})
}
ThisPageData.showingCostHistory = false ThisPageData.showingCostHistory = false
ThisPageData.costHistoryData = ${json.dumps(cost_history_grid.get_buefy_data()['data'])|n} ThisPageData.costHistoryDataRaw = ${json.dumps(cost_history_grid.get_buefy_data()['data'])|n}
ThisPageData.costHistoryLoading = false
ThisPage.computed.costHistoryData = function() {
let data = []
this.costHistoryDataRaw.forEach(raw => {
data.push({
cost: raw.cost_display,
vendor: raw.vendor,
since: raw.since,
changed: raw.changed_display_html,
changed_by: raw.changed_by_display,
})
})
return data
}
ThisPage.methods.showCostHistory = function() {
this.showingCostHistory = true
this.costHistoryLoading = true
let url = '${url("products.cost_history", uuid=instance.uuid)}'
this.$http.get(url).then(response => {
this.costHistoryDataRaw = response.data
this.costHistoryLoading = false
})
}
</script> </script>
% endif % endif

View file

@ -483,7 +483,7 @@ class ProductsView(MasterView):
return text return text
if self.get_use_buefy(): if self.get_use_buefy():
kwargs = {'@click.prevent': 'showingPriceHistory_{} = true'.format(typ)} kwargs = {'@click.prevent': 'showPriceHistory_{}()'.format(typ)}
else: else:
kwargs = {'id': 'view-{}-price-history'.format(typ)} kwargs = {'id': 'view-{}-price-history'.format(typ)}
history = tags.link_to("(view history)", '#', **kwargs) history = tags.link_to("(view history)", '#', **kwargs)
@ -494,10 +494,17 @@ class ProductsView(MasterView):
br = HTML.tag('br') br = HTML.tag('br')
return HTML.tag('div', c=[text, br, history]) return HTML.tag('div', c=[text, br, history])
def show_price_effective_dates(self):
if not self.rattail_config.versioning_enabled():
return False
return self.rattail_config.getbool(
'tailbone', 'products.show_effective_price_dates',
default=True)
def render_regular_price(self, product, field): def render_regular_price(self, product, field):
text = self.render_price(product, field) text = self.render_price(product, field)
if text and self.rattail_config.versioning_enabled(): if text and self.show_price_effective_dates():
history = self.get_regular_price_history(product) history = self.get_regular_price_history(product)
if history: if history:
date = localtime(self.rattail_config, history[0]['changed'], from_utc=True).date() date = localtime(self.rattail_config, history[0]['changed'], from_utc=True).date()
@ -508,7 +515,7 @@ class ProductsView(MasterView):
def render_current_price(self, product, field): def render_current_price(self, product, field):
text = self.render_price(product, field) text = self.render_price(product, field)
if text and self.rattail_config.versioning_enabled(): if text and self.show_price_effective_dates():
history = self.get_current_price_history(product) history = self.get_current_price_history(product)
if history: if history:
date = localtime(self.rattail_config, history[0]['changed'], from_utc=True).date() date = localtime(self.rattail_config, history[0]['changed'], from_utc=True).date()
@ -526,7 +533,7 @@ class ProductsView(MasterView):
def render_suggested_price(self, product, column): def render_suggested_price(self, product, column):
text = self.render_price(product, column) text = self.render_price(product, column)
if text and self.rattail_config.versioning_enabled(): if text and self.show_price_effective_dates():
history = self.get_suggested_price_history(product) history = self.get_suggested_price_history(product)
if history: if history:
date = localtime(self.rattail_config, history[0]['changed'], from_utc=True).date() date = localtime(self.rattail_config, history[0]['changed'], from_utc=True).date()
@ -973,8 +980,63 @@ class ProductsView(MasterView):
return "" return ""
return pretty_quantity(value) return pretty_quantity(value)
def price_history(self):
"""
AJAX view for fetching various types of price history for a product.
"""
product = self.get_instance()
typ = self.request.params.get('type', 'regular')
assert typ in ('regular', 'current', 'suggested')
getter = getattr(self, 'get_{}_price_history'.format(typ))
data = getter(product)
# make some data JSON-friendly
jsdata = []
for history in data:
history = dict(history)
price = history['price']
history['price'] = float(price)
history['price_display'] = "${:0.2f}".format(price)
changed = localtime(self.rattail_config, history['changed'], from_utc=True)
history['changed'] = six.text_type(changed)
history['changed_display_html'] = raw_datetime(self.rattail_config, changed)
user = history.pop('changed_by')
history['changed_by_uuid'] = user.uuid
history['changed_by_display'] = six.text_type(user)
jsdata.append(history)
return jsdata
def cost_history(self):
"""
AJAX view for fetching cost history for a product.
"""
product = self.get_instance()
data = self.get_cost_history(product)
# make some data JSON-friendly
jsdata = []
for history in data:
history = dict(history)
cost = history['cost']
if cost is not None:
history['cost'] = float(cost)
history['cost_display'] = "${:0.2f}".format(cost)
else:
history['cost_display'] = None
changed = localtime(self.rattail_config, history['changed'], from_utc=True)
history['changed'] = six.text_type(changed)
history['changed_display_html'] = raw_datetime(self.rattail_config, changed)
user = history.pop('changed_by')
history['changed_by_uuid'] = user.uuid
history['changed_by_display'] = six.text_type(user)
jsdata.append(history)
return jsdata
def template_kwargs_view(self, **kwargs): def template_kwargs_view(self, **kwargs):
product = kwargs['instance'] product = kwargs['instance']
use_buefy = self.get_use_buefy()
# TODO: pretty sure this is no longer needed? guess we'll find out # TODO: pretty sure this is no longer needed? guess we'll find out
# kwargs['image'] = False # kwargs['image'] = False
@ -998,7 +1060,10 @@ class ProductsView(MasterView):
if self.rattail_config.versioning_enabled() and self.has_perm('versions'): if self.rattail_config.versioning_enabled() and self.has_perm('versions'):
# regular price # regular price
data = self.get_regular_price_history(product) if use_buefy:
data = [] # defer fetching until user asks for it
else:
data = self.get_regular_price_history(product)
grid = grids.Grid('products.regular_price_history', data, grid = grids.Grid('products.regular_price_history', data,
request=self.request, request=self.request,
columns=[ columns=[
@ -1012,7 +1077,10 @@ class ProductsView(MasterView):
kwargs['regular_price_history_grid'] = grid kwargs['regular_price_history_grid'] = grid
# current price # current price
data = self.get_current_price_history(product) if use_buefy:
data = [] # defer fetching until user asks for it
else:
data = self.get_current_price_history(product)
grid = grids.Grid('products.current_price_history', data, grid = grids.Grid('products.current_price_history', data,
request=self.request, request=self.request,
columns=[ columns=[
@ -1030,7 +1098,10 @@ class ProductsView(MasterView):
kwargs['current_price_history_grid'] = grid kwargs['current_price_history_grid'] = grid
# suggested price # suggested price
data = self.get_suggested_price_history(product) if use_buefy:
data = [] # defer fetching until user asks for it
else:
data = self.get_suggested_price_history(product)
grid = grids.Grid('products.suggested_price_history', data, grid = grids.Grid('products.suggested_price_history', data,
request=self.request, request=self.request,
columns=[ columns=[
@ -1044,7 +1115,10 @@ class ProductsView(MasterView):
kwargs['suggested_price_history_grid'] = grid kwargs['suggested_price_history_grid'] = grid
# cost history # cost history
data = self.get_cost_history(product) if use_buefy:
data = [] # defer fetching until user asks for it
else:
data = self.get_cost_history(product)
grid = grids.Grid('products.cost_history', data, grid = grids.Grid('products.cost_history', data,
request=self.request, request=self.request,
columns=[ columns=[
@ -1654,6 +1728,7 @@ class ProductsView(MasterView):
rattail_config = config.registry.settings.get('rattail_config') rattail_config = config.registry.settings.get('rattail_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()
instance_url_prefix = cls.get_instance_url_prefix()
template_prefix = cls.get_template_prefix() template_prefix = cls.get_template_prefix()
permission_prefix = cls.get_permission_prefix() permission_prefix = cls.get_permission_prefix()
model_title = cls.get_model_title() model_title = cls.get_model_title()
@ -1684,6 +1759,20 @@ class ProductsView(MasterView):
config.add_route('products.image', '/products/{uuid}/image') config.add_route('products.image', '/products/{uuid}/image')
config.add_view(cls, attr='image', route_name='products.image') config.add_view(cls, attr='image', route_name='products.image')
# price history
config.add_route('{}.price_history'.format(route_prefix), '{}/price-history'.format(instance_url_prefix),
request_method='GET')
config.add_view(cls, attr='price_history', route_name='{}.price_history'.format(route_prefix),
renderer='json',
permission='{}.versions'.format(permission_prefix))
# cost history
config.add_route('{}.cost_history'.format(route_prefix), '{}/cost-history'.format(instance_url_prefix),
request_method='GET')
config.add_view(cls, attr='cost_history', route_name='{}.cost_history'.format(route_prefix),
renderer='json',
permission='{}.versions'.format(permission_prefix))
# mobile quick lookup # mobile quick lookup
if legacy_mobile: if legacy_mobile:
config.add_route('mobile.products.quick_lookup', '/mobile/products/quick-lookup') config.add_route('mobile.products.quick_lookup', '/mobile/products/quick-lookup')