feat: add initial workflow master views, UI features

This commit is contained in:
Lance Edgar 2025-01-22 21:32:15 -06:00
parent 9d378a0c5f
commit 7167c6a7cc
10 changed files with 2364 additions and 22 deletions

View file

@ -9,6 +9,7 @@ class TestOrderHandler(DataTestCase):
def make_config(self, **kwargs):
config = super().make_config(**kwargs)
config.setdefault('wutta.model_spec', 'sideshow.db.model')
config.setdefault('wutta.enum_spec', 'sideshow.enum')
return config
@ -58,3 +59,361 @@ class TestOrderHandler(DataTestCase):
self.assertEqual(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_RESTOCKED), 'warning')
self.assertEqual(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_EXPIRED), 'warning')
self.assertEqual(handler.item_status_to_variant(enum.ORDER_ITEM_STATUS_INACTIVE), 'warning')
def test_process_placement(self):
model = self.app.model
enum = self.app.enum
handler = self.make_handler()
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_READY)
order.items.append(item1)
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_READY)
order.items.append(item2)
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_READY)
order.items.append(item3)
self.session.add(order)
self.session.flush()
# two items are updated
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_READY)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_READY)
self.assertEqual(len(item1.events), 0)
self.assertEqual(len(item2.events), 0)
handler.process_placement([item1, item2], user,
vendor_name="Acme Dist", po_number='ACME123')
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(len(item1.events), 1)
self.assertEqual(len(item2.events), 1)
self.assertEqual(item1.events[0].note, "PO ACME123 for vendor Acme Dist")
self.assertEqual(item2.events[0].note, "PO ACME123 for vendor Acme Dist")
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_PLACED)
self.assertEqual(item2.events[0].type_code, enum.ORDER_ITEM_EVENT_PLACED)
# update last item, without vendor name but extra note
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_READY)
self.assertEqual(len(item3.events), 0)
handler.process_placement([item3], user, po_number="939234", note="extra note")
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(len(item3.events), 2)
self.assertEqual(item3.events[0].note, "PO 939234")
self.assertEqual(item3.events[1].note, "extra note")
self.assertEqual(item3.events[0].type_code, enum.ORDER_ITEM_EVENT_PLACED)
self.assertEqual(item3.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
def test_process_receiving(self):
model = self.app.model
enum = self.app.enum
handler = self.make_handler()
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_PLACED)
order.items.append(item1)
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_PLACED)
order.items.append(item2)
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_PLACED)
order.items.append(item3)
item4 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_PLACED)
order.items.append(item4)
item5 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_PLACED)
order.items.append(item5)
self.session.add(order)
self.session.flush()
# all info provided
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(len(item1.events), 0)
handler.process_receiving([item1], user, vendor_name="Acme Dist",
invoice_number='INV123', po_number='123')
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item1.events), 1)
self.assertEqual(item1.events[0].note, "invoice INV123 (PO 123) from vendor Acme Dist")
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_RECEIVED)
# missing PO number
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(len(item2.events), 0)
handler.process_receiving([item2], user, vendor_name="Acme Dist", invoice_number='INV123')
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item2.events), 1)
self.assertEqual(item2.events[0].note, "invoice INV123 from vendor Acme Dist")
self.assertEqual(item2.events[0].type_code, enum.ORDER_ITEM_EVENT_RECEIVED)
# missing invoice number
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(len(item3.events), 0)
handler.process_receiving([item3], user, vendor_name="Acme Dist", po_number='123')
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item3.events), 1)
self.assertEqual(item3.events[0].note, "PO 123 from vendor Acme Dist")
self.assertEqual(item3.events[0].type_code, enum.ORDER_ITEM_EVENT_RECEIVED)
# vendor name only
self.assertEqual(item4.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(len(item4.events), 0)
handler.process_receiving([item4], user, vendor_name="Acme Dist")
self.assertEqual(item4.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item4.events), 1)
self.assertEqual(item4.events[0].note, "from vendor Acme Dist")
self.assertEqual(item4.events[0].type_code, enum.ORDER_ITEM_EVENT_RECEIVED)
# no info; extra note
self.assertEqual(item5.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(len(item5.events), 0)
handler.process_receiving([item5], user, note="extra note")
self.assertEqual(item5.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item5.events), 2)
self.assertIsNone(item5.events[0].note)
self.assertEqual(item5.events[0].type_code, enum.ORDER_ITEM_EVENT_RECEIVED)
self.assertEqual(item5.events[1].note, "extra note")
self.assertEqual(item5.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
def test_process_reorder(self):
model = self.app.model
enum = self.app.enum
handler = self.make_handler()
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_PLACED)
order.items.append(item1)
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_PLACED)
order.items.append(item2)
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_PLACED)
order.items.append(item3)
self.session.add(order)
self.session.flush()
# two items are updated
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(len(item1.events), 0)
self.assertEqual(len(item2.events), 0)
handler.process_reorder([item1, item2], user)
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_READY)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_READY)
self.assertEqual(len(item1.events), 1)
self.assertEqual(len(item2.events), 1)
self.assertIsNone(item1.events[0].note)
self.assertIsNone(item2.events[0].note)
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_REORDER)
self.assertEqual(item2.events[0].type_code, enum.ORDER_ITEM_EVENT_REORDER)
# update last item, with extra note
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(len(item3.events), 0)
handler.process_reorder([item3], user, note="extra note")
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_READY)
self.assertEqual(len(item3.events), 2)
self.assertIsNone(item3.events[0].note)
self.assertEqual(item3.events[1].note, "extra note")
self.assertEqual(item3.events[0].type_code, enum.ORDER_ITEM_EVENT_REORDER)
self.assertEqual(item3.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
def test_process_contact_success(self):
model = self.app.model
enum = self.app.enum
handler = self.make_handler()
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item1)
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item2)
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item3)
self.session.add(order)
self.session.flush()
# two items are updated
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item1.events), 0)
self.assertEqual(len(item2.events), 0)
handler.process_contact_success([item1, item2], user)
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_CONTACTED)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_CONTACTED)
self.assertEqual(len(item1.events), 1)
self.assertEqual(len(item2.events), 1)
self.assertIsNone(item1.events[0].note)
self.assertIsNone(item2.events[0].note)
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACTED)
self.assertEqual(item2.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACTED)
# update last item, with extra note
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item3.events), 0)
handler.process_contact_success([item3], user, note="extra note")
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_CONTACTED)
self.assertEqual(len(item3.events), 2)
self.assertIsNone(item3.events[0].note)
self.assertEqual(item3.events[1].note, "extra note")
self.assertEqual(item3.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACTED)
self.assertEqual(item3.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
def test_process_contact_failure(self):
model = self.app.model
enum = self.app.enum
handler = self.make_handler()
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item1)
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item2)
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item3)
self.session.add(order)
self.session.flush()
# two items are updated
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item1.events), 0)
self.assertEqual(len(item2.events), 0)
handler.process_contact_failure([item1, item2], user)
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_CONTACT_FAILED)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_CONTACT_FAILED)
self.assertEqual(len(item1.events), 1)
self.assertEqual(len(item2.events), 1)
self.assertIsNone(item1.events[0].note)
self.assertIsNone(item2.events[0].note)
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED)
self.assertEqual(item2.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED)
# update last item, with extra note
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item3.events), 0)
handler.process_contact_failure([item3], user, note="extra note")
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_CONTACT_FAILED)
self.assertEqual(len(item3.events), 2)
self.assertIsNone(item3.events[0].note)
self.assertEqual(item3.events[1].note, "extra note")
self.assertEqual(item3.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED)
self.assertEqual(item3.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
def test_process_delivery(self):
model = self.app.model
enum = self.app.enum
handler = self.make_handler()
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item1)
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item2)
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item3)
self.session.add(order)
self.session.flush()
# two items are updated
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item1.events), 0)
self.assertEqual(len(item2.events), 0)
handler.process_delivery([item1, item2], user)
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_DELIVERED)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_DELIVERED)
self.assertEqual(len(item1.events), 1)
self.assertEqual(len(item2.events), 1)
self.assertIsNone(item1.events[0].note)
self.assertIsNone(item2.events[0].note)
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_DELIVERED)
self.assertEqual(item2.events[0].type_code, enum.ORDER_ITEM_EVENT_DELIVERED)
# update last item, with extra note
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item3.events), 0)
handler.process_delivery([item3], user, note="extra note")
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_DELIVERED)
self.assertEqual(len(item3.events), 2)
self.assertIsNone(item3.events[0].note)
self.assertEqual(item3.events[1].note, "extra note")
self.assertEqual(item3.events[0].type_code, enum.ORDER_ITEM_EVENT_DELIVERED)
self.assertEqual(item3.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
def test_process_restock(self):
model = self.app.model
enum = self.app.enum
handler = self.make_handler()
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item1)
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item2)
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item3)
self.session.add(order)
self.session.flush()
# two items are updated
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item1.events), 0)
self.assertEqual(len(item2.events), 0)
handler.process_restock([item1, item2], user)
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RESTOCKED)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_RESTOCKED)
self.assertEqual(len(item1.events), 1)
self.assertEqual(len(item2.events), 1)
self.assertIsNone(item1.events[0].note)
self.assertIsNone(item2.events[0].note)
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_RESTOCKED)
self.assertEqual(item2.events[0].type_code, enum.ORDER_ITEM_EVENT_RESTOCKED)
# update last item, with extra note
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item3.events), 0)
handler.process_restock([item3], user, note="extra note")
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_RESTOCKED)
self.assertEqual(len(item3.events), 2)
self.assertIsNone(item3.events[0].note)
self.assertEqual(item3.events[1].note, "extra note")
self.assertEqual(item3.events[0].type_code, enum.ORDER_ITEM_EVENT_RESTOCKED)
self.assertEqual(item3.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)

View file

@ -1265,24 +1265,28 @@ class TestOrderView(WebTestCase):
self.assertTrue(self.session.query(model.Setting).count() > 1)
class TestOrderItemView(WebTestCase):
class OrderItemViewTestMixin:
def make_view(self):
return mod.OrderItemView(self.request)
def test_order_handler(self):
def test_common_order_handler(self):
view = self.make_view()
handler = view.order_handler
self.assertIsInstance(handler, OrderHandler)
handler2 = view.get_order_handler()
self.assertIs(handler2, handler)
def test_get_query(self):
def test_common_get_fallback_templates(self):
view = self.make_view()
templates = view.get_fallback_templates('view')
self.assertEqual(templates, ['/order-items/view.mako',
'/master/view.mako'])
def test_common_get_query(self):
view = self.make_view()
query = view.get_query(session=self.session)
self.assertIsInstance(query, orm.Query)
def test_configure_grid(self):
def test_common_configure_grid(self):
model = self.app.model
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
@ -1290,7 +1294,7 @@ class TestOrderItemView(WebTestCase):
view.configure_grid(grid)
self.assertIn('order_id', grid.linked_columns)
def test_render_order_id(self):
def test_common_render_order_id(self):
model = self.app.model
view = self.make_view()
order = model.Order(order_id=42)
@ -1298,13 +1302,13 @@ class TestOrderItemView(WebTestCase):
order.items.append(item)
self.assertEqual(view.render_order_id(item, None, None), 42)
def test_render_status_code(self):
def test_common_render_status_code(self):
enum = self.app.enum
view = self.make_view()
self.assertEqual(view.render_status_code(None, None, enum.ORDER_ITEM_STATUS_INITIATED),
'initiated')
def test_grid_row_class(self):
def test_common_grid_row_class(self):
model = self.app.model
enum = self.app.enum
view = self.make_view()
@ -1317,7 +1321,7 @@ class TestOrderItemView(WebTestCase):
item = model.OrderItem(status_code=enum.ORDER_ITEM_STATUS_CANCELED)
self.assertEqual(view.grid_row_class(item, {}, 1), 'has-background-warning')
def test_configure_form(self):
def test_common_configure_form(self):
model = self.app.model
enum = self.app.enum
view = self.make_view()
@ -1343,7 +1347,7 @@ class TestOrderItemView(WebTestCase):
self.assertIsInstance(schema['order'].typ, OrderRef)
self.assertNotIn('pending_product', form)
def test_get_template_context(self):
def test_common_get_template_context(self):
model = self.app.model
enum = self.app.enum
view = self.make_view()
@ -1363,7 +1367,7 @@ class TestOrderItemView(WebTestCase):
self.assertIn('order_qty_uom_text', context)
self.assertEqual(context['order_qty_uom_text'], "2 Cases (× 8 = 16 Units)")
def test_render_event_note(self):
def test_common_render_event_note(self):
model = self.app.model
enum = self.app.enum
view = self.make_view()
@ -1381,7 +1385,7 @@ class TestOrderItemView(WebTestCase):
self.assertIn('class="has-background-info-light"', result)
self.assertIn('testing2', result)
def test_get_xref_buttons(self):
def test_common_get_xref_buttons(self):
self.pyramid_config.add_route('orders.view', '/orders/{uuid}')
model = self.app.model
enum = self.app.enum
@ -1404,11 +1408,12 @@ class TestOrderItemView(WebTestCase):
self.assertEqual(len(buttons), 1)
self.assertIn("View the Order", buttons[0])
def test_add_note(self):
self.pyramid_config.add_route('order_items.view', '/order-items/{uuid}')
def test_common_add_note(self):
model = self.app.model
enum = self.app.enum
view = self.make_view()
self.pyramid_config.add_route(f'{view.get_route_prefix()}.view',
f'{view.get_url_prefix()}/{{uuid}}')
user = model.User(username='barney')
self.session.add(user)
@ -1429,11 +1434,12 @@ class TestOrderItemView(WebTestCase):
self.assertEqual(item.events[0].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
self.assertEqual(item.events[0].note, 'testing')
def test_change_status(self):
self.pyramid_config.add_route('order_items.view', '/order-items/{uuid}')
def test_common_change_status(self):
model = self.app.model
enum = self.app.enum
view = self.make_view()
self.pyramid_config.add_route(f'{view.get_route_prefix()}.view',
f'{view.get_url_prefix()}/{{uuid}}')
user = model.User(username='barney')
self.session.add(user)
@ -1459,7 +1465,7 @@ class TestOrderItemView(WebTestCase):
self.assertEqual(len(item.events), 1)
self.assertEqual(item.events[0].type_code, enum.ORDER_ITEM_EVENT_STATUS_CHANGE)
self.assertEqual(item.events[0].note,
"status changed from 'initiated' to 'placed'")
'status changed from "initiated" to "placed"')
# status change plus note
with patch.object(self.request, 'POST', new={
@ -1472,10 +1478,10 @@ class TestOrderItemView(WebTestCase):
self.assertEqual(len(item.events), 3)
self.assertEqual(item.events[0].type_code, enum.ORDER_ITEM_EVENT_STATUS_CHANGE)
self.assertEqual(item.events[0].note,
"status changed from 'initiated' to 'placed'")
'status changed from "initiated" to "placed"')
self.assertEqual(item.events[1].type_code, enum.ORDER_ITEM_EVENT_STATUS_CHANGE)
self.assertEqual(item.events[1].note,
"status changed from 'placed' to 'received'")
'status changed from "placed" to "received"')
self.assertEqual(item.events[2].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
self.assertEqual(item.events[2].note, "check it out")
@ -1486,3 +1492,510 @@ class TestOrderItemView(WebTestCase):
self.assertIsInstance(result, HTTPFound)
self.assertTrue(self.request.session.peek_flash('error'))
self.assertEqual(len(item.events), 3)
class TestOrderItemView(OrderItemViewTestMixin, WebTestCase):
def make_view(self):
return mod.OrderItemView(self.request)
def test_get_order_items(self):
model = self.app.model
enum = self.app.enum
view = self.make_view()
self.pyramid_config.add_route('order_items', '/order-items/')
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_READY)
order.items.append(item1)
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_READY)
order.items.append(item2)
self.session.add(order)
self.session.flush()
with patch.object(view, 'Session', return_value=self.session):
# no items found
self.assertRaises(HTTPFound, view.get_order_items, None)
self.assertRaises(HTTPFound, view.get_order_items, '')
self.assertRaises(HTTPFound, view.get_order_items, [])
self.assertRaises(HTTPFound, view.get_order_items, 'invalid')
# list of UUID
items = view.get_order_items([item1.uuid, item2.uuid])
self.assertEqual(len(items), 2)
self.assertIs(items[0], item1)
self.assertIs(items[1], item2)
# list of str
items = view.get_order_items([item1.uuid.hex, item2.uuid.hex])
self.assertEqual(len(items), 2)
self.assertIs(items[0], item1)
self.assertIs(items[1], item2)
# comma-delimited str
items = view.get_order_items(','.join([item1.uuid.hex, item2.uuid.hex]))
self.assertEqual(len(items), 2)
self.assertIs(items[0], item1)
self.assertIs(items[1], item2)
class TestPlacementView(OrderItemViewTestMixin, WebTestCase):
def make_view(self):
return mod.PlacementView(self.request)
def test_configure_grid(self):
model = self.app.model
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
# nothing added without perms
self.assertEqual(len(grid.tools), 0)
view.configure_grid(grid)
self.assertFalse(grid.checkable)
self.assertEqual(len(grid.tools), 0)
# button added with perm
with patch.object(self.request, 'is_root', new=True):
view.configure_grid(grid)
self.assertTrue(grid.checkable)
self.assertEqual(len(grid.tools), 1)
self.assertIn('process_placement', grid.tools)
tool = grid.tools['process_placement']
self.assertIn('<b-button ', tool)
self.assertIn('Order Placed', tool)
def test_process_placement(self):
self.pyramid_config.add_route('order_items_placement', '/placement/')
model = self.app.model
enum = self.app.enum
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_READY)
order.items.append(item1)
item2 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_READY)
order.items.append(item2)
item3 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_READY)
order.items.append(item3)
self.session.add(order)
self.session.flush()
# view only configured for POST
with patch.multiple(self.request, method='POST', user=user):
with patch.object(view, 'Session', return_value=self.session):
# redirect if items not specified
with patch.object(view.order_handler, 'process_placement') as process_placement:
self.assertRaises(HTTPFound, view.process_placement)
process_placement.assert_not_called()
self.assertTrue(self.request.session.pop_flash('warning'))
self.assertFalse(self.request.session.peek_flash())
# two items are updated
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_READY)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_READY)
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_READY)
self.assertEqual(len(item1.events), 0)
self.assertEqual(len(item2.events), 0)
self.assertEqual(len(item3.events), 0)
with patch.object(self.request, 'POST', new={
'item_uuids': ','.join([item1.uuid.hex, item2.uuid.hex]),
'vendor_name': 'Acme Dist',
'po_number': 'ACME123',
}):
view.process_placement()
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(item2.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(item3.status_code, enum.ORDER_ITEM_STATUS_READY)
self.assertEqual(len(item1.events), 1)
self.assertEqual(len(item2.events), 1)
self.assertEqual(len(item3.events), 0)
self.assertEqual(item1.events[0].note, "PO ACME123 for vendor Acme Dist")
self.assertEqual(item2.events[0].note, "PO ACME123 for vendor Acme Dist")
self.assertFalse(self.request.session.peek_flash('warning'))
self.assertTrue(self.request.session.pop_flash())
class TestReceivingView(OrderItemViewTestMixin, WebTestCase):
def make_view(self):
return mod.ReceivingView(self.request)
def test_configure_grid(self):
model = self.app.model
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
# nothing added without perms
self.assertEqual(len(grid.tools), 0)
view.configure_grid(grid)
self.assertFalse(grid.checkable)
self.assertEqual(len(grid.tools), 0)
# buttons added with perm
with patch.object(self.request, 'is_root', new=True):
view.configure_grid(grid)
self.assertEqual(len(grid.tools), 2)
self.assertTrue(grid.checkable)
self.assertIn('process_receiving', grid.tools)
tool = grid.tools['process_receiving']
self.assertIn('<b-button ', tool)
self.assertIn('Received', tool)
self.assertIn('process_reorder', grid.tools)
tool = grid.tools['process_reorder']
self.assertIn('<b-button ', tool)
self.assertIn('Re-Order', tool)
def test_process_receiving(self):
self.pyramid_config.add_route('order_items_receiving', '/receiving/')
model = self.app.model
enum = self.app.enum
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_PLACED)
order.items.append(item1)
self.session.add(order)
self.session.flush()
# view only configured for POST
with patch.multiple(self.request, method='POST', user=user):
with patch.object(view, 'Session', return_value=self.session):
# redirect if items not specified
with patch.object(view.order_handler, 'process_receiving') as process_receiving:
self.assertRaises(HTTPFound, view.process_receiving)
process_receiving.assert_not_called()
self.assertTrue(self.request.session.pop_flash('warning'))
self.assertFalse(self.request.session.peek_flash())
# all info provided
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(len(item1.events), 0)
with patch.object(self.request, 'POST', new={
'item_uuids': item1.uuid.hex,
'vendor_name': "Acme Dist",
'invoice_number': 'INV123',
'po_number': '123',
'note': 'extra note',
}):
view.process_receiving()
self.assertFalse(self.request.session.peek_flash('warning'))
self.assertTrue(self.request.session.pop_flash())
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item1.events), 2)
self.assertEqual(item1.events[0].note, "invoice INV123 (PO 123) from vendor Acme Dist")
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_RECEIVED)
self.assertEqual(item1.events[1].note, "extra note")
self.assertEqual(item1.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
def test_process_reorder(self):
self.pyramid_config.add_route('order_items_receiving', '/receiving/')
model = self.app.model
enum = self.app.enum
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_PLACED)
order.items.append(item1)
self.session.add(order)
self.session.flush()
# view only configured for POST
with patch.multiple(self.request, method='POST', user=user):
with patch.object(view, 'Session', return_value=self.session):
# redirect if items not specified
with patch.object(view.order_handler, 'process_reorder') as process_reorder:
self.assertRaises(HTTPFound, view.process_reorder)
process_reorder.assert_not_called()
self.assertTrue(self.request.session.pop_flash('warning'))
self.assertFalse(self.request.session.peek_flash())
# all info provided
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_PLACED)
self.assertEqual(len(item1.events), 0)
with patch.object(self.request, 'POST', new={
'item_uuids': item1.uuid.hex,
'note': 'extra note',
}):
view.process_reorder()
self.assertFalse(self.request.session.peek_flash('warning'))
self.assertTrue(self.request.session.pop_flash())
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_READY)
self.assertEqual(len(item1.events), 2)
self.assertIsNone(item1.events[0].note)
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_REORDER)
self.assertEqual(item1.events[1].note, "extra note")
self.assertEqual(item1.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
class TestContactView(OrderItemViewTestMixin, WebTestCase):
def make_view(self):
return mod.ContactView(self.request)
def test_configure_grid(self):
model = self.app.model
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
# nothing added without perms
self.assertEqual(len(grid.tools), 0)
view.configure_grid(grid)
self.assertFalse(grid.checkable)
self.assertEqual(len(grid.tools), 0)
# buttons added with perm
with patch.object(self.request, 'is_root', new=True):
view.configure_grid(grid)
self.assertEqual(len(grid.tools), 2)
self.assertTrue(grid.checkable)
self.assertIn('process_contact_success', grid.tools)
tool = grid.tools['process_contact_success']
self.assertIn('<b-button ', tool)
self.assertIn('Contact Success', tool)
self.assertIn('process_contact_failure', grid.tools)
tool = grid.tools['process_contact_failure']
self.assertIn('<b-button ', tool)
self.assertIn('Contact Failure', tool)
def test_process_contact_success(self):
self.pyramid_config.add_route('order_items_contact', '/contact/')
model = self.app.model
enum = self.app.enum
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item1)
self.session.add(order)
self.session.flush()
# view only configured for POST
with patch.multiple(self.request, method='POST', user=user):
with patch.object(view, 'Session', return_value=self.session):
# redirect if items not specified
with patch.object(view.order_handler, 'process_contact_success') as process_contact_success:
self.assertRaises(HTTPFound, view.process_contact_success)
process_contact_success.assert_not_called()
self.assertTrue(self.request.session.pop_flash('warning'))
self.assertFalse(self.request.session.peek_flash())
# all info provided
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item1.events), 0)
with patch.object(self.request, 'POST', new={
'item_uuids': item1.uuid.hex,
'note': 'extra note',
}):
view.process_contact_success()
self.assertFalse(self.request.session.peek_flash('warning'))
self.assertTrue(self.request.session.pop_flash())
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_CONTACTED)
self.assertEqual(len(item1.events), 2)
self.assertIsNone(item1.events[0].note)
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACTED)
self.assertEqual(item1.events[1].note, "extra note")
self.assertEqual(item1.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
def test_process_contact_failure(self):
self.pyramid_config.add_route('order_items_contact', '/contact/')
model = self.app.model
enum = self.app.enum
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_RECEIVED)
order.items.append(item1)
self.session.add(order)
self.session.flush()
# view only configured for POST
with patch.multiple(self.request, method='POST', user=user):
with patch.object(view, 'Session', return_value=self.session):
# redirect if items not specified
with patch.object(view.order_handler, 'process_contact_failure') as process_contact_failure:
self.assertRaises(HTTPFound, view.process_contact_failure)
process_contact_failure.assert_not_called()
self.assertTrue(self.request.session.pop_flash('warning'))
self.assertFalse(self.request.session.peek_flash())
# all info provided
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RECEIVED)
self.assertEqual(len(item1.events), 0)
with patch.object(self.request, 'POST', new={
'item_uuids': item1.uuid.hex,
'note': 'extra note',
}):
view.process_contact_failure()
self.assertFalse(self.request.session.peek_flash('warning'))
self.assertTrue(self.request.session.pop_flash())
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_CONTACT_FAILED)
self.assertEqual(len(item1.events), 2)
self.assertIsNone(item1.events[0].note)
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_CONTACT_FAILED)
self.assertEqual(item1.events[1].note, "extra note")
self.assertEqual(item1.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
class TestDeliveryView(OrderItemViewTestMixin, WebTestCase):
def make_view(self):
return mod.DeliveryView(self.request)
def test_configure_grid(self):
model = self.app.model
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
# nothing added without perms
self.assertEqual(len(grid.tools), 0)
view.configure_grid(grid)
self.assertFalse(grid.checkable)
self.assertEqual(len(grid.tools), 0)
# buttons added with perm
with patch.object(self.request, 'is_root', new=True):
view.configure_grid(grid)
self.assertEqual(len(grid.tools), 2)
self.assertTrue(grid.checkable)
self.assertIn('process_delivery', grid.tools)
tool = grid.tools['process_delivery']
self.assertIn('<b-button ', tool)
self.assertIn('Delivered', tool)
self.assertIn('process_restock', grid.tools)
tool = grid.tools['process_restock']
self.assertIn('<b-button ', tool)
self.assertIn('Restocked', tool)
def test_process_delivery(self):
self.pyramid_config.add_route('order_items_delivery', '/delivery/')
model = self.app.model
enum = self.app.enum
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_CONTACTED)
order.items.append(item1)
self.session.add(order)
self.session.flush()
# view only configured for POST
with patch.multiple(self.request, method='POST', user=user):
with patch.object(view, 'Session', return_value=self.session):
# redirect if items not specified
with patch.object(view.order_handler, 'process_delivery') as process_delivery:
self.assertRaises(HTTPFound, view.process_delivery)
process_delivery.assert_not_called()
self.assertTrue(self.request.session.pop_flash('warning'))
self.assertFalse(self.request.session.peek_flash())
# all info provided
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_CONTACTED)
self.assertEqual(len(item1.events), 0)
with patch.object(self.request, 'POST', new={
'item_uuids': item1.uuid.hex,
'note': 'extra note',
}):
view.process_delivery()
self.assertFalse(self.request.session.peek_flash('warning'))
self.assertTrue(self.request.session.pop_flash())
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_DELIVERED)
self.assertEqual(len(item1.events), 2)
self.assertIsNone(item1.events[0].note)
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_DELIVERED)
self.assertEqual(item1.events[1].note, "extra note")
self.assertEqual(item1.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)
def test_process_restock(self):
self.pyramid_config.add_route('order_items_delivery', '/delivery/')
model = self.app.model
enum = self.app.enum
view = self.make_view()
grid = view.make_grid(model_class=model.OrderItem)
# sample data
user = model.User(username='barney')
self.session.add(user)
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
item1 = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
status_code=enum.ORDER_ITEM_STATUS_CONTACTED)
order.items.append(item1)
self.session.add(order)
self.session.flush()
# view only configured for POST
with patch.multiple(self.request, method='POST', user=user):
with patch.object(view, 'Session', return_value=self.session):
# redirect if items not specified
with patch.object(view.order_handler, 'process_restock') as process_restock:
self.assertRaises(HTTPFound, view.process_restock)
process_restock.assert_not_called()
self.assertTrue(self.request.session.pop_flash('warning'))
self.assertFalse(self.request.session.peek_flash())
# all info provided
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_CONTACTED)
self.assertEqual(len(item1.events), 0)
with patch.object(self.request, 'POST', new={
'item_uuids': item1.uuid.hex,
'note': 'extra note',
}):
view.process_restock()
self.assertFalse(self.request.session.peek_flash('warning'))
self.assertTrue(self.request.session.pop_flash())
self.assertEqual(item1.status_code, enum.ORDER_ITEM_STATUS_RESTOCKED)
self.assertEqual(len(item1.events), 2)
self.assertIsNone(item1.events[0].note)
self.assertEqual(item1.events[0].type_code, enum.ORDER_ITEM_EVENT_RESTOCKED)
self.assertEqual(item1.events[1].note, "extra note")
self.assertEqual(item1.events[1].type_code, enum.ORDER_ITEM_EVENT_NOTE_ADDED)