Add dialog for viewing product SRP history
only old jquery theme is supported, for now
This commit is contained in:
parent
8947a4d14f
commit
7dce154cc3
|
@ -1,10 +1,41 @@
|
|||
## -*- 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() {
|
||||
|
||||
$('#view-srp-history').on('click', function() {
|
||||
$('#srp-history-dialog').dialog({
|
||||
title: "SRP History",
|
||||
width: 550,
|
||||
height: 300,
|
||||
modal: true,
|
||||
buttons: [
|
||||
{
|
||||
text: "Close",
|
||||
click: function() {
|
||||
$(this).dialog('close');
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
% endif
|
||||
</%def>
|
||||
|
||||
<%def name="extra_styles()">
|
||||
${parent.extra_styles()}
|
||||
% if use_buefy:
|
||||
<style type="text/css">
|
||||
% if use_buefy:
|
||||
#main-product-panel {
|
||||
margin-right: 2em;
|
||||
margin-top: 1em;
|
||||
|
@ -12,8 +43,12 @@
|
|||
#pricing-panel .field-wrapper .field {
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
% else:
|
||||
#srp-history-dialog .grid {
|
||||
color: black;
|
||||
}
|
||||
% endif
|
||||
</style>
|
||||
</%def>
|
||||
|
||||
<%def name="render_main_fields(form)">
|
||||
|
@ -341,6 +376,12 @@
|
|||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
% if request.rattail_config.versioning_enabled() and master.has_perm('versions'):
|
||||
<div id="srp-history-dialog" style="display: none;">
|
||||
${srp_history_grid.render_grid()|n}
|
||||
</div>
|
||||
% endif
|
||||
% endif
|
||||
|
||||
% if buttons:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
################################################################################
|
||||
#
|
||||
# Rattail -- Retail Software Framework
|
||||
# Copyright © 2010-2018 Lance Edgar
|
||||
# Copyright © 2010-2020 Lance Edgar
|
||||
#
|
||||
# This file is part of Rattail.
|
||||
#
|
||||
|
@ -30,16 +30,19 @@ import re
|
|||
import logging
|
||||
|
||||
import six
|
||||
import humanize
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
import sqlalchemy_continuum as continuum
|
||||
|
||||
from rattail import enum, pod, sil
|
||||
from rattail.db import model, api, auth, Session as RattailSession
|
||||
from rattail.gpc import GPC
|
||||
from rattail.threads import Thread
|
||||
from rattail.exceptions import LabelPrintingError
|
||||
from rattail.util import load_object, pretty_quantity
|
||||
from rattail.util import load_object, pretty_quantity, OrderedDict
|
||||
from rattail.batch import get_batch_handler
|
||||
from rattail.time import localtime, make_utc
|
||||
|
||||
import colander
|
||||
from deform import widget as dfwidget
|
||||
|
@ -383,7 +386,7 @@ class ProductsView(MasterView):
|
|||
f.remove_field('suggested_price')
|
||||
else:
|
||||
f.set_readonly('suggested_price')
|
||||
f.set_renderer('suggested_price', self.render_price)
|
||||
f.set_renderer('suggested_price', self.render_suggested_price)
|
||||
|
||||
# regular_price
|
||||
if self.creating:
|
||||
|
@ -445,11 +448,11 @@ class ProductsView(MasterView):
|
|||
|
||||
def render_cost(self, product, field):
|
||||
cost = getattr(product, field)
|
||||
if cost:
|
||||
if cost.unit_cost:
|
||||
if not cost:
|
||||
return ""
|
||||
if cost.unit_cost is None:
|
||||
return ""
|
||||
return "${:0.2f}".format(cost.unit_cost)
|
||||
else:
|
||||
return "TODO: does this item have a cost?"
|
||||
|
||||
def render_price(self, product, column):
|
||||
price = product[column]
|
||||
|
@ -470,13 +473,31 @@ class ProductsView(MasterView):
|
|||
return "$ {:0.2f} / {}".format(price.pack_price, price.pack_multiple)
|
||||
return ""
|
||||
|
||||
def render_cost(self, product, column):
|
||||
cost = product.cost
|
||||
if not cost:
|
||||
return ""
|
||||
if cost.unit_cost is None:
|
||||
return ""
|
||||
return "${:0.2f}".format(cost.unit_cost)
|
||||
def add_srp_history_link(self, text):
|
||||
if not self.rattail_config.versioning_enabled():
|
||||
return text
|
||||
if not self.has_perm('versions'):
|
||||
return text
|
||||
|
||||
history = tags.link_to("(view history)", '#',
|
||||
id='view-srp-history')
|
||||
if not text:
|
||||
return history
|
||||
|
||||
text = HTML.tag('span', c=text)
|
||||
br = HTML.tag('br')
|
||||
return HTML.tag('div', c=[text, br, history])
|
||||
|
||||
def render_suggested_price(self, product, column):
|
||||
text = self.render_price(product, column)
|
||||
|
||||
if text and self.rattail_config.versioning_enabled():
|
||||
history = self.get_srp_history(product)
|
||||
if history:
|
||||
date = localtime(self.rattail_config, history[0]['changed'], from_utc=True).date()
|
||||
text = "{} (as of {})".format(text, date)
|
||||
|
||||
return self.add_srp_history_link(text)
|
||||
|
||||
def render_true_cost(self, product, field):
|
||||
if not product.volatile:
|
||||
|
@ -906,12 +927,96 @@ class ProductsView(MasterView):
|
|||
if not kwargs.get('image_url'):
|
||||
kwargs['image_url'] = self.request.static_url('tailbone:static/img/product.png')
|
||||
|
||||
# add SRP history, if user has access
|
||||
if self.rattail_config.versioning_enabled() and self.has_perm('versions'):
|
||||
data = self.get_srp_history(product)
|
||||
grid = grids.Grid('products.srp_history', data,
|
||||
request=self.request,
|
||||
columns=[
|
||||
'price',
|
||||
'since',
|
||||
'changed',
|
||||
'changed_by',
|
||||
])
|
||||
grid.set_type('price', 'currency')
|
||||
grid.set_type('changed', 'datetime')
|
||||
kwargs['srp_history_grid'] = grid
|
||||
|
||||
kwargs['costs_label_preferred'] = "Pref."
|
||||
kwargs['costs_label_vendor'] = "Vendor"
|
||||
kwargs['costs_label_code'] = "Order Code"
|
||||
kwargs['costs_label_case_size'] = "Case Size"
|
||||
return kwargs
|
||||
|
||||
def get_srp_history(self, product):
|
||||
"""
|
||||
Returns a sequence of "records" which corresponds to the given
|
||||
product's SRP history.
|
||||
"""
|
||||
Transaction = continuum.transaction_class(model.Product)
|
||||
ProductVersion = continuum.version_class(model.Product)
|
||||
ProductPriceVersion = continuum.version_class(model.ProductPrice)
|
||||
now = make_utc()
|
||||
history = []
|
||||
|
||||
# first we find all relevant ProductVersion records
|
||||
versions = self.Session.query(ProductVersion)\
|
||||
.join(Transaction,
|
||||
Transaction.id == ProductVersion.transaction_id)\
|
||||
.filter(ProductVersion.uuid == product.uuid)\
|
||||
.order_by(Transaction.issued_at,
|
||||
Transaction.id)\
|
||||
.all()
|
||||
|
||||
last_uuid = None
|
||||
for version in versions:
|
||||
if version.suggested_price_uuid != last_uuid:
|
||||
changed = version.transaction.issued_at
|
||||
if version.suggested_price:
|
||||
assert isinstance(version.suggested_price, ProductPriceVersion)
|
||||
price = version.suggested_price.price
|
||||
else:
|
||||
price = None
|
||||
history.append({
|
||||
'transaction_id': version.transaction.id,
|
||||
'price': price,
|
||||
'since': humanize.naturaltime(now - changed),
|
||||
'changed': changed,
|
||||
'changed_by': version.transaction.user,
|
||||
})
|
||||
last_uuid = version.suggested_price_uuid
|
||||
|
||||
# next we find all relevant ProductPriceVersion records
|
||||
versions = self.Session.query(ProductPriceVersion)\
|
||||
.join(Transaction,
|
||||
Transaction.id == ProductPriceVersion.transaction_id)\
|
||||
.filter(ProductPriceVersion.product_uuid == product.uuid)\
|
||||
.filter(ProductPriceVersion.type == self.enum.PRICE_TYPE_MFR_SUGGESTED)\
|
||||
.order_by(Transaction.issued_at,
|
||||
Transaction.id)\
|
||||
.all()
|
||||
|
||||
last_price = None
|
||||
for version in versions:
|
||||
if version.price != last_price:
|
||||
changed = version.transaction.issued_at
|
||||
price = version.price
|
||||
history.append({
|
||||
'transaction_id': version.transaction.id,
|
||||
'price': version.price,
|
||||
'since': humanize.naturaltime(now - changed),
|
||||
'changed': changed,
|
||||
'changed_by': version.transaction.user,
|
||||
})
|
||||
last_price = version.price
|
||||
|
||||
final_history = OrderedDict()
|
||||
for hist in reversed(history):
|
||||
if hist['transaction_id'] not in final_history:
|
||||
final_history[hist['transaction_id']] = hist
|
||||
|
||||
return list(final_history.values())
|
||||
|
||||
def edit(self):
|
||||
# TODO: Should add some more/better hooks, so don't have to duplicate
|
||||
# so much code here.
|
||||
|
|
Loading…
Reference in a new issue