diff --git a/tailbone/templates/products/view.mako b/tailbone/templates/products/view.mako index 6ca39c28..35095a1d 100644 --- a/tailbone/templates/products/view.mako +++ b/tailbone/templates/products/view.mako @@ -31,6 +31,11 @@ return false; }); + $('#view-current-price-history').on('click', function() { + showPriceHistory('current'); + return false; + }); + $('#view-suggested-price-history').on('click', function() { showPriceHistory('suggested'); return false; @@ -394,6 +399,9 @@
${regular_price_history_grid.render_grid()|n}
+
+ ${current_price_history_grid.render_grid()|n} +
${suggested_price_history_grid.render_grid()|n}
diff --git a/tailbone/views/products.py b/tailbone/views/products.py index 43b6d93e..3ce27e87 100644 --- a/tailbone/views/products.py +++ b/tailbone/views/products.py @@ -403,7 +403,7 @@ class ProductsView(MasterView): f.remove_field('current_price') else: f.set_readonly('current_price') - f.set_renderer('current_price', self.render_price) + f.set_renderer('current_price', self.render_current_price) # current_price_ends if self.creating: @@ -506,6 +506,21 @@ class ProductsView(MasterView): else: # not buefy return self.add_price_history_link(text, 'regular') + def render_current_price(self, product, field): + text = self.render_price(product, field) + + if text and self.rattail_config.versioning_enabled(): + history = self.get_current_price_history(product) + if history: + date = localtime(self.rattail_config, history[0]['changed'], from_utc=True).date() + text = "{} (as of {})".format(text, date) + + if self.get_use_buefy(): + # TODO: should add history link here too... + return text + else: # not buefy + return self.add_price_history_link(text, 'current') + def warn_if_regprice_more_than_srp(self, product, text): sugprice = product.suggested_price.price if product.suggested_price else None regprice = product.regular_price.price if product.regular_price else None @@ -983,6 +998,24 @@ class ProductsView(MasterView): grid.set_type('changed', 'datetime') kwargs['regular_price_history_grid'] = grid + # current price + data = self.get_current_price_history(product) + grid = grids.Grid('products.current_price_history', data, + request=self.request, + columns=[ + 'price', + 'price_type', + 'since', + 'changed', + 'changed_by', + ], + labels={ + 'price_type': "Type", + }) + grid.set_type('price', 'currency') + grid.set_type('changed', 'datetime') + kwargs['current_price_history_grid'] = grid + # suggested price data = self.get_suggested_price_history(product) grid = grids.Grid('products.suggested_price_history', data, @@ -1066,7 +1099,122 @@ class ProductsView(MasterView): last_price = version.price final_history = OrderedDict() - for hist in reversed(history): + for hist in sorted(history, key=lambda h: h['changed'], reverse=True): + if hist['transaction_id'] not in final_history: + final_history[hist['transaction_id']] = hist + + return list(final_history.values()) + + def get_current_price_history(self, product): + """ + Returns a sequence of "records" which corresponds to the given + product's current price 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_current_uuid = None + last_regular_uuid = None + for version in versions: + + changed = False + if version.current_price_uuid != last_current_uuid: + changed = True + elif not version.current_price_uuid and version.regular_price_uuid != last_regular_uuid: + changed = True + + if changed: + changed = version.transaction.issued_at + if version.current_price: + assert isinstance(version.current_price, ProductPriceVersion) + price = version.current_price.price + price_type = self.enum.PRICE_TYPE.get(version.current_price.type) + elif version.regular_price: + price = version.regular_price.price + price_type = self.enum.PRICE_TYPE.get(version.regular_price.type) + else: + price = None + price_type = None + history.append({ + 'transaction_id': version.transaction.id, + 'price': price, + 'price_type': price_type, + 'since': humanize.naturaltime(now - changed), + 'changed': changed, + 'changed_by': version.transaction.user, + }) + + last_current_uuid = version.current_price_uuid + last_regular_uuid = version.regular_price_uuid + + # next we find all relevant *SALE* 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_SALE)\ + .order_by(Transaction.issued_at, + Transaction.id)\ + .all() + + last_price = None + for version in versions: + # only include this version if it was "current" at the time + if version.uuid == version.product.current_price_uuid: + if version.price != last_price: + changed = version.transaction.issued_at + price = version.price + history.append({ + 'transaction_id': version.transaction.id, + 'price': version.price, + 'price_type': self.enum.PRICE_TYPE[version.type], + 'since': humanize.naturaltime(now - changed), + 'changed': changed, + 'changed_by': version.transaction.user, + }) + last_price = version.price + + # next we find all relevant *TPR* 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_TPR)\ + .order_by(Transaction.issued_at, + Transaction.id)\ + .all() + + last_price = None + for version in versions: + # only include this version if it was "current" at the time + if version.uuid == version.product.current_price_uuid: + if version.price != last_price: + changed = version.transaction.issued_at + price = version.price + history.append({ + 'transaction_id': version.transaction.id, + 'price': version.price, + 'price_type': self.enum.PRICE_TYPE[version.type], + 'since': humanize.naturaltime(now - changed), + 'changed': changed, + 'changed_by': version.transaction.user, + }) + last_price = version.price + + final_history = OrderedDict() + for hist in sorted(history, key=lambda h: h['changed'], reverse=True): if hist['transaction_id'] not in final_history: final_history[hist['transaction_id']] = hist @@ -1135,7 +1283,7 @@ class ProductsView(MasterView): last_price = version.price final_history = OrderedDict() - for hist in reversed(history): + for hist in sorted(history, key=lambda h: h['changed'], reverse=True): if hist['transaction_id'] not in final_history: final_history[hist['transaction_id']] = hist