feat: allow re-order past product for new orders

assuming batch has a customer set, with order history

nb. this only uses past *products* and not order qty/uom
This commit is contained in:
Lance Edgar 2025-02-01 19:39:02 -06:00
parent aa31d23fc8
commit 3ca89a8479
5 changed files with 633 additions and 54 deletions

View file

@ -4,6 +4,8 @@ import datetime
import decimal
from unittest.mock import patch
import sqlalchemy as sa
from wuttjamaican.testing import DataTestCase
from sideshow.batch import neworder as mod
@ -267,6 +269,14 @@ class TestNewOrderBatchHandler(DataTestCase):
# search for juice finds nothing
self.assertEqual(handler.autocomplete_products_local(self.session, 'juice'), [])
def test_get_default_uom_choices(self):
enum = self.app.enum
handler = self.make_handler()
uoms = handler.get_default_uom_choices()
self.assertEqual(uoms, [{'key': key, 'value': val}
for key, val in enum.ORDER_UOM.items()])
def test_get_product_info_external(self):
handler = self.make_handler()
self.assertRaises(NotImplementedError, handler.get_product_info_external,
@ -308,6 +318,174 @@ class TestNewOrderBatchHandler(DataTestCase):
mock_uuid = self.app.make_true_uuid()
self.assertRaises(ValueError, handler.get_product_info_local, self.session, mock_uuid.hex)
def test_normalize_local_product(self):
model = self.app.model
handler = self.make_handler()
product = model.LocalProduct(scancode='07430500132',
brand_name="Bragg's",
description="Apple Cider Vinegar",
size="32oz",
department_name="Grocery",
case_size=12,
unit_price_reg=5.99,
vendor_name="UNFI",
vendor_item_code='1234')
self.session.add(product)
self.session.flush()
info = handler.normalize_local_product(product)
self.assertIsInstance(info, dict)
self.assertEqual(info['product_id'], product.uuid.hex)
for prop in sa.inspect(model.LocalProduct).column_attrs:
if prop.key == 'uuid':
continue
if prop.key not in info:
continue
self.assertEqual(info[prop.key], getattr(product, prop.key))
def test_get_past_orders(self):
model = self.app.model
handler = self.make_handler()
user = model.User(username='barney')
self.session.add(user)
batch = handler.make_batch(self.session, created_by=user)
self.session.add(batch)
self.session.flush()
# ..will test local customers first
# error if no customer
self.assertRaises(ValueError, handler.get_past_orders, batch)
# empty history for customer
customer = model.LocalCustomer(full_name='Fred Flintstone')
batch.local_customer = customer
self.session.flush()
orders = handler.get_past_orders(batch)
self.assertEqual(len(orders), 0)
# mock historical order
order = model.Order(order_id=42, local_customer=customer, created_by=user)
self.session.add(order)
self.session.flush()
# that should now be returned
orders = handler.get_past_orders(batch)
self.assertEqual(len(orders), 1)
self.assertIs(orders[0], order)
# ..now we test external customers, w/ new batch
with patch.object(handler, 'use_local_customers', return_value=False):
batch2 = handler.make_batch(self.session, created_by=user)
self.session.add(batch2)
self.session.flush()
# error if no customer
self.assertRaises(ValueError, handler.get_past_orders, batch2)
# empty history for customer
batch2.customer_id = '123'
self.session.flush()
orders = handler.get_past_orders(batch2)
self.assertEqual(len(orders), 0)
# mock historical order
order2 = model.Order(order_id=42, customer_id='123', created_by=user)
self.session.add(order2)
self.session.flush()
# that should now be returned
orders = handler.get_past_orders(batch2)
self.assertEqual(len(orders), 1)
self.assertIs(orders[0], order2)
def test_get_past_products(self):
model = self.app.model
enum = self.app.enum
handler = self.make_handler()
user = model.User(username='barney')
self.session.add(user)
batch = handler.make_batch(self.session, created_by=user)
self.session.add(batch)
self.session.flush()
# (nb. this all assumes local customers)
# ..will test local products first
# error if no customer
self.assertRaises(ValueError, handler.get_past_products, batch)
# empty history for customer
customer = model.LocalCustomer(full_name='Fred Flintstone')
batch.local_customer = customer
self.session.flush()
products = handler.get_past_products(batch)
self.assertEqual(len(products), 0)
# mock historical order
order = model.Order(order_id=42, local_customer=customer, created_by=user)
product = model.LocalProduct(scancode='07430500132', description='Vinegar',
unit_price_reg=5.99, case_size=12)
item = model.OrderItem(local_product=product, order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_READY)
order.items.append(item)
self.session.add(order)
self.session.flush()
self.session.refresh(product)
# that should now be returned
products = handler.get_past_products(batch)
self.assertEqual(len(products), 1)
self.assertEqual(products[0]['product_id'], product.uuid.hex)
self.assertEqual(products[0]['scancode'], '07430500132')
self.assertEqual(products[0]['description'], 'Vinegar')
self.assertEqual(products[0]['case_price_quoted'], decimal.Decimal('71.88'))
self.assertEqual(products[0]['case_price_quoted_display'], '$71.88')
# ..now we test external products, w/ new batch
with patch.object(handler, 'use_local_products', return_value=False):
batch2 = handler.make_batch(self.session, created_by=user)
self.session.add(batch2)
self.session.flush()
# error if no customer
self.assertRaises(ValueError, handler.get_past_products, batch2)
# empty history for customer
batch2.local_customer = customer
self.session.flush()
products = handler.get_past_products(batch2)
self.assertEqual(len(products), 0)
# mock historical order
order2 = model.Order(order_id=44, local_customer=customer, created_by=user)
self.session.add(order2)
item2 = model.OrderItem(product_id='07430500116',
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_READY)
order2.items.append(item2)
self.session.flush()
# its product should now be returned
with patch.object(handler, 'get_product_info_external', return_value={
'product_id': '07430500116',
'scancode': '07430500116',
'description': 'VINEGAR',
'unit_price_reg': decimal.Decimal('3.99'),
'case_size': 12,
}):
products = handler.get_past_products(batch2)
self.assertEqual(len(products), 1)
self.assertEqual(products[0]['product_id'], '07430500116')
self.assertEqual(products[0]['scancode'], '07430500116')
self.assertEqual(products[0]['description'], 'VINEGAR')
self.assertEqual(products[0]['case_price_quoted'], decimal.Decimal('47.88'))
self.assertEqual(products[0]['case_price_quoted_display'], '$47.88')
def test_add_item(self):
model = self.app.model
enum = self.app.enum

View file

@ -16,6 +16,7 @@ from sideshow.orders import OrderHandler
from sideshow.testing import WebTestCase
from sideshow.web.views import orders as mod
from sideshow.web.forms.schema import OrderRef, PendingProductRef
from sideshow.config import SideshowConfig
class TestIncludeme(WebTestCase):
@ -26,6 +27,11 @@ class TestIncludeme(WebTestCase):
class TestOrderView(WebTestCase):
def make_config(self, **kw):
config = super().make_config(**kw)
SideshowConfig().configure(config)
return config
def make_view(self):
return mod.OrderView(self.request)
@ -661,6 +667,51 @@ class TestOrderView(WebTestCase):
context = view.get_product_info(batch, {'product_id': '42'})
self.assertEqual(context, {'error': "something smells fishy"})
def test_get_past_products(self):
model = self.app.model
enum = self.app.enum
view = self.make_view()
handler = view.batch_handler
user = model.User(username='barney')
self.session.add(user)
batch = handler.make_batch(self.session, created_by=user)
self.session.add(batch)
self.session.flush()
# (nb. this all assumes local customers and products)
# error if no customer
self.assertRaises(ValueError, view.get_past_products, batch, {})
# empty history for customer
customer = model.LocalCustomer(full_name='Fred Flintstone')
batch.local_customer = customer
self.session.flush()
products = view.get_past_products(batch, {})
self.assertEqual(len(products), 0)
# mock historical order
order = model.Order(order_id=42, local_customer=customer, created_by=user)
product = model.LocalProduct(scancode='07430500132', description='Vinegar',
unit_price_reg=5.99, case_size=12)
item = model.OrderItem(local_product=product, order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_READY)
order.items.append(item)
self.session.add(order)
self.session.flush()
self.session.refresh(product)
# that should now be returned
products = view.get_past_products(batch, {})
self.assertEqual(len(products), 1)
self.assertEqual(products[0]['product_id'], product.uuid.hex)
self.assertEqual(products[0]['scancode'], '07430500132')
self.assertEqual(products[0]['description'], 'Vinegar')
# nb. this is a float, since result is JSON-safe
self.assertEqual(products[0]['case_price_quoted'], 71.88)
self.assertEqual(products[0]['case_price_quoted_display'], '$71.88')
def test_add_item(self):
model = self.app.model
enum = self.app.enum
@ -911,14 +962,6 @@ class TestOrderView(WebTestCase):
'error': f"ValueError: batch has already been executed: {batch}",
})
def test_get_default_uom_choices(self):
enum = self.app.enum
view = self.make_view()
uoms = view.get_default_uom_choices()
self.assertEqual(uoms, [{'key': key, 'value': val}
for key, val in enum.ORDER_UOM.items()])
def test_normalize_batch(self):
model = self.app.model
enum = self.app.enum