Update app.py
Browse files
app.py
CHANGED
|
@@ -9,6 +9,9 @@ from bs4 import BeautifulSoup
|
|
| 9 |
from sqlalchemy import select
|
| 10 |
from fuzzywuzzy import fuzz
|
| 11 |
from pydantic import BaseModel
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
from fastapi import FastAPI, Request, HTTPException, BackgroundTasks, UploadFile, File, Form
|
| 14 |
from fastapi.responses import JSONResponse, StreamingResponse, RedirectResponse
|
|
@@ -408,6 +411,47 @@ def match_dishes(user_input: str, threshold: int = 70) -> list:
|
|
| 408 |
matched_dishes.append(dish_name)
|
| 409 |
return list(set(matched_dishes))
|
| 410 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 411 |
|
| 412 |
async def process_order_flow(user_id: str, message: str) -> str:
|
| 413 |
"""
|
|
@@ -666,7 +710,7 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 666 |
if message.lower() in ["yes", "y"]:
|
| 667 |
order_id = f"ORD-{int(time.time())}"
|
| 668 |
state.data["order_id"] = order_id
|
| 669 |
-
price_per_serving =
|
| 670 |
quantity = state.data.get("quantity", 1)
|
| 671 |
shipping_cost = state.data.get("shipping_cost", 0)
|
| 672 |
total_price = (quantity * price_per_serving) + shipping_cost
|
|
@@ -687,34 +731,27 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 687 |
await session.commit()
|
| 688 |
asyncio.create_task(save_order())
|
| 689 |
asyncio.create_task(log_order_tracking(order_id, "Order Placed", "Order placed and awaiting payment."))
|
| 690 |
-
|
| 691 |
-
async def notify_management_order(order_details: dict):
|
| 692 |
-
message_body = (
|
| 693 |
-
f"New Order Received:\n"
|
| 694 |
-
f"Order ID: {order_details['order_id']}\n"
|
| 695 |
-
f"Dish: {order_details['dish']}\n"
|
| 696 |
-
f"Quantity: {order_details['quantity']}\n"
|
| 697 |
-
f"Total Price: {order_details['price']}\n"
|
| 698 |
-
f"Phone: {state.data.get('phone_number', '')}\n"
|
| 699 |
-
f"Delivery Address: {order_details.get('address', 'Not Provided')}\n"
|
| 700 |
-
f"Extras: {state.data.get('extras', 'None')}\n"
|
| 701 |
-
f"Status: Pending Payment"
|
| 702 |
-
)
|
| 703 |
-
await asyncio.to_thread(send_whatsapp_message, MANAGEMENT_WHATSAPP_NUMBER, message_body)
|
| 704 |
order_details = {
|
| 705 |
"order_id": order_id,
|
| 706 |
"dish": state.data["dish"],
|
| 707 |
"quantity": state.data["quantity"],
|
| 708 |
"price": state.data["price"],
|
| 709 |
-
"address": state.data.get("address", "")
|
|
|
|
|
|
|
| 710 |
}
|
| 711 |
-
|
| 712 |
-
|
| 713 |
-
|
| 714 |
-
|
| 715 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 716 |
dish_name = state.data.get("dish", "")
|
| 717 |
-
# Clean up state
|
| 718 |
state.reset()
|
| 719 |
if user_id in user_state:
|
| 720 |
del user_state[user_id]
|
|
@@ -736,12 +773,12 @@ async def process_order_flow(user_id: str, message: str) -> str:
|
|
| 736 |
"but we could not initialize online payment. Please try again later, or "
|
| 737 |
"you may opt to pay via bank transfer to Account Number 1433042821, Access Bank, Angelo Food Court 2 "
|
| 738 |
"and send your payment screenshot to this chatbot.")
|
| 739 |
-
|
| 740 |
-
|
| 741 |
-
|
| 742 |
-
|
| 743 |
-
|
| 744 |
-
|
| 745 |
# Final fallback
|
| 746 |
return ""
|
| 747 |
|
|
|
|
| 9 |
from sqlalchemy import select
|
| 10 |
from fuzzywuzzy import fuzz
|
| 11 |
from pydantic import BaseModel
|
| 12 |
+
import smtplib
|
| 13 |
+
from email.mime.multipart import MIMEMultipart
|
| 14 |
+
from email.mime.text import MIMEText
|
| 15 |
|
| 16 |
from fastapi import FastAPI, Request, HTTPException, BackgroundTasks, UploadFile, File, Form
|
| 17 |
from fastapi.responses import JSONResponse, StreamingResponse, RedirectResponse
|
|
|
|
| 411 |
matched_dishes.append(dish_name)
|
| 412 |
return list(set(matched_dishes))
|
| 413 |
|
| 414 |
+
def get_dish_price(dish: str) -> int:
|
| 415 |
+
for item in menu_items:
|
| 416 |
+
if item["name"].lower() == dish.lower():
|
| 417 |
+
return item["price"]
|
| 418 |
+
return 0 # default if not found
|
| 419 |
+
|
| 420 |
+
def send_email_notification(order_details):
|
| 421 |
+
# Construct the email payload. Adjust values as needed.
|
| 422 |
+
payload = {
|
| 423 |
+
"from": "yungdml31@gmail.com",
|
| 424 |
+
"to": "samyung05@gmail.com", # You can also use a comma-separated list for multiple recipients.
|
| 425 |
+
"subject": f"New Order Received: {order_details['order_id']}",
|
| 426 |
+
"body": (
|
| 427 |
+
f"New Order Received:\n"
|
| 428 |
+
f"Order ID: {order_details['order_id']}\n"
|
| 429 |
+
f"Dish: {order_details['dish']}\n"
|
| 430 |
+
f"Quantity: {order_details['quantity']}\n"
|
| 431 |
+
f"Total Price: N{order_details['price']}\n"
|
| 432 |
+
f"Phone: {order_details.get('phone_number', 'Not Provided')}\n"
|
| 433 |
+
f"Delivery Address: {order_details.get('address', 'Not Provided')}\n"
|
| 434 |
+
f"Extras: {order_details.get('extras', 'None')}\n"
|
| 435 |
+
f"Status: Pending Payment"
|
| 436 |
+
),
|
| 437 |
+
# Even though your endpoint is set up to receive these fields, if they're fixed you can omit them or keep them here:
|
| 438 |
+
"smtpHost": "smtp.gmail.com", # or your SMTP host
|
| 439 |
+
"smtpPort": 587, # or your SMTP port
|
| 440 |
+
"smtpSecure": "false", # boolean as string if needed
|
| 441 |
+
"smtpUser": "yungdml31@gmail.com",
|
| 442 |
+
"smtpPassword": "uddvxabxotlvfewk",
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
# Replace the URL with the URL of your SMTP API endpoint.
|
| 446 |
+
url = "https://smtp-server-ten.vercel.app/smtp"
|
| 447 |
+
try:
|
| 448 |
+
response = requests.post(url, json=payload, timeout=10)
|
| 449 |
+
response.raise_for_status()
|
| 450 |
+
return response.json()
|
| 451 |
+
except Exception as e:
|
| 452 |
+
print(f"Error sending email: {e}")
|
| 453 |
+
return None
|
| 454 |
+
|
| 455 |
|
| 456 |
async def process_order_flow(user_id: str, message: str) -> str:
|
| 457 |
"""
|
|
|
|
| 710 |
if message.lower() in ["yes", "y"]:
|
| 711 |
order_id = f"ORD-{int(time.time())}"
|
| 712 |
state.data["order_id"] = order_id
|
| 713 |
+
price_per_serving = get_dish_price(state.data["dish"]) # Use your helper to get the correct price
|
| 714 |
quantity = state.data.get("quantity", 1)
|
| 715 |
shipping_cost = state.data.get("shipping_cost", 0)
|
| 716 |
total_price = (quantity * price_per_serving) + shipping_cost
|
|
|
|
| 731 |
await session.commit()
|
| 732 |
asyncio.create_task(save_order())
|
| 733 |
asyncio.create_task(log_order_tracking(order_id, "Order Placed", "Order placed and awaiting payment."))
|
| 734 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 735 |
order_details = {
|
| 736 |
"order_id": order_id,
|
| 737 |
"dish": state.data["dish"],
|
| 738 |
"quantity": state.data["quantity"],
|
| 739 |
"price": state.data["price"],
|
| 740 |
+
"address": state.data.get("address", ""),
|
| 741 |
+
"phone_number": state.data.get("phone_number", ""),
|
| 742 |
+
"extras": state.data.get("extras", "None")
|
| 743 |
}
|
| 744 |
+
# Notify admin via email
|
| 745 |
+
email_response = send_email_notification(order_details)
|
| 746 |
+
if email_response:
|
| 747 |
+
print("Email notification sent successfully:", email_response)
|
| 748 |
+
else:
|
| 749 |
+
print("Failed to send email notification.")
|
| 750 |
+
|
| 751 |
+
# Create Paystack payment link
|
| 752 |
+
email_for_paystack = "customer@example.com" # Replace with actual email if available
|
| 753 |
+
payment_data = create_paystack_payment_link(email_for_paystack, total_price * 100, order_id)
|
| 754 |
dish_name = state.data.get("dish", "")
|
|
|
|
| 755 |
state.reset()
|
| 756 |
if user_id in user_state:
|
| 757 |
del user_state[user_id]
|
|
|
|
| 773 |
"but we could not initialize online payment. Please try again later, or "
|
| 774 |
"you may opt to pay via bank transfer to Account Number 1433042821, Access Bank, Angelo Food Court 2 "
|
| 775 |
"and send your payment screenshot to this chatbot.")
|
| 776 |
+
else:
|
| 777 |
+
state.reset()
|
| 778 |
+
if user_id in user_state:
|
| 779 |
+
del user_state[user_id]
|
| 780 |
+
return "Order canceled. Let me know if you'd like to try again."
|
| 781 |
+
|
| 782 |
# Final fallback
|
| 783 |
return ""
|
| 784 |
|