1339 lines
58 KiB
Python
1339 lines
58 KiB
Python
# -*- coding: utf-8; -*-
|
|
|
|
import datetime
|
|
import decimal
|
|
from unittest.mock import patch
|
|
|
|
from sqlalchemy import orm
|
|
from pyramid.httpexceptions import HTTPForbidden, HTTPFound
|
|
from pyramid.response import Response
|
|
|
|
from wuttaweb.forms.schema import WuttaMoney
|
|
|
|
from sideshow.batch.neworder import NewOrderBatchHandler
|
|
from sideshow.testing import WebTestCase
|
|
from sideshow.web.views import orders as mod
|
|
from sideshow.web.forms.schema import OrderRef, PendingProductRef
|
|
|
|
|
|
class TestIncludeme(WebTestCase):
|
|
|
|
def test_coverage(self):
|
|
mod.includeme(self.pyramid_config)
|
|
|
|
|
|
class TestOrderView(WebTestCase):
|
|
|
|
def make_view(self):
|
|
return mod.OrderView(self.request)
|
|
|
|
def make_handler(self):
|
|
return NewOrderBatchHandler(self.config)
|
|
|
|
def test_configure_grid(self):
|
|
model = self.app.model
|
|
view = self.make_view()
|
|
grid = view.make_grid(model_class=model.PendingProduct)
|
|
self.assertNotIn('order_id', grid.linked_columns)
|
|
self.assertNotIn('total_price', grid.renderers)
|
|
view.configure_grid(grid)
|
|
self.assertIn('order_id', grid.linked_columns)
|
|
self.assertIn('total_price', grid.renderers)
|
|
|
|
def test_create(self):
|
|
self.pyramid_config.include('sideshow.web.views')
|
|
self.config.setdefault('wutta.batch.neworder.handler.spec',
|
|
'sideshow.batch.neworder:NewOrderBatchHandler')
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
self.session.flush()
|
|
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(self.request, 'current_route_url', return_value='/orders/new'):
|
|
|
|
# this will require some perms
|
|
with patch.multiple(self.request, create=True,
|
|
user=user, is_root=True):
|
|
|
|
# fetch page to start things off
|
|
self.assertEqual(self.session.query(model.NewOrderBatch).count(), 0)
|
|
response = view.create()
|
|
self.assertEqual(self.session.query(model.NewOrderBatch).count(), 1)
|
|
batch1 = self.session.query(model.NewOrderBatch).one()
|
|
|
|
# start over; deletes current batch
|
|
with patch.multiple(self.request, create=True,
|
|
method='POST',
|
|
POST={'action': 'start_over'}):
|
|
response = view.create()
|
|
self.assertIsInstance(response, HTTPFound)
|
|
self.assertIn('/orders/new', response.location)
|
|
self.assertEqual(self.session.query(model.NewOrderBatch).count(), 0)
|
|
|
|
# fetch again to get new batch
|
|
response = view.create()
|
|
self.assertEqual(self.session.query(model.NewOrderBatch).count(), 1)
|
|
batch2 = self.session.query(model.NewOrderBatch).one()
|
|
self.assertIsNot(batch2, batch1)
|
|
|
|
# set pending customer
|
|
with patch.multiple(self.request, create=True,
|
|
method='POST',
|
|
json_body={'action': 'set_pending_customer',
|
|
'first_name': 'Fred',
|
|
'last_name': 'Flintstone',
|
|
'phone_number': '555-1234',
|
|
'email_address': 'fred@mailinator.com'}):
|
|
response = view.create()
|
|
self.assertIsInstance(response, Response)
|
|
self.assertEqual(response.content_type, 'application/json')
|
|
self.assertEqual(response.json_body, {
|
|
'customer_is_known': False,
|
|
'customer_id': None,
|
|
'customer_name': 'Fred Flintstone',
|
|
'phone_number': '555-1234',
|
|
'email_address': 'fred@mailinator.com',
|
|
'new_customer_full_name': 'Fred Flintstone',
|
|
'new_customer_first_name': 'Fred',
|
|
'new_customer_last_name': 'Flintstone',
|
|
'new_customer_phone': '555-1234',
|
|
'new_customer_email': 'fred@mailinator.com',
|
|
})
|
|
|
|
# invalid action
|
|
with patch.multiple(self.request, create=True,
|
|
method='POST',
|
|
POST={'action': 'bogus'},
|
|
json_body={'action': 'bogus'}):
|
|
response = view.create()
|
|
self.assertIsInstance(response, Response)
|
|
self.assertEqual(response.content_type, 'application/json')
|
|
self.assertEqual(response.json_body, {'error': 'unknown form action'})
|
|
|
|
# add item
|
|
with patch.multiple(self.request, create=True,
|
|
method='POST',
|
|
json_body={'action': 'add_item',
|
|
'product_info': {
|
|
'scancode': '07430500132',
|
|
'description': 'Vinegar',
|
|
'unit_price_reg': 5.99,
|
|
},
|
|
'order_qty': 1,
|
|
'order_uom': enum.ORDER_UOM_UNIT}):
|
|
response = view.create()
|
|
self.assertIsInstance(response, Response)
|
|
self.assertEqual(response.content_type, 'application/json')
|
|
data = response.json_body
|
|
self.assertEqual(sorted(data), ['batch', 'row'])
|
|
|
|
# add item, w/ error
|
|
with patch.object(NewOrderBatchHandler, 'add_item', side_effect=RuntimeError):
|
|
with patch.multiple(self.request, create=True,
|
|
method='POST',
|
|
json_body={'action': 'add_item',
|
|
'product_info': {
|
|
'scancode': '07430500116',
|
|
'description': 'Vinegar',
|
|
'unit_price_reg': 3.59,
|
|
},
|
|
'order_qty': 1,
|
|
'order_uom': enum.ORDER_UOM_UNIT}):
|
|
response = view.create()
|
|
self.assertIsInstance(response, Response)
|
|
self.assertEqual(response.content_type, 'application/json')
|
|
self.assertEqual(response.json_body, {'error': 'RuntimeError'})
|
|
|
|
def test_get_current_batch(self):
|
|
model = self.app.model
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
# user is required
|
|
self.assertRaises(HTTPForbidden, view.get_current_batch)
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
self.session.commit()
|
|
|
|
with patch.object(view, 'batch_handler', create=True, new=handler):
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(self.request, 'user', new=user):
|
|
|
|
# batch is auto-created
|
|
self.assertEqual(self.session.query(model.NewOrderBatch).count(), 0)
|
|
batch = view.get_current_batch()
|
|
self.session.flush()
|
|
self.assertEqual(self.session.query(model.NewOrderBatch).count(), 1)
|
|
self.assertIs(batch.created_by, user)
|
|
|
|
# same batch is returned subsequently
|
|
batch2 = view.get_current_batch()
|
|
self.session.flush()
|
|
self.assertEqual(self.session.query(model.NewOrderBatch).count(), 1)
|
|
self.assertIs(batch2, batch)
|
|
|
|
def test_customer_autocomplete(self):
|
|
model = self.app.model
|
|
handler = self.make_handler()
|
|
view = self.make_view()
|
|
view.batch_handler = handler
|
|
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
|
|
# empty results by default
|
|
self.assertEqual(view.customer_autocomplete(), [])
|
|
with patch.object(self.request, 'GET', new={'term': 'foo'}, create=True):
|
|
self.assertEqual(view.customer_autocomplete(), [])
|
|
|
|
# add a customer
|
|
customer = model.LocalCustomer(full_name="Chuck Norris")
|
|
self.session.add(customer)
|
|
self.session.flush()
|
|
|
|
# search for chuck finds chuck
|
|
with patch.object(self.request, 'GET', new={'term': 'chuck'}, create=True):
|
|
result = view.customer_autocomplete()
|
|
self.assertEqual(len(result), 1)
|
|
self.assertEqual(result[0], {
|
|
'value': customer.uuid.hex,
|
|
'label': "Chuck Norris",
|
|
})
|
|
|
|
# search for sally finds nothing
|
|
with patch.object(self.request, 'GET', new={'term': 'sally'}, create=True):
|
|
result = view.customer_autocomplete()
|
|
self.assertEqual(result, [])
|
|
|
|
# external lookup not implemented by default
|
|
with patch.object(handler, 'use_local_customers', return_value=False):
|
|
with patch.object(self.request, 'GET', new={'term': 'sally'}, create=True):
|
|
self.assertRaises(NotImplementedError, view.customer_autocomplete)
|
|
|
|
def test_product_autocomplete(self):
|
|
model = self.app.model
|
|
handler = self.make_handler()
|
|
view = self.make_view()
|
|
view.batch_handler = handler
|
|
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
|
|
# empty results by default
|
|
self.assertEqual(view.product_autocomplete(), [])
|
|
with patch.object(self.request, 'GET', new={'term': 'foo'}, create=True):
|
|
self.assertEqual(view.product_autocomplete(), [])
|
|
|
|
# add a product
|
|
product = model.LocalProduct(brand_name="Bragg's", description="Vinegar")
|
|
self.session.add(product)
|
|
self.session.flush()
|
|
|
|
# search for vinegar finds product
|
|
with patch.object(self.request, 'GET', new={'term': 'vinegar'}, create=True):
|
|
result = view.product_autocomplete()
|
|
self.assertEqual(len(result), 1)
|
|
self.assertEqual(result[0], {
|
|
'value': product.uuid.hex,
|
|
'label': "Bragg's Vinegar",
|
|
})
|
|
|
|
# search for brag finds product
|
|
with patch.object(self.request, 'GET', new={'term': 'brag'}, create=True):
|
|
result = view.product_autocomplete()
|
|
self.assertEqual(len(result), 1)
|
|
self.assertEqual(result[0], {
|
|
'value': product.uuid.hex,
|
|
'label': "Bragg's Vinegar",
|
|
})
|
|
|
|
# search for juice finds nothing
|
|
with patch.object(self.request, 'GET', new={'term': 'juice'}, create=True):
|
|
result = view.product_autocomplete()
|
|
self.assertEqual(result, [])
|
|
|
|
# external lookup not implemented by default
|
|
with patch.object(handler, 'use_local_products', return_value=False):
|
|
with patch.object(self.request, 'GET', new={'term': 'juice'}, create=True):
|
|
self.assertRaises(NotImplementedError, view.product_autocomplete)
|
|
|
|
def test_get_pending_product_required_fields(self):
|
|
model = self.app.model
|
|
view = self.make_view()
|
|
|
|
# only description is required by default
|
|
fields = view.get_pending_product_required_fields()
|
|
self.assertEqual(fields, ['description'])
|
|
|
|
# but config can specify otherwise
|
|
self.config.setdefault('sideshow.orders.unknown_product.fields.brand_name.required', 'true')
|
|
self.config.setdefault('sideshow.orders.unknown_product.fields.description.required', 'false')
|
|
self.config.setdefault('sideshow.orders.unknown_product.fields.size.required', 'true')
|
|
self.config.setdefault('sideshow.orders.unknown_product.fields.unit_price_reg.required', 'true')
|
|
fields = view.get_pending_product_required_fields()
|
|
self.assertEqual(fields, ['brand_name', 'size', 'unit_price_reg'])
|
|
|
|
def test_get_context_customer(self):
|
|
self.pyramid_config.add_route('orders', '/orders/')
|
|
model = self.app.model
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
view.batch_handler = handler
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
|
|
# with external customer
|
|
with patch.object(handler, 'use_local_customers', return_value=False):
|
|
batch = handler.make_batch(self.session, created_by=user,
|
|
customer_id=42, customer_name='Fred Flintstone',
|
|
phone_number='555-1234', email_address='fred@mailinator.com')
|
|
self.session.add(batch)
|
|
self.session.flush()
|
|
context = view.get_context_customer(batch)
|
|
self.assertEqual(context, {
|
|
'customer_is_known': True,
|
|
'customer_id': 42,
|
|
'customer_name': 'Fred Flintstone',
|
|
'phone_number': '555-1234',
|
|
'email_address': 'fred@mailinator.com',
|
|
})
|
|
|
|
# with local customer
|
|
local = model.LocalCustomer(full_name="Betty Boop")
|
|
self.session.add(local)
|
|
batch = handler.make_batch(self.session, created_by=user,
|
|
local_customer=local, customer_name='Betty Boop',
|
|
phone_number='555-8888')
|
|
self.session.add(batch)
|
|
self.session.flush()
|
|
context = view.get_context_customer(batch)
|
|
self.assertEqual(context, {
|
|
'customer_is_known': True,
|
|
'customer_id': local.uuid.hex,
|
|
'customer_name': 'Betty Boop',
|
|
'phone_number': '555-8888',
|
|
'email_address': None,
|
|
})
|
|
|
|
# with pending customer
|
|
batch = handler.make_batch(self.session, created_by=user)
|
|
self.session.add(batch)
|
|
handler.set_customer(batch, dict(
|
|
full_name="Fred Flintstone",
|
|
first_name="Fred", last_name="Flintstone",
|
|
phone_number='555-1234', email_address='fred@mailinator.com',
|
|
))
|
|
self.session.flush()
|
|
context = view.get_context_customer(batch)
|
|
self.assertEqual(context, {
|
|
'customer_is_known': False,
|
|
'customer_id': None,
|
|
'customer_name': 'Fred Flintstone',
|
|
'phone_number': '555-1234',
|
|
'email_address': 'fred@mailinator.com',
|
|
'new_customer_full_name': 'Fred Flintstone',
|
|
'new_customer_first_name': 'Fred',
|
|
'new_customer_last_name': 'Flintstone',
|
|
'new_customer_phone': '555-1234',
|
|
'new_customer_email': 'fred@mailinator.com',
|
|
})
|
|
|
|
# with no customer
|
|
batch = handler.make_batch(self.session, created_by=user)
|
|
self.session.add(batch)
|
|
self.session.flush()
|
|
context = view.get_context_customer(batch)
|
|
self.assertEqual(context, {
|
|
'customer_is_known': True, # nb. this is for UI default
|
|
'customer_id': None,
|
|
'customer_name': None,
|
|
'phone_number': None,
|
|
'email_address': None,
|
|
})
|
|
|
|
def test_start_over(self):
|
|
self.pyramid_config.add_route('orders.create', '/orders/new')
|
|
model = self.app.model
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
self.session.commit()
|
|
|
|
with patch.object(view, 'batch_handler', create=True, new=handler):
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(self.request, 'user', new=user):
|
|
|
|
batch = view.get_current_batch()
|
|
self.session.flush()
|
|
self.assertEqual(self.session.query(model.NewOrderBatch).count(), 1)
|
|
result = view.start_over(batch)
|
|
self.assertIsInstance(result, HTTPFound)
|
|
self.session.flush()
|
|
self.assertEqual(self.session.query(model.NewOrderBatch).count(), 0)
|
|
|
|
def test_cancel_order(self):
|
|
self.pyramid_config.add_route('orders', '/orders/')
|
|
model = self.app.model
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
self.session.commit()
|
|
|
|
with patch.object(view, 'batch_handler', create=True, new=handler):
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(self.request, 'user', new=user):
|
|
|
|
batch = view.get_current_batch()
|
|
self.session.flush()
|
|
self.assertEqual(self.session.query(model.NewOrderBatch).count(), 1)
|
|
result = view.cancel_order(batch)
|
|
self.assertIsInstance(result, HTTPFound)
|
|
self.session.flush()
|
|
self.assertEqual(self.session.query(model.NewOrderBatch).count(), 0)
|
|
|
|
def test_assign_customer(self):
|
|
self.pyramid_config.add_route('orders.create', '/orders/new')
|
|
model = self.app.model
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
weirdal = model.LocalCustomer(full_name="Weird Al")
|
|
self.session.add(weirdal)
|
|
self.session.flush()
|
|
|
|
with patch.object(view, 'batch_handler', create=True, new=handler):
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(self.request, 'user', new=user):
|
|
batch = view.get_current_batch()
|
|
|
|
# normal
|
|
self.assertIsNone(batch.local_customer)
|
|
self.assertIsNone(batch.pending_customer)
|
|
context = view.assign_customer(batch, {'customer_id': weirdal.uuid.hex})
|
|
self.assertIsNone(batch.pending_customer)
|
|
self.assertIs(batch.local_customer, weirdal)
|
|
self.assertEqual(context, {
|
|
'customer_is_known': True,
|
|
'customer_id': weirdal.uuid.hex,
|
|
'customer_name': 'Weird Al',
|
|
'phone_number': None,
|
|
'email_address': None,
|
|
})
|
|
|
|
# missing customer_id
|
|
context = view.assign_customer(batch, {})
|
|
self.assertEqual(context, {'error': "Must provide customer_id"})
|
|
|
|
def test_unassign_customer(self):
|
|
self.pyramid_config.add_route('orders.create', '/orders/new')
|
|
model = self.app.model
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
self.session.flush()
|
|
|
|
with patch.object(view, 'batch_handler', create=True, new=handler):
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(self.request, 'user', new=user):
|
|
batch = view.get_current_batch()
|
|
view.set_pending_customer(batch, {'first_name': 'Jack',
|
|
'last_name': 'Black'})
|
|
|
|
# normal
|
|
self.assertIsNone(batch.local_customer)
|
|
self.assertIsNotNone(batch.pending_customer)
|
|
self.assertEqual(batch.customer_name, 'Jack Black')
|
|
context = view.unassign_customer(batch, {})
|
|
# nb. pending record remains, but not used
|
|
self.assertIsNotNone(batch.pending_customer)
|
|
self.assertIsNone(batch.customer_name)
|
|
self.assertIsNone(batch.local_customer)
|
|
self.assertEqual(context, {
|
|
'customer_is_known': True,
|
|
'customer_id': None,
|
|
'customer_name': None,
|
|
'phone_number': None,
|
|
'email_address': None,
|
|
'new_customer_full_name': 'Jack Black',
|
|
'new_customer_first_name': 'Jack',
|
|
'new_customer_last_name': 'Black',
|
|
'new_customer_phone': None,
|
|
'new_customer_email': None,
|
|
})
|
|
|
|
def test_set_pending_customer(self):
|
|
self.pyramid_config.add_route('orders.create', '/orders/new')
|
|
model = self.app.model
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
self.session.commit()
|
|
|
|
data = {
|
|
'first_name': 'Fred',
|
|
'last_name': 'Flintstone',
|
|
'phone_number': '555-1234',
|
|
'email_address': 'fred@mailinator.com',
|
|
}
|
|
|
|
with patch.object(view, 'batch_handler', create=True, new=handler):
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(self.request, 'user', new=user):
|
|
batch = view.get_current_batch()
|
|
self.session.flush()
|
|
|
|
# normal
|
|
self.assertIsNone(batch.pending_customer)
|
|
context = view.set_pending_customer(batch, data)
|
|
self.assertIsInstance(batch.pending_customer, model.PendingCustomer)
|
|
self.assertEqual(context, {
|
|
'customer_is_known': False,
|
|
'customer_id': None,
|
|
'customer_name': 'Fred Flintstone',
|
|
'phone_number': '555-1234',
|
|
'email_address': 'fred@mailinator.com',
|
|
'new_customer_full_name': 'Fred Flintstone',
|
|
'new_customer_first_name': 'Fred',
|
|
'new_customer_last_name': 'Flintstone',
|
|
'new_customer_phone': '555-1234',
|
|
'new_customer_email': 'fred@mailinator.com',
|
|
})
|
|
|
|
def test_get_product_info(self):
|
|
model = self.app.model
|
|
handler = self.make_handler()
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
local = model.LocalProduct(scancode='07430500132',
|
|
brand_name='Bragg',
|
|
description='Vinegar',
|
|
size='32oz',
|
|
case_size=12,
|
|
unit_price_reg=decimal.Decimal('5.99'))
|
|
self.session.add(local)
|
|
self.session.flush()
|
|
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(view, 'batch_handler', create=True, new=handler):
|
|
with patch.object(self.request, 'user', new=user):
|
|
batch = view.get_current_batch()
|
|
|
|
# typical, for local product
|
|
context = view.get_product_info(batch, {'product_id': local.uuid.hex})
|
|
self.assertEqual(context['product_id'], local.uuid.hex)
|
|
self.assertEqual(context['scancode'], '07430500132')
|
|
self.assertEqual(context['brand_name'], 'Bragg')
|
|
self.assertEqual(context['description'], 'Vinegar')
|
|
self.assertEqual(context['size'], '32oz')
|
|
self.assertEqual(context['full_description'], 'Bragg Vinegar 32oz')
|
|
self.assertEqual(context['case_size'], 12)
|
|
self.assertEqual(context['unit_price_reg'], 5.99)
|
|
|
|
# error if no product_id
|
|
context = view.get_product_info(batch, {})
|
|
self.assertEqual(context, {'error': "Must specify a product ID"})
|
|
|
|
# error if product not found
|
|
mock_uuid = self.app.make_true_uuid()
|
|
self.assertRaises(ValueError, view.get_product_info,
|
|
batch, {'product_id': mock_uuid.hex})
|
|
|
|
with patch.object(handler, 'use_local_products', return_value=False):
|
|
|
|
# external lookup not implemented by default
|
|
self.assertRaises(NotImplementedError, view.get_product_info,
|
|
batch, {'product_id': '42'})
|
|
|
|
# external lookup may return its own error
|
|
with patch.object(handler, 'get_product_info_external',
|
|
return_value={'error': "something smells fishy"}):
|
|
context = view.get_product_info(batch, {'product_id': '42'})
|
|
self.assertEqual(context, {'error': "something smells fishy"})
|
|
|
|
def test_add_item(self):
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
self.session.commit()
|
|
|
|
data = {
|
|
'product_info': {
|
|
'scancode': '07430500132',
|
|
'brand_name': 'Bragg',
|
|
'description': 'Vinegar',
|
|
'size': '32oz',
|
|
'unit_price_reg': 5.99,
|
|
},
|
|
'order_qty': 1,
|
|
'order_uom': enum.ORDER_UOM_UNIT,
|
|
}
|
|
|
|
with patch.object(view, 'batch_handler', create=True, new=handler):
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(self.request, 'user', new=user):
|
|
batch = view.get_current_batch()
|
|
self.session.flush()
|
|
self.assertEqual(len(batch.rows), 0)
|
|
|
|
# normal pending product
|
|
result = view.add_item(batch, data)
|
|
self.assertIn('batch', result)
|
|
self.assertIn('row', result)
|
|
self.session.flush()
|
|
self.assertEqual(len(batch.rows), 1)
|
|
row = batch.rows[0]
|
|
self.assertIsInstance(row.pending_product, model.PendingProduct)
|
|
|
|
# external product not yet supported
|
|
with patch.object(handler, 'use_local_products', return_value=False):
|
|
with patch.dict(data, product_info='42'):
|
|
self.assertRaises(NotImplementedError, view.add_item, batch, data)
|
|
|
|
def test_update_item(self):
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
self.session.commit()
|
|
|
|
data = {
|
|
'product_info': {
|
|
'scancode': '07430500132',
|
|
'brand_name': 'Bragg',
|
|
'description': 'Vinegar',
|
|
'size': '32oz',
|
|
'unit_price_reg': 5.99,
|
|
'case_size': 12,
|
|
},
|
|
'order_qty': 1,
|
|
'order_uom': enum.ORDER_UOM_CASE,
|
|
}
|
|
|
|
with patch.object(view, 'batch_handler', create=True, new=handler):
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(self.request, 'user', new=user):
|
|
batch = view.get_current_batch()
|
|
self.session.flush()
|
|
self.assertEqual(len(batch.rows), 0)
|
|
|
|
# add row w/ pending product
|
|
view.add_item(batch, data)
|
|
self.session.flush()
|
|
row = batch.rows[0]
|
|
self.assertIsInstance(row.pending_product, model.PendingProduct)
|
|
self.assertEqual(row.unit_price_quoted, decimal.Decimal('5.99'))
|
|
|
|
# missing row uuid
|
|
result = view.update_item(batch, data)
|
|
self.assertEqual(result, {'error': "Must specify row UUID"})
|
|
|
|
# row not found
|
|
with patch.dict(data, uuid=self.app.make_true_uuid()):
|
|
result = view.update_item(batch, data)
|
|
self.assertEqual(result, {'error': "Row not found"})
|
|
|
|
# row for wrong batch
|
|
batch2 = handler.make_batch(self.session, created_by=user)
|
|
self.session.add(batch2)
|
|
row2 = handler.make_row(order_qty=1, order_uom=enum.ORDER_UOM_UNIT)
|
|
handler.add_row(batch2, row2)
|
|
self.session.flush()
|
|
with patch.dict(data, uuid=row2.uuid):
|
|
result = view.update_item(batch, data)
|
|
self.assertEqual(result, {'error': "Row is for wrong batch"})
|
|
|
|
# true product not yet supported
|
|
with patch.object(handler, 'use_local_products', return_value=False):
|
|
self.assertRaises(NotImplementedError, view.update_item, batch, {
|
|
'uuid': row.uuid,
|
|
'product_info': '42',
|
|
'order_qty': 1,
|
|
'order_uom': enum.ORDER_UOM_UNIT,
|
|
})
|
|
|
|
# update row, pending product
|
|
with patch.dict(data, uuid=row.uuid, order_qty=2):
|
|
with patch.dict(data['product_info'], scancode='07430500116'):
|
|
self.assertEqual(row.product_scancode, '07430500132')
|
|
self.assertEqual(row.order_qty, 1)
|
|
result = view.update_item(batch, data)
|
|
self.assertEqual(sorted(result), ['batch', 'row'])
|
|
self.assertEqual(row.product_scancode, '07430500116')
|
|
self.assertEqual(row.order_qty, 2)
|
|
self.assertEqual(row.pending_product.scancode, '07430500116')
|
|
self.assertEqual(result['row']['product_scancode'], '07430500116')
|
|
self.assertEqual(result['row']['order_qty'], 2)
|
|
|
|
def test_delete_item(self):
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
self.session.commit()
|
|
|
|
data = {
|
|
'product_info': {
|
|
'scancode': '07430500132',
|
|
'brand_name': 'Bragg',
|
|
'description': 'Vinegar',
|
|
'size': '32oz',
|
|
'unit_price_reg': 5.99,
|
|
'case_size': 12,
|
|
},
|
|
'order_qty': 1,
|
|
'order_uom': enum.ORDER_UOM_CASE,
|
|
}
|
|
|
|
with patch.object(view, 'batch_handler', create=True, new=handler):
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(self.request, 'user', new=user):
|
|
batch = view.get_current_batch()
|
|
self.session.flush()
|
|
self.assertEqual(len(batch.rows), 0)
|
|
|
|
# add row w/ pending product
|
|
view.add_item(batch, data)
|
|
self.session.flush()
|
|
row = batch.rows[0]
|
|
self.assertIsInstance(row.pending_product, model.PendingProduct)
|
|
self.assertEqual(row.unit_price_quoted, decimal.Decimal('5.99'))
|
|
|
|
# missing row uuid
|
|
result = view.delete_item(batch, data)
|
|
self.assertEqual(result, {'error': "Must specify a row UUID"})
|
|
|
|
# row not found
|
|
with patch.dict(data, uuid=self.app.make_true_uuid()):
|
|
result = view.delete_item(batch, data)
|
|
self.assertEqual(result, {'error': "Row not found"})
|
|
|
|
# row for wrong batch
|
|
batch2 = handler.make_batch(self.session, created_by=user)
|
|
self.session.add(batch2)
|
|
row2 = handler.make_row(order_qty=1, order_uom=enum.ORDER_UOM_UNIT)
|
|
handler.add_row(batch2, row2)
|
|
self.session.flush()
|
|
with patch.dict(data, uuid=row2.uuid):
|
|
result = view.delete_item(batch, data)
|
|
self.assertEqual(result, {'error': "Row is for wrong batch"})
|
|
|
|
# row is deleted
|
|
data['uuid'] = row.uuid
|
|
self.assertEqual(len(batch.rows), 1)
|
|
self.assertEqual(batch.row_count, 1)
|
|
result = view.delete_item(batch, data)
|
|
self.assertEqual(sorted(result), ['batch'])
|
|
self.session.refresh(batch)
|
|
self.assertEqual(len(batch.rows), 0)
|
|
self.assertEqual(batch.row_count, 0)
|
|
|
|
def test_submit_order(self):
|
|
self.pyramid_config.add_route('orders.view', '/orders/{uuid}')
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
self.session.commit()
|
|
|
|
data = {
|
|
'product_info': {
|
|
'scancode': '07430500132',
|
|
'brand_name': 'Bragg',
|
|
'description': 'Vinegar',
|
|
'size': '32oz',
|
|
'unit_price_reg': 5.99,
|
|
'case_size': 12,
|
|
},
|
|
'order_qty': 1,
|
|
'order_uom': enum.ORDER_UOM_CASE,
|
|
}
|
|
|
|
with patch.object(view, 'batch_handler', create=True, new=handler):
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.object(self.request, 'user', new=user):
|
|
batch = view.get_current_batch()
|
|
self.assertEqual(len(batch.rows), 0)
|
|
|
|
# add row w/ pending product
|
|
view.add_item(batch, data)
|
|
self.assertEqual(len(batch.rows), 1)
|
|
row = batch.rows[0]
|
|
self.assertIsInstance(row.pending_product, model.PendingProduct)
|
|
self.assertEqual(row.unit_price_quoted, decimal.Decimal('5.99'))
|
|
|
|
# execute not allowed yet (no customer)
|
|
result = view.submit_order(batch, {})
|
|
self.assertEqual(result, {'error': "Must assign the customer"})
|
|
|
|
# execute not allowed yet (no phone number)
|
|
view.set_pending_customer(batch, {'full_name': 'John Doe'})
|
|
result = view.submit_order(batch, {})
|
|
self.assertEqual(result, {'error': "Customer phone number is required"})
|
|
|
|
# submit/execute ok
|
|
view.set_pending_customer(batch, {'full_name': 'John Doe',
|
|
'phone_number': '555-1234'})
|
|
result = view.submit_order(batch, {})
|
|
self.assertEqual(sorted(result), ['next_url'])
|
|
self.assertIn('/orders/', result['next_url'])
|
|
|
|
# error (already executed)
|
|
result = view.submit_order(batch, {})
|
|
self.assertEqual(result, {
|
|
'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
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
batch = handler.make_batch(self.session, created_by=user)
|
|
self.session.add(batch)
|
|
pending = {
|
|
'scancode': '07430500132',
|
|
'brand_name': 'Bragg',
|
|
'description': 'Vinegar',
|
|
'size': '32oz',
|
|
'unit_price_reg': 5.99,
|
|
'case_size': 12,
|
|
}
|
|
row = handler.add_item(batch, pending, 1, enum.ORDER_UOM_CASE)
|
|
self.session.commit()
|
|
|
|
data = view.normalize_batch(batch)
|
|
self.assertEqual(data, {
|
|
'uuid': batch.uuid.hex,
|
|
'total_price': '71.880',
|
|
'total_price_display': '$71.88',
|
|
'status_code': None,
|
|
'status_text': None,
|
|
})
|
|
|
|
def test_normalize_row(self):
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
view.batch_handler = 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()
|
|
|
|
# add 1st row w/ pending product
|
|
pending = {
|
|
'scancode': '07430500132',
|
|
'brand_name': 'Bragg',
|
|
'description': 'Vinegar',
|
|
'size': '32oz',
|
|
'unit_price_reg': 5.99,
|
|
'case_size': 12,
|
|
'vendor_name': 'Acme Warehouse',
|
|
'vendor_item_code': '1234',
|
|
}
|
|
row1 = handler.add_item(batch, pending, 2, enum.ORDER_UOM_CASE)
|
|
|
|
# typical, pending product
|
|
data = view.normalize_row(row1)
|
|
self.assertIsInstance(data, dict)
|
|
self.assertEqual(data['uuid'], row1.uuid.hex)
|
|
self.assertEqual(data['sequence'], 1)
|
|
self.assertIsNone(data['product_id'])
|
|
self.assertEqual(data['product_scancode'], '07430500132')
|
|
self.assertEqual(data['product_full_description'], 'Bragg Vinegar 32oz')
|
|
self.assertEqual(data['case_size'], 12)
|
|
self.assertEqual(data['vendor_name'], 'Acme Warehouse')
|
|
self.assertEqual(data['order_qty'], 2)
|
|
self.assertEqual(data['order_uom'], 'CS')
|
|
self.assertEqual(data['order_qty_display'], '2 Cases (× 12 = 24 Units)')
|
|
self.assertEqual(data['unit_price_reg'], 5.99)
|
|
self.assertEqual(data['unit_price_reg_display'], '$5.99')
|
|
self.assertNotIn('unit_price_sale', data)
|
|
self.assertNotIn('unit_price_sale_display', data)
|
|
self.assertNotIn('sale_ends', data)
|
|
self.assertNotIn('sale_ends_display', data)
|
|
self.assertEqual(data['unit_price_quoted'], 5.99)
|
|
self.assertEqual(data['unit_price_quoted_display'], '$5.99')
|
|
self.assertEqual(data['case_price_quoted'], 71.88)
|
|
self.assertEqual(data['case_price_quoted_display'], '$71.88')
|
|
self.assertEqual(data['total_price'], 143.76)
|
|
self.assertEqual(data['total_price_display'], '$143.76')
|
|
self.assertIsNone(data['special_order'])
|
|
self.assertEqual(data['status_code'], row1.STATUS_OK)
|
|
self.assertEqual(data['pending_product'], {
|
|
'uuid': row1.pending_product_uuid.hex,
|
|
'scancode': '07430500132',
|
|
'brand_name': 'Bragg',
|
|
'description': 'Vinegar',
|
|
'size': '32oz',
|
|
'department_id': None,
|
|
'department_name': None,
|
|
'unit_price_reg': 5.99,
|
|
'vendor_name': 'Acme Warehouse',
|
|
'vendor_item_code': '1234',
|
|
'unit_cost': None,
|
|
'case_size': 12.0,
|
|
'notes': None,
|
|
'special_order': None,
|
|
})
|
|
|
|
# the next few tests will morph 1st row..
|
|
|
|
# unknown case size
|
|
row1.pending_product.case_size = None
|
|
handler.refresh_row(row1)
|
|
self.session.flush()
|
|
data = view.normalize_row(row1)
|
|
self.assertIsNone(data['case_size'])
|
|
self.assertEqual(data['order_qty_display'], '2 Cases (× ?? = ?? Units)')
|
|
|
|
# order by unit
|
|
row1.order_uom = enum.ORDER_UOM_UNIT
|
|
handler.refresh_row(row1)
|
|
self.session.flush()
|
|
data = view.normalize_row(row1)
|
|
self.assertEqual(data['order_uom'], enum.ORDER_UOM_UNIT)
|
|
self.assertEqual(data['order_qty_display'], '2 Units')
|
|
|
|
# item on sale
|
|
row1.pending_product.case_size = 12
|
|
row1.unit_price_sale = decimal.Decimal('5.19')
|
|
row1.sale_ends = datetime.datetime(2099, 1, 5, 20, 32)
|
|
handler.refresh_row(row1)
|
|
self.session.flush()
|
|
data = view.normalize_row(row1)
|
|
self.assertEqual(data['unit_price_sale'], 5.19)
|
|
self.assertEqual(data['unit_price_sale_display'], '$5.19')
|
|
self.assertEqual(data['sale_ends'], '2099-01-05 20:32:00')
|
|
self.assertEqual(data['sale_ends_display'], '2099-01-05')
|
|
self.assertEqual(data['unit_price_quoted'], 5.19)
|
|
self.assertEqual(data['unit_price_quoted_display'], '$5.19')
|
|
self.assertEqual(data['case_price_quoted'], 62.28)
|
|
self.assertEqual(data['case_price_quoted_display'], '$62.28')
|
|
|
|
# add 2nd row w/ local product
|
|
local = model.LocalProduct(brand_name="Lay's",
|
|
description="Potato Chips",
|
|
vendor_name='Acme Distribution',
|
|
unit_price_reg=3.29)
|
|
self.session.add(local)
|
|
self.session.flush()
|
|
row2 = handler.add_item(batch, local.uuid.hex, 1, enum.ORDER_UOM_UNIT)
|
|
|
|
# typical, local product
|
|
data = view.normalize_row(row2)
|
|
self.assertEqual(data['uuid'], row2.uuid.hex)
|
|
self.assertEqual(data['sequence'], 2)
|
|
self.assertEqual(data['product_id'], local.uuid.hex)
|
|
self.assertIsNone(data['product_scancode'])
|
|
self.assertEqual(data['product_full_description'], "Lay's Potato Chips")
|
|
self.assertIsNone(data['case_size'])
|
|
self.assertEqual(data['vendor_name'], 'Acme Distribution')
|
|
self.assertEqual(data['order_qty'], 1)
|
|
self.assertEqual(data['order_uom'], 'EA')
|
|
self.assertEqual(data['order_qty_display'], '1 Units')
|
|
self.assertEqual(data['unit_price_reg'], 3.29)
|
|
self.assertEqual(data['unit_price_reg_display'], '$3.29')
|
|
self.assertNotIn('unit_price_sale', data)
|
|
self.assertNotIn('unit_price_sale_display', data)
|
|
self.assertNotIn('sale_ends', data)
|
|
self.assertNotIn('sale_ends_display', data)
|
|
self.assertEqual(data['unit_price_quoted'], 3.29)
|
|
self.assertEqual(data['unit_price_quoted_display'], '$3.29')
|
|
self.assertIsNone(data['case_price_quoted'])
|
|
self.assertEqual(data['case_price_quoted_display'], '')
|
|
self.assertEqual(data['total_price'], 3.29)
|
|
self.assertEqual(data['total_price_display'], '$3.29')
|
|
self.assertIsNone(data['special_order'])
|
|
self.assertEqual(data['status_code'], row2.STATUS_OK)
|
|
self.assertNotIn('pending_product', data)
|
|
|
|
# the next few tests will morph 2nd row..
|
|
|
|
def refresh_external(row):
|
|
row.product_scancode = '012345'
|
|
row.product_brand = 'Acme'
|
|
row.product_description = 'Bricks'
|
|
row.product_size = '1 ton'
|
|
row.product_weighed = True
|
|
row.department_id = 1
|
|
row.department_name = "Bricks & Mortar"
|
|
row.special_order = False
|
|
row.case_size = None
|
|
row.unit_cost = decimal.Decimal('599.99')
|
|
row.unit_price_reg = decimal.Decimal('999.99')
|
|
|
|
# typical, external product
|
|
with patch.object(handler, 'use_local_products', return_value=False):
|
|
with patch.object(handler, 'refresh_row_from_external_product', new=refresh_external):
|
|
handler.update_item(row2, '42', 1, enum.ORDER_UOM_UNIT)
|
|
data = view.normalize_row(row2)
|
|
self.assertEqual(data['uuid'], row2.uuid.hex)
|
|
self.assertEqual(data['sequence'], 2)
|
|
self.assertEqual(data['product_id'], '42')
|
|
self.assertEqual(data['product_scancode'], '012345')
|
|
self.assertEqual(data['product_full_description'], 'Acme Bricks 1 ton')
|
|
self.assertIsNone(data['case_size'])
|
|
self.assertNotIn('vendor_name', data) # TODO
|
|
self.assertEqual(data['order_qty'], 1)
|
|
self.assertEqual(data['order_uom'], 'EA')
|
|
self.assertEqual(data['order_qty_display'], '1 Units')
|
|
self.assertEqual(data['unit_price_reg'], 999.99)
|
|
self.assertEqual(data['unit_price_reg_display'], '$999.99')
|
|
self.assertNotIn('unit_price_sale', data)
|
|
self.assertNotIn('unit_price_sale_display', data)
|
|
self.assertNotIn('sale_ends', data)
|
|
self.assertNotIn('sale_ends_display', data)
|
|
self.assertEqual(data['unit_price_quoted'], 999.99)
|
|
self.assertEqual(data['unit_price_quoted_display'], '$999.99')
|
|
self.assertIsNone(data['case_price_quoted'])
|
|
self.assertEqual(data['case_price_quoted_display'], '')
|
|
self.assertEqual(data['total_price'], 999.99)
|
|
self.assertEqual(data['total_price_display'], '$999.99')
|
|
self.assertFalse(data['special_order'])
|
|
self.assertEqual(data['status_code'], row2.STATUS_OK)
|
|
self.assertNotIn('pending_product', data)
|
|
|
|
def test_get_instance_title(self):
|
|
model = self.app.model
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
order = model.Order(order_id=42, customer_name="Fred Flintstone", created_by=user)
|
|
self.session.add(order)
|
|
self.session.flush()
|
|
|
|
title = view.get_instance_title(order)
|
|
self.assertEqual(title, "#42 for Fred Flintstone")
|
|
|
|
def test_configure_form(self):
|
|
model = self.app.model
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
order = model.Order(order_id=42, created_by=user)
|
|
self.session.add(order)
|
|
self.session.commit()
|
|
|
|
# viewing (no customer)
|
|
with patch.object(view, 'viewing', new=True):
|
|
form = view.make_form(model_instance=order)
|
|
# nb. this is to avoid include/exclude ambiguity
|
|
form.remove('items')
|
|
view.configure_form(form)
|
|
schema = form.get_schema()
|
|
self.assertIn('pending_customer', form)
|
|
self.assertIsInstance(schema['total_price'].typ, WuttaMoney)
|
|
|
|
# assign local customer
|
|
local = model.LocalCustomer(first_name='Jack', last_name='Black',
|
|
phone_number='555-1234')
|
|
self.session.add(local)
|
|
self.session.flush()
|
|
|
|
# viewing (local customer)
|
|
with patch.object(view, 'viewing', new=True):
|
|
with patch.object(order, 'local_customer', new=local):
|
|
form = view.make_form(model_instance=order)
|
|
# nb. this is to avoid include/exclude ambiguity
|
|
form.remove('items')
|
|
view.configure_form(form)
|
|
self.assertNotIn('pending_customer', form)
|
|
schema = form.get_schema()
|
|
self.assertIsInstance(schema['total_price'].typ, WuttaMoney)
|
|
|
|
# local customer is hidden if missing when customer_id is set
|
|
with patch.object(view, 'viewing', new=True):
|
|
with patch.object(order, 'customer_id', new='42'):
|
|
form = view.make_form(model_instance=order)
|
|
# nb. this is to avoid include/exclude ambiguity
|
|
form.remove('items')
|
|
view.configure_form(form)
|
|
self.assertNotIn('local_customer', form)
|
|
|
|
def test_get_xref_buttons(self):
|
|
self.pyramid_config.add_route('neworder_batches.view', '/batch/neworder/{uuid}')
|
|
model = self.app.model
|
|
handler = NewOrderBatchHandler(self.config)
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
order = model.Order(order_id=42, created_by=user)
|
|
self.session.add(order)
|
|
self.session.flush()
|
|
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
|
|
# nb. this requires perm to view batch
|
|
with patch.object(self.request, 'is_root', new=True):
|
|
|
|
# order has no batch, so no buttons
|
|
buttons = view.get_xref_buttons(order)
|
|
self.assertEqual(buttons, [])
|
|
|
|
# mock up a batch to get a button
|
|
batch = handler.make_batch(self.session,
|
|
id=order.order_id,
|
|
created_by=user,
|
|
executed=datetime.datetime.now(),
|
|
executed_by=user)
|
|
self.session.add(batch)
|
|
self.session.flush()
|
|
buttons = view.get_xref_buttons(order)
|
|
self.assertEqual(len(buttons), 1)
|
|
button = buttons[0]
|
|
self.assertIn("View the Batch", button)
|
|
|
|
def test_get_row_grid_data(self):
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
order = model.Order(order_id=42, created_by=user)
|
|
self.session.add(order)
|
|
self.session.flush()
|
|
order.items.append(model.OrderItem(product_id='07430500132',
|
|
product_scancode='07430500132',
|
|
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
|
status_code=enum.ORDER_ITEM_STATUS_INITIATED))
|
|
self.session.flush()
|
|
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
query = view.get_row_grid_data(order)
|
|
self.assertIsInstance(query, orm.Query)
|
|
items = query.all()
|
|
self.assertEqual(len(items), 1)
|
|
self.assertEqual(items[0].product_scancode, '07430500132')
|
|
|
|
def test_configure_row_grid(self):
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
order = model.Order(order_id=42, created_by=user)
|
|
self.session.add(order)
|
|
self.session.flush()
|
|
order.items.append(model.OrderItem(product_id='07430500132',
|
|
product_scancode='07430500132',
|
|
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
|
status_code=enum.ORDER_ITEM_STATUS_INITIATED))
|
|
self.session.flush()
|
|
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
grid = view.make_grid(model_class=model.OrderItem, data=order.items)
|
|
self.assertNotIn('product_scancode', grid.linked_columns)
|
|
view.configure_row_grid(grid)
|
|
self.assertIn('product_scancode', grid.linked_columns)
|
|
|
|
def test_render_status_code(self):
|
|
enum = self.app.enum
|
|
view = self.make_view()
|
|
result = view.render_status_code(None, None, enum.ORDER_ITEM_STATUS_INITIATED)
|
|
self.assertEqual(result, "initiated")
|
|
self.assertEqual(result, enum.ORDER_ITEM_STATUS[enum.ORDER_ITEM_STATUS_INITIATED])
|
|
|
|
def test_get_row_action_url_view(self):
|
|
self.pyramid_config.add_route('order_items.view', '/order-items/{uuid}')
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
order = model.Order(order_id=42, created_by=user)
|
|
self.session.add(order)
|
|
self.session.flush()
|
|
item = model.OrderItem(product_id='07430500132',
|
|
product_scancode='07430500132',
|
|
order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
|
status_code=enum.ORDER_ITEM_STATUS_INITIATED)
|
|
order.items.append(item)
|
|
self.session.flush()
|
|
|
|
url = view.get_row_action_url_view(item, 0)
|
|
self.assertIn(f'/order-items/{item.uuid}', url)
|
|
|
|
def test_configure(self):
|
|
self.pyramid_config.add_route('home', '/')
|
|
self.pyramid_config.add_route('login', '/auth/login')
|
|
self.pyramid_config.add_route('orders', '/orders/')
|
|
model = self.app.model
|
|
view = self.make_view()
|
|
|
|
with patch.object(view, 'Session', return_value=self.session):
|
|
with patch.multiple(self.config, usedb=True, preferdb=True):
|
|
|
|
# sanity check
|
|
allowed = self.config.get_bool('sideshow.orders.allow_unknown_products',
|
|
session=self.session)
|
|
self.assertIsNone(allowed)
|
|
self.assertEqual(self.session.query(model.Setting).count(), 0)
|
|
|
|
# fetch initial page
|
|
response = view.configure()
|
|
self.assertIsInstance(response, Response)
|
|
self.assertNotIsInstance(response, HTTPFound)
|
|
self.session.flush()
|
|
allowed = self.config.get_bool('sideshow.orders.allow_unknown_products',
|
|
session=self.session)
|
|
self.assertIsNone(allowed)
|
|
self.assertEqual(self.session.query(model.Setting).count(), 0)
|
|
|
|
# post new settings
|
|
with patch.multiple(self.request, create=True,
|
|
method='POST',
|
|
POST={
|
|
'sideshow.orders.allow_unknown_products': 'true',
|
|
}):
|
|
response = view.configure()
|
|
self.assertIsInstance(response, HTTPFound)
|
|
self.session.flush()
|
|
allowed = self.config.get_bool('sideshow.orders.allow_unknown_products',
|
|
session=self.session)
|
|
self.assertTrue(allowed)
|
|
self.assertTrue(self.session.query(model.Setting).count() > 1)
|
|
|
|
|
|
class TestOrderItemView(WebTestCase):
|
|
|
|
def make_view(self):
|
|
return mod.OrderItemView(self.request)
|
|
|
|
def test_get_query(self):
|
|
view = self.make_view()
|
|
query = view.get_query(session=self.session)
|
|
self.assertIsInstance(query, orm.Query)
|
|
|
|
def test_configure_grid(self):
|
|
model = self.app.model
|
|
view = self.make_view()
|
|
grid = view.make_grid(model_class=model.OrderItem)
|
|
self.assertNotIn('order_id', grid.linked_columns)
|
|
view.configure_grid(grid)
|
|
self.assertIn('order_id', grid.linked_columns)
|
|
|
|
def test_render_order_id(self):
|
|
model = self.app.model
|
|
view = self.make_view()
|
|
order = model.Order(order_id=42)
|
|
item = model.OrderItem()
|
|
order.items.append(item)
|
|
self.assertEqual(view.render_order_id(item, None, None), 42)
|
|
|
|
def test_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_get_instance_title(self):
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
view = self.make_view()
|
|
|
|
item = model.OrderItem(product_brand='Bragg',
|
|
product_description='Vinegar',
|
|
product_size='32oz',
|
|
status_code=enum.ORDER_ITEM_STATUS_INITIATED)
|
|
title = view.get_instance_title(item)
|
|
self.assertEqual(title, "(initiated) Bragg Vinegar 32oz")
|
|
|
|
def test_configure_form(self):
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
view = self.make_view()
|
|
|
|
item = model.OrderItem(status_code=enum.ORDER_ITEM_STATUS_INITIATED)
|
|
|
|
# viewing, w/ pending product
|
|
with patch.object(view, 'viewing', new=True):
|
|
form = view.make_form(model_instance=item)
|
|
view.configure_form(form)
|
|
schema = form.get_schema()
|
|
self.assertIsInstance(schema['order'].typ, OrderRef)
|
|
self.assertIn('pending_product', form)
|
|
self.assertIsInstance(schema['pending_product'].typ, PendingProductRef)
|
|
|
|
# viewing, w/ local product
|
|
local = model.LocalProduct()
|
|
item.local_product = local
|
|
with patch.object(view, 'viewing', new=True):
|
|
form = view.make_form(model_instance=item)
|
|
view.configure_form(form)
|
|
schema = form.get_schema()
|
|
self.assertIsInstance(schema['order'].typ, OrderRef)
|
|
self.assertNotIn('pending_product', form)
|
|
|
|
def test_get_xref_buttons(self):
|
|
self.pyramid_config.add_route('orders.view', '/orders/{uuid}')
|
|
model = self.app.model
|
|
enum = self.app.enum
|
|
view = self.make_view()
|
|
|
|
user = model.User(username='barney')
|
|
self.session.add(user)
|
|
order = model.Order(order_id=42, created_by=user)
|
|
self.session.add(order)
|
|
item = model.OrderItem(order_qty=1, order_uom=enum.ORDER_UOM_UNIT,
|
|
status_code=enum.ORDER_ITEM_STATUS_INITIATED)
|
|
order.items.append(item)
|
|
self.session.flush()
|
|
|
|
# nb. this requires perms
|
|
with patch.object(self.request, 'is_root', new=True):
|
|
|
|
# one button by default
|
|
buttons = view.get_xref_buttons(item)
|
|
self.assertEqual(len(buttons), 1)
|
|
self.assertIn("View the Order", buttons[0])
|