tailbone/tailbone/templates/products/view.mako
Lance Edgar cc96d9877b 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
2020-04-06 13:12:38 -05:00

664 lines
20 KiB
Mako

## -*- coding: utf-8; -*-
<%inherit file="/master/view.mako" />
<%def name="extra_javascript()">
${parent.extra_javascript()}
% if not use_buefy and request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<script type="text/javascript">
function showPriceHistory(typ) {
var dialog = $('#' + typ + '-price-history-dialog');
dialog.dialog({
title: typ[0].toUpperCase() + typ.slice(1) + " Price History",
width: 600,
height: 300,
modal: true,
buttons: [
{
text: "Close",
click: function() {
dialog.dialog('close');
}
}
]
});
}
function showCostHistory() {
var dialog = $('#cost-history-dialog');
dialog.dialog({
title: "Cost History",
width: 600,
height: 300,
modal: true,
buttons: [
{
text: "Close",
click: function() {
dialog.dialog('close');
}
}
]
});
}
$(function() {
$('#view-regular-price-history').on('click', function() {
showPriceHistory('regular');
return false;
});
$('#view-current-price-history').on('click', function() {
showPriceHistory('current');
return false;
});
$('#view-suggested-price-history').on('click', function() {
showPriceHistory('suggested');
return false;
});
$('#view-cost-history').on('click', function() {
showCostHistory();
return false;
});
});
</script>
% endif
</%def>
<%def name="extra_styles()">
${parent.extra_styles()}
<style type="text/css">
% if use_buefy:
#main-product-panel {
margin-right: 2em;
margin-top: 1em;
}
#pricing-panel .field-wrapper .field {
white-space: nowrap;
}
% else:
.price-history-dialog {
display: none;
}
.price-history-dialog .grid {
color: black;
}
% endif
</style>
</%def>
<%def name="render_main_fields(form)">
${form.render_field_readonly('upc')}
${form.render_field_readonly('brand')}
${form.render_field_readonly('description')}
${form.render_field_readonly('size')}
${form.render_field_readonly('unit_size')}
${form.render_field_readonly('unit_of_measure')}
${form.render_field_readonly('case_size')}
% if instance.is_pack_item():
${form.render_field_readonly('pack_size')}
${form.render_field_readonly('unit')}
${form.render_field_readonly('default_pack')}
% elif instance.packs:
${form.render_field_readonly('packs')}
% endif
${self.extra_main_fields(form)}
</%def>
<%def name="left_column()">
% if use_buefy:
<nav class="panel" id="pricing-panel">
<p class="panel-heading">Pricing</p>
<div class="panel-block">
<div>
${self.render_price_fields(form)}
</div>
</div>
</nav>
<nav class="panel">
<p class="panel-heading">Flags</p>
<div class="panel-block">
<div>
${self.render_flag_fields(form)}
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Pricing</h2>
<div class="panel-body">
${self.render_price_fields(form)}
</div>
</div>
<div class="panel">
<h2>Flags</h2>
<div class="panel-body">
${self.render_flag_fields(form)}
</div>
</div>
% endif
${self.extra_left_panels()}
</%def>
<%def name="right_column()">
${self.organization_panel()}
${self.movement_panel()}
${self.sources_panel()}
${self.notes_panel()}
${self.ingredients_panel()}
${self.lookup_codes_panel()}
${self.extra_right_panels()}
</%def>
<%def name="extra_main_fields(form)"></%def>
<%def name="organization_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Organization</p>
<div class="panel-block">
<div>
${self.render_organization_fields(form)}
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Organization</h2>
<div class="panel-body">
${self.render_organization_fields(form)}
</div>
</div>
% endif
</%def>
<%def name="render_organization_fields(form)">
${form.render_field_readonly('department')}
${form.render_field_readonly('subdepartment')}
${form.render_field_readonly('category')}
${form.render_field_readonly('family')}
${form.render_field_readonly('report_code')}
</%def>
<%def name="render_price_fields(form)">
${form.render_field_readonly('price_required')}
${form.render_field_readonly('regular_price')}
${form.render_field_readonly('current_price')}
${form.render_field_readonly('current_price_ends')}
${form.render_field_readonly('suggested_price')}
${form.render_field_readonly('deposit_link')}
${form.render_field_readonly('tax')}
</%def>
<%def name="render_flag_fields(form)">
${form.render_field_readonly('weighed')}
${form.render_field_readonly('discountable')}
${form.render_field_readonly('special_order')}
${form.render_field_readonly('organic')}
${form.render_field_readonly('not_for_sale')}
${form.render_field_readonly('discontinued')}
${form.render_field_readonly('deleted')}
</%def>
<%def name="movement_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Movement</p>
<div class="panel-block">
<div>
${self.render_movement_fields(form)}
</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Movement</h2>
<div class="panel-body">
${self.render_movement_fields(form)}
</div>
</div>
% endif
</%def>
<%def name="render_movement_fields(form)">
${form.render_field_readonly('last_sold')}
</%def>
<%def name="lookup_codes_grid()">
<div class="grid full no-border">
<table>
<thead>
<th>Seq</th>
<th>Code</th>
</thead>
<tbody>
% for code in instance._codes:
<tr>
<td>${code.ordinal}</td>
<td>${code.code}</td>
</tr>
% endfor
</tbody>
</table>
</div>
</%def>
<%def name="lookup_codes_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Additional Lookup Codes</p>
<div class="panel-block">
${self.lookup_codes_grid()}
</div>
</nav>
% else:
<div class="panel-grid" id="product-codes">
<h2>Additional Lookup Codes</h2>
${self.lookup_codes_grid()}
</div>
% endif
</%def>
<%def name="sources_grid()">
<div class="grid full no-border">
<table>
<thead>
<th>${costs_label_preferred}</th>
<th>${costs_label_vendor}</th>
<th>${costs_label_code}</th>
<th>${costs_label_case_size}</th>
<th>Case Cost</th>
<th>Unit Cost</th>
<th>Status</th>
</thead>
<tbody>
% for i, cost in enumerate(instance.costs, 1):
<tr class="${'even' if i % 2 == 0 else 'odd'}">
<td class="center">${'X' if cost.preference == 1 else ''}</td>
<td>
% if request.has_perm('vendors.view'):
${h.link_to(cost.vendor, request.route_url('vendors.view', uuid=cost.vendor_uuid))}
% else:
${cost.vendor}
% endif
</td>
<td class="center">${cost.code or ''}</td>
<td class="center">${h.pretty_quantity(cost.case_size)}</td>
<td class="right">${'$ %0.2f' % cost.case_cost if cost.case_cost is not None else ''}</td>
<td class="right">${'$ %0.4f' % cost.unit_cost if cost.unit_cost is not None else ''}</td>
<td>${"discontinued" if cost.discontinued else "available"}</td>
</tr>
% endfor
</tbody>
</table>
</div>
</%def>
<%def name="sources_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">
Vendor Sources
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<a href="#" @click.prevent="showCostHistory()">
(view cost history)
</a>
% endif
</p>
<div class="panel-block">
${self.sources_grid()}
</div>
</nav>
% else:
<div class="panel-grid" id="product-costs">
<h2>
Vendor Sources
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<a id="view-cost-history" href="#">(view cost history)</a>
% endif
</h2>
${self.sources_grid()}
</div>
% endif
</%def>
<%def name="notes_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Notes</p>
<div class="panel-block">
<div class="field">${form.render_field_readonly('notes')}</div>
</div>
</nav>
% else:
<div class="panel">
<h2>Notes</h2>
<div class="panel-body">
<div class="field">${form.render_field_readonly('notes')}</div>
</div>
</div>
% endif
</%def>
<%def name="ingredients_panel()">
% if use_buefy:
<nav class="panel">
<p class="panel-heading">Ingredients</p>
<div class="panel-block">
${form.render_field_readonly('ingredients')}
</div>
</nav>
% else:
<div class="panel">
<h2>Ingredients</h2>
<div class="panel-body">
${form.render_field_readonly('ingredients')}
</div>
</div>
% endif
</%def>
<%def name="extra_left_panels()"></%def>
<%def name="extra_right_panels()"></%def>
<%def name="render_this_page()">
${parent.render_this_page()}
% if use_buefy and request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<b-modal :active.sync="showingPriceHistory_regular"
has-modal-card>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">
Regular Price History
</p>
</header>
<section class="modal-card-body">
${regular_price_history_grid.render_buefy_table_element(data_prop='regularPriceHistoryData', loading='regularPriceHistoryLoading')|n}
</section>
<footer class="modal-card-foot">
<b-button @click="showingPriceHistory_regular = false">
Close
</b-button>
</footer>
</div>
</b-modal>
<b-modal :active.sync="showingPriceHistory_current"
has-modal-card>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">
Current Price History
</p>
</header>
<section class="modal-card-body">
${current_price_history_grid.render_buefy_table_element(data_prop='currentPriceHistoryData', loading='currentPriceHistoryLoading')|n}
</section>
<footer class="modal-card-foot">
<b-button @click="showingPriceHistory_current = false">
Close
</b-button>
</footer>
</div>
</b-modal>
<b-modal :active.sync="showingPriceHistory_suggested"
has-modal-card>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">
Suggested Price History
</p>
</header>
<section class="modal-card-body">
${suggested_price_history_grid.render_buefy_table_element(data_prop='suggestedPriceHistoryData', loading='suggestedPriceHistoryLoading')|n}
</section>
<footer class="modal-card-foot">
<b-button @click="showingPriceHistory_suggested = false">
Close
</b-button>
</footer>
</div>
</b-modal>
<b-modal :active.sync="showingCostHistory"
has-modal-card>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">
Cost History
</p>
</header>
<section class="modal-card-body">
${cost_history_grid.render_buefy_table_element(data_prop='costHistoryData', loading='costHistoryLoading')|n}
</section>
<footer class="modal-card-foot">
<b-button @click="showingCostHistory = false">
Close
</b-button>
</footer>
</div>
</b-modal>
% endif
</%def>
<%def name="page_content()">
% if use_buefy:
<div style="display: flex; flex-direction: column;">
<nav class="panel" id="main-product-panel">
<p class="panel-heading">Product</p>
<div class="panel-block">
<div style="display: flex; justify-content: space-between; width: 100%;">
<div>
${self.render_main_fields(form)}
</div>
<div>
% if image_url:
${h.image(image_url, "Product Image", id='product-image', width=150, height=150)}
% endif
</div>
</div>
</div>
</nav>
<div style="display: flex;">
<div class="panel-wrapper"> <!-- left column -->
${self.left_column()}
</div> <!-- left column -->
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div> <!-- right column -->
</div>
</div>
% else:
## legacy / not buefy
<div style="display: flex; flex-direction: column;">
<div class="panel" id="product-main">
<h2>Product</h2>
<div class="panel-body">
<div style="display: flex; justify-content: space-between;">
<div>
${self.render_main_fields(form)}
</div>
<div>
% if image_url:
${h.image(image_url, "Product Image", id='product-image', width=150, height=150)}
% endif
</div>
</div>
</div>
</div>
<div style="display: flex;">
<div class="panel-wrapper"> <!-- left column -->
${self.left_column()}
</div> <!-- left column -->
<div class="panel-wrapper" style="margin-left: 1em;"> <!-- right column -->
${self.right_column()}
</div> <!-- right column -->
</div>
</div>
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<div class="price-history-dialog" id="regular-price-history-dialog">
${regular_price_history_grid.render_grid()|n}
</div>
<div class="price-history-dialog" id="current-price-history-dialog">
${current_price_history_grid.render_grid()|n}
</div>
<div class="price-history-dialog" id="suggested-price-history-dialog">
${suggested_price_history_grid.render_grid()|n}
</div>
<div class="price-history-dialog" id="cost-history-dialog">
${cost_history_grid.render_grid()|n}
</div>
% endif
% endif
% if buttons:
${buttons|n}
% endif
</%def>
<%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()}
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
<script type="text/javascript">
ThisPageData.showingPriceHistory_regular = false
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.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.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.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>
% endif
</%def>
${parent.body()}