Update app.py
Browse files
app.py
CHANGED
|
@@ -501,14 +501,14 @@ def match_dishes(user_input: str, threshold: int = 70) -> list:
|
|
| 501 |
|
| 502 |
return list(set(matched_dishes))
|
| 503 |
|
| 504 |
-
def get_dish_price(dish: str) -> int:
|
| 505 |
-
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
| 509 |
|
| 510 |
# Fetch dish price from the MenuItem table
|
| 511 |
-
async def
|
| 512 |
async with async_session() as session:
|
| 513 |
# Using ilike() for case-insensitive matching
|
| 514 |
result = await session.execute(select(MenuItem).where(MenuItem.name.ilike(dish)))
|
|
@@ -727,7 +727,7 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 727 |
"Please provide your phone number and delivery address.")
|
| 728 |
|
| 729 |
# Step 4: Parse phone & address (for single or multi-dish orders), then skip extras.
|
| 730 |
-
# --- Step 4: Parse phone & address, compute
|
| 731 |
if state and state.flow == "order" and state.step == 3:
|
| 732 |
phone_pattern = r'(\+?\d{10,15})'
|
| 733 |
phone_match = re.search(phone_pattern, message)
|
|
@@ -747,27 +747,30 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 747 |
"For example: '09162409591, 1, Iyana Isashi, Isashi, Lagos'.")
|
| 748 |
if not state.data.get("address"):
|
| 749 |
return "Thank you. Please provide your delivery address."
|
| 750 |
-
|
|
|
|
| 751 |
state.data["shipping_cost"] = shipping_cost
|
| 752 |
|
| 753 |
-
# Automatically set extras to empty since we're not using extras
|
| 754 |
state.data["extras"] = ""
|
|
|
|
|
|
|
|
|
|
| 755 |
|
| 756 |
-
#
|
| 757 |
if "orders" in state.data:
|
| 758 |
dish_summary = ", ".join(state.data["orders"].keys())
|
| 759 |
quantity_total = sum(state.data["orders"].values())
|
| 760 |
total_price = 0
|
| 761 |
for dish, qty in state.data["orders"].items():
|
| 762 |
-
total_price += get_dish_price(dish) * qty
|
| 763 |
total_price += shipping_cost
|
| 764 |
else:
|
| 765 |
dish_summary = state.data.get("dish", "")
|
| 766 |
quantity_total = state.data.get("quantity", 1)
|
| 767 |
-
|
|
|
|
| 768 |
|
| 769 |
-
# Skip extras prompt and jump directly to confirmation (Step 7)
|
| 770 |
-
state.step = 7
|
| 771 |
return (f"Order Summary:\n"
|
| 772 |
f"Dish(es): {dish_summary}\n"
|
| 773 |
f"Quantity: {quantity_total}\n"
|
|
@@ -778,24 +781,28 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 778 |
"Confirm order? (yes/no)")
|
| 779 |
|
| 780 |
|
|
|
|
| 781 |
|
| 782 |
# 7) Step 7: Order Confirmation and Payment Link Generation
|
| 783 |
if state and state.flow == "order" and state.step == 7:
|
| 784 |
if message.lower() in ["yes", "y"]:
|
| 785 |
order_id = f"ORD-{int(time.time())}"
|
| 786 |
state.data["order_id"] = order_id
|
|
|
|
| 787 |
# Calculate total price:
|
| 788 |
if "orders" in state.data:
|
| 789 |
total_price = 0
|
| 790 |
for dish, qty in state.data["orders"].items():
|
| 791 |
-
total_price += get_dish_price(dish) * qty
|
| 792 |
total_price += state.data.get("shipping_cost", 0)
|
| 793 |
dish_summary = ", ".join(state.data["orders"].keys())
|
| 794 |
quantity_total = sum(state.data["orders"].values())
|
| 795 |
else:
|
| 796 |
dish_summary = state.data.get("dish", "")
|
| 797 |
quantity_total = state.data.get("quantity", 1)
|
| 798 |
-
|
|
|
|
|
|
|
| 799 |
state.data["price"] = str(total_price)
|
| 800 |
|
| 801 |
async def save_order():
|
|
@@ -814,10 +821,7 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 814 |
asyncio.create_task(save_order())
|
| 815 |
asyncio.create_task(log_order_tracking(order_id, "Order Placed", "Order placed and awaiting payment."))
|
| 816 |
|
| 817 |
-
#
|
| 818 |
-
state.data["extras"] = ""
|
| 819 |
-
|
| 820 |
-
# Prepare order details as a dictionary for the email notification.
|
| 821 |
order_details = {
|
| 822 |
"order_id": order_id,
|
| 823 |
"dish": dish_summary,
|
|
@@ -827,14 +831,26 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 827 |
"address": state.data.get("address", "Not Provided"),
|
| 828 |
"extras": state.data.get("extras", "None")
|
| 829 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 830 |
email_response = send_email_notification(order_details)
|
| 831 |
if email_response:
|
| 832 |
print("Email notification sent successfully.")
|
| 833 |
else:
|
| 834 |
print("Failed to send email notification.")
|
| 835 |
|
| 836 |
-
#
|
| 837 |
-
email_for_paystack = "customer@example.com"
|
| 838 |
payment_data = create_paystack_payment_link(email_for_paystack, total_price * 100, order_id)
|
| 839 |
state.reset()
|
| 840 |
if user_id in user_state:
|
|
@@ -855,15 +871,15 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 855 |
else:
|
| 856 |
return (f"Your order has been placed with Order ID {order_id}, "
|
| 857 |
"but we could not initialize online payment. Please try again later, or "
|
| 858 |
-
"you may opt to pay via bank transfer to Account Number
|
| 859 |
"and send your payment screenshot to this chatbot.")
|
| 860 |
elif message.lower() in ["no", "n"]:
|
| 861 |
state.reset()
|
| 862 |
if user_id in user_state:
|
| 863 |
del user_state[user_id]
|
| 864 |
return "Order canceled. Let me know if you'd like to try again."
|
| 865 |
-
|
| 866 |
-
|
| 867 |
|
| 868 |
return ""
|
| 869 |
|
|
|
|
| 501 |
|
| 502 |
return list(set(matched_dishes))
|
| 503 |
|
| 504 |
+
# def get_dish_price(dish: str) -> int:
|
| 505 |
+
# for item in menu_items:
|
| 506 |
+
# if item["name"].lower() == dish.lower():
|
| 507 |
+
# return item["price"]
|
| 508 |
+
# return 0 # or raise an error if dish not found
|
| 509 |
|
| 510 |
# Fetch dish price from the MenuItem table
|
| 511 |
+
async def get_dish_price(dish: str) -> int:
|
| 512 |
async with async_session() as session:
|
| 513 |
# Using ilike() for case-insensitive matching
|
| 514 |
result = await session.execute(select(MenuItem).where(MenuItem.name.ilike(dish)))
|
|
|
|
| 727 |
"Please provide your phone number and delivery address.")
|
| 728 |
|
| 729 |
# Step 4: Parse phone & address (for single or multi-dish orders), then skip extras.
|
| 730 |
+
# --- Step 4: Parse phone & address, compute shipping cost, and jump to confirmation ---
|
| 731 |
if state and state.flow == "order" and state.step == 3:
|
| 732 |
phone_pattern = r'(\+?\d{10,15})'
|
| 733 |
phone_match = re.search(phone_pattern, message)
|
|
|
|
| 747 |
"For example: '09162409591, 1, Iyana Isashi, Isashi, Lagos'.")
|
| 748 |
if not state.data.get("address"):
|
| 749 |
return "Thank you. Please provide your delivery address."
|
| 750 |
+
# Get shipping cost from the database
|
| 751 |
+
shipping_cost = await get_shipping_cost(state.data["address"])
|
| 752 |
state.data["shipping_cost"] = shipping_cost
|
| 753 |
|
| 754 |
+
# Automatically set extras to empty (since we're not using extras)
|
| 755 |
state.data["extras"] = ""
|
| 756 |
+
|
| 757 |
+
# Jump directly to order confirmation (Step 7)
|
| 758 |
+
state.step = 7
|
| 759 |
|
| 760 |
+
# For order summary, determine dish summary and quantity:
|
| 761 |
if "orders" in state.data:
|
| 762 |
dish_summary = ", ".join(state.data["orders"].keys())
|
| 763 |
quantity_total = sum(state.data["orders"].values())
|
| 764 |
total_price = 0
|
| 765 |
for dish, qty in state.data["orders"].items():
|
| 766 |
+
total_price += (await get_dish_price(dish)) * qty
|
| 767 |
total_price += shipping_cost
|
| 768 |
else:
|
| 769 |
dish_summary = state.data.get("dish", "")
|
| 770 |
quantity_total = state.data.get("quantity", 1)
|
| 771 |
+
dish_price = await get_dish_price(dish_summary)
|
| 772 |
+
total_price = (quantity_total * dish_price) + shipping_cost
|
| 773 |
|
|
|
|
|
|
|
| 774 |
return (f"Order Summary:\n"
|
| 775 |
f"Dish(es): {dish_summary}\n"
|
| 776 |
f"Quantity: {quantity_total}\n"
|
|
|
|
| 781 |
"Confirm order? (yes/no)")
|
| 782 |
|
| 783 |
|
| 784 |
+
|
| 785 |
|
| 786 |
# 7) Step 7: Order Confirmation and Payment Link Generation
|
| 787 |
if state and state.flow == "order" and state.step == 7:
|
| 788 |
if message.lower() in ["yes", "y"]:
|
| 789 |
order_id = f"ORD-{int(time.time())}"
|
| 790 |
state.data["order_id"] = order_id
|
| 791 |
+
|
| 792 |
# Calculate total price:
|
| 793 |
if "orders" in state.data:
|
| 794 |
total_price = 0
|
| 795 |
for dish, qty in state.data["orders"].items():
|
| 796 |
+
total_price += (await get_dish_price(dish)) * qty
|
| 797 |
total_price += state.data.get("shipping_cost", 0)
|
| 798 |
dish_summary = ", ".join(state.data["orders"].keys())
|
| 799 |
quantity_total = sum(state.data["orders"].values())
|
| 800 |
else:
|
| 801 |
dish_summary = state.data.get("dish", "")
|
| 802 |
quantity_total = state.data.get("quantity", 1)
|
| 803 |
+
dish_price = await get_dish_price(dish_summary)
|
| 804 |
+
total_price = (quantity_total * dish_price) + state.data.get("shipping_cost", 0)
|
| 805 |
+
|
| 806 |
state.data["price"] = str(total_price)
|
| 807 |
|
| 808 |
async def save_order():
|
|
|
|
| 821 |
asyncio.create_task(save_order())
|
| 822 |
asyncio.create_task(log_order_tracking(order_id, "Order Placed", "Order placed and awaiting payment."))
|
| 823 |
|
| 824 |
+
# Prepare order details for email notification.
|
|
|
|
|
|
|
|
|
|
| 825 |
order_details = {
|
| 826 |
"order_id": order_id,
|
| 827 |
"dish": dish_summary,
|
|
|
|
| 831 |
"address": state.data.get("address", "Not Provided"),
|
| 832 |
"extras": state.data.get("extras", "None")
|
| 833 |
}
|
| 834 |
+
admin_emails = os.getenv("ADMIN_EMAILS", "admin@example.com").split(",")
|
| 835 |
+
email_subject = f"New Order Received: {order_id}"
|
| 836 |
+
email_body = (
|
| 837 |
+
f"New Order Received:\n"
|
| 838 |
+
f"Order ID: {order_id}\n"
|
| 839 |
+
f"Dish(es): {dish_summary}\n"
|
| 840 |
+
f"Quantity: {quantity_total}\n"
|
| 841 |
+
f"Total Price: N{total_price}\n"
|
| 842 |
+
f"Phone: {state.data.get('phone_number', '')}\n"
|
| 843 |
+
f"Delivery Address: {state.data.get('address', 'Not Provided')}\n"
|
| 844 |
+
f"Extras: {state.data.get('extras', 'None')}\n"
|
| 845 |
+
f"Status: Pending Payment"
|
| 846 |
+
)
|
| 847 |
email_response = send_email_notification(order_details)
|
| 848 |
if email_response:
|
| 849 |
print("Email notification sent successfully.")
|
| 850 |
else:
|
| 851 |
print("Failed to send email notification.")
|
| 852 |
|
| 853 |
+
email_for_paystack = "customer@example.com" # Replace with user's email if available
|
|
|
|
| 854 |
payment_data = create_paystack_payment_link(email_for_paystack, total_price * 100, order_id)
|
| 855 |
state.reset()
|
| 856 |
if user_id in user_state:
|
|
|
|
| 871 |
else:
|
| 872 |
return (f"Your order has been placed with Order ID {order_id}, "
|
| 873 |
"but we could not initialize online payment. Please try again later, or "
|
| 874 |
+
"you may opt to pay via bank transfer to Account Number 1433042821, Access Bank, Angelo Food Court 2 "
|
| 875 |
"and send your payment screenshot to this chatbot.")
|
| 876 |
elif message.lower() in ["no", "n"]:
|
| 877 |
state.reset()
|
| 878 |
if user_id in user_state:
|
| 879 |
del user_state[user_id]
|
| 880 |
return "Order canceled. Let me know if you'd like to try again."
|
| 881 |
+
else:
|
| 882 |
+
return "I didn't understand that. Please type 'yes' to confirm your order or 'no' to cancel it."
|
| 883 |
|
| 884 |
return ""
|
| 885 |
|