mirror of
https://github.com/Sea-Haven-Industries/meal-order-manager.git
synced 2026-10-05 13:01:58 +00:00
138 lines
3.7 KiB
Python
138 lines
3.7 KiB
Python
|
|
"""CSV parsing and menu matching for the Redefine cart filler."""
|
||
|
|
|
||
|
|
from scraper.fill_cart import build_plan, cart_lines, error_text, quantity_for
|
||
|
|
from scraper.parse_menu import extract_catalog_products
|
||
|
|
|
||
|
|
PRODUCTS = [
|
||
|
|
{
|
||
|
|
"name": "Korean Steak Bowl",
|
||
|
|
"uuid": "korean-id",
|
||
|
|
"available": True,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"name": "Sale Bowl",
|
||
|
|
"uuid": "sale-id",
|
||
|
|
"available": True,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"name": "Hidden Bowl",
|
||
|
|
"uuid": "hidden-id",
|
||
|
|
"available": False,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"name": "Twin Bowl",
|
||
|
|
"uuid": "twin-a",
|
||
|
|
"available": True,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"name": "twin bowl",
|
||
|
|
"uuid": "twin-b",
|
||
|
|
"available": True,
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"name": "No Id Bowl",
|
||
|
|
"uuid": "",
|
||
|
|
"available": True,
|
||
|
|
},
|
||
|
|
]
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_plan_matches_names_and_skips_the_rest():
|
||
|
|
csv_text = "\n".join(
|
||
|
|
[
|
||
|
|
"Item,Quantity",
|
||
|
|
"korean steak bowl,4",
|
||
|
|
"Sale Bowl,2",
|
||
|
|
"Sale Bowl,3",
|
||
|
|
"Hidden Bowl,1",
|
||
|
|
"Twin Bowl,8",
|
||
|
|
"Missing Bowl,1",
|
||
|
|
"No Id Bowl,1",
|
||
|
|
"=cmd,1",
|
||
|
|
"Zero Bowl,0",
|
||
|
|
"Bad Qty,nope",
|
||
|
|
]
|
||
|
|
)
|
||
|
|
# The admin exporter prefixes formula-like names with an apostrophe.
|
||
|
|
csv_text = csv_text.replace("=cmd", "'=cmd")
|
||
|
|
|
||
|
|
plan = build_plan(csv_text, PRODUCTS)
|
||
|
|
|
||
|
|
assert [(item.name, item.quantity, item.uuid) for item in plan.adds] == [
|
||
|
|
("Korean Steak Bowl", 4, "korean-id"),
|
||
|
|
("Sale Bowl", 5, "sale-id"),
|
||
|
|
]
|
||
|
|
assert [(line.name, line.reason) for line in plan.skipped] == [
|
||
|
|
("Bad Qty", "invalid quantity 'nope'"),
|
||
|
|
("Hidden Bowl", "unavailable on the menu"),
|
||
|
|
("Twin Bowl", "matches more than one menu item"),
|
||
|
|
("Missing Bowl", "not on the menu"),
|
||
|
|
("No Id Bowl", "not on the menu"),
|
||
|
|
("=cmd", "not on the menu"),
|
||
|
|
]
|
||
|
|
assert plan.ignored_zero == 1
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_plan_reads_quoted_fields_and_a_byte_order_mark():
|
||
|
|
csv_text = '\ufeffItem,Quantity\r\n"Bowl, Large",2\r\n'
|
||
|
|
products = [{"name": "Bowl, Large", "uuid": "bowl", "available": True}]
|
||
|
|
|
||
|
|
plan = build_plan(csv_text, products)
|
||
|
|
|
||
|
|
assert plan.adds[0].name == "Bowl, Large"
|
||
|
|
assert plan.adds[0].quantity == 2
|
||
|
|
assert plan.skipped == ()
|
||
|
|
|
||
|
|
|
||
|
|
def test_build_plan_requires_the_admin_columns():
|
||
|
|
try:
|
||
|
|
build_plan("Meal,Qty\nSoup,1\n", PRODUCTS)
|
||
|
|
except ValueError as exc:
|
||
|
|
assert "Item and Quantity" in str(exc)
|
||
|
|
else:
|
||
|
|
raise AssertionError("expected a column error")
|
||
|
|
|
||
|
|
|
||
|
|
def test_extract_catalog_products_reads_the_menu_attribute():
|
||
|
|
page = """
|
||
|
|
<orders-page
|
||
|
|
:products='[{"name":"Korean Steak Bowl","uuid":"korean-id","available":true}]'
|
||
|
|
:newest-ids='[]'
|
||
|
|
></orders-page>
|
||
|
|
"""
|
||
|
|
|
||
|
|
assert extract_catalog_products(page)[0]["uuid"] == "korean-id"
|
||
|
|
|
||
|
|
|
||
|
|
def test_cart_lines_use_the_product_uuid_and_quantity():
|
||
|
|
cart = {
|
||
|
|
"items": [
|
||
|
|
{
|
||
|
|
"uuid": "line-1",
|
||
|
|
"quantity": "4",
|
||
|
|
"product": {"name": "Korean Steak Bowl", "uuid": "korean-id"},
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
lines = cart_lines(cart)
|
||
|
|
|
||
|
|
assert lines[0].name == "Korean Steak Bowl"
|
||
|
|
assert lines[0].product_uuid == "korean-id"
|
||
|
|
assert quantity_for(lines, "korean-id") == 4
|
||
|
|
assert quantity_for(lines, "line-1") == 0
|
||
|
|
|
||
|
|
|
||
|
|
def test_error_text_keeps_the_message_and_drops_the_trace():
|
||
|
|
body = {
|
||
|
|
"message": "Product is not available.",
|
||
|
|
"exception": "HttpException",
|
||
|
|
"file": "/home/app/secret.php",
|
||
|
|
"trace": [{"file": "/home/app/secret.php"}],
|
||
|
|
}
|
||
|
|
|
||
|
|
text = error_text(422, body)
|
||
|
|
|
||
|
|
assert text == "HTTP 422: Product is not available."
|
||
|
|
assert "secret.php" not in text
|