Fred808 commited on
Commit
34b29bd
·
verified ·
1 Parent(s): 87e06ac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -18
app.py CHANGED
@@ -238,8 +238,11 @@ def process_order_flow(user_id: str, message: str) -> str:
238
  Implements an FSM-based order flow that:
239
  - Step 1: Expects the user to mention a dish name (optionally with quantity)
240
  - Step 2: Asks for quantity if not provided
241
- - Step 3: Requests the delivery address
242
- - Step 4: Asks for order confirmation (yes/no) and finalizes the order
 
 
 
243
  """
244
  # Retrieve or initialize conversation state
245
  state = user_state.get(user_id)
@@ -248,7 +251,7 @@ def process_order_flow(user_id: str, message: str) -> str:
248
  del user_state[user_id]
249
  state = None
250
 
251
- # If the user explicitly types "order" or "menu", (re)start the order flow.
252
  if message.lower() in ["order", "menu"]:
253
  state = ConversationState()
254
  state.flow = "order"
@@ -286,10 +289,10 @@ def process_order_flow(user_id: str, message: str) -> str:
286
  if quantity <= 0:
287
  return "Please enter a valid quantity (e.g., 1, 2, 3)."
288
  state.data["quantity"] = quantity
289
- state.step = 3 # move directly to address step
290
- return f"You selected {found_dish} with {quantity} serving(s). Please provide your delivery address."
291
  else:
292
- state.step = 2 # ask for quantity
293
  return f"You selected {found_dish}. How many servings would you like?"
294
  else:
295
  return "I couldn't identify the dish. Please type the dish name from our menu."
@@ -304,17 +307,59 @@ def process_order_flow(user_id: str, message: str) -> str:
304
  return "Please enter a valid quantity (e.g., 1, 2, 3)."
305
  state.data["quantity"] = quantity
306
  state.step = 3
307
- return f"Got it. {quantity} serving(s) of {state.data.get('dish')}. Now, please provide your delivery address."
308
 
309
- # --- Step 3: Requesting Delivery Address ---
310
  if state.step == 3:
311
- # Assume any text is a valid address
312
- state.data["address"] = message
313
- state.step = 4
314
- return f"Thanks. Your delivery address is recorded as: {message}. Confirm order? (yes/no)"
 
 
 
315
 
316
- # --- Step 4: Order Confirmation & Finalization ---
317
  if state.step == 4:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
318
  if message.lower() in ["yes", "y"]:
319
  order_id = f"ORD-{int(time.time())}"
320
  state.data["order_id"] = order_id
@@ -323,7 +368,7 @@ def process_order_flow(user_id: str, message: str) -> str:
323
  total_price = quantity * price_per_serving
324
  state.data["price"] = str(total_price)
325
 
326
- # Save the order asynchronously (including delivery_address)
327
  async def save_order():
328
  async with async_session() as session:
329
  order = Order(
@@ -347,7 +392,9 @@ def process_order_flow(user_id: str, message: str) -> str:
347
  f"Dish: {order_details['dish']}\n"
348
  f"Quantity: {order_details['quantity']}\n"
349
  f"Total Price: {order_details['price']}\n"
 
350
  f"Delivery Address: {order_details.get('address', 'Not Provided')}\n"
 
351
  f"Status: Pending Payment"
352
  )
353
  await asyncio.to_thread(send_whatsapp_message, MANAGEMENT_WHATSAPP_NUMBER, message_body)
@@ -356,8 +403,7 @@ def process_order_flow(user_id: str, message: str) -> str:
356
  "dish": state.data["dish"],
357
  "quantity": state.data["quantity"],
358
  "price": state.data["price"],
359
- "address": state.data.get("address", ""),
360
- "status": "Pending Payment"
361
  }
362
  asyncio.create_task(notify_management_order(order_details))
363
 
@@ -371,7 +417,8 @@ def process_order_flow(user_id: str, message: str) -> str:
371
  payment_link = payment_data["data"]["authorization_url"]
372
  return (f"Thank you for your order of {quantity} serving(s) of {dish_name}! "
373
  f"Your Order ID is {order_id}.\nPlease complete payment here: {payment_link}\n"
374
- "You can track your order status using your Order ID.")
 
375
  else:
376
  return f"Your order has been placed with Order ID {order_id}, but we could not initialize payment. Please try again later."
377
  else:
@@ -520,7 +567,7 @@ async def chatbot_response(request: Request, background_tasks: BackgroundTasks):
520
  if selected_dish:
521
  state = ConversationState()
522
  state.flow = "order"
523
- # **** FIX: Set step to 2 since the dish is already selected ****
524
  state.step = 2
525
  state.data["dish"] = selected_dish
526
  state.update_last_active()
 
238
  Implements an FSM-based order flow that:
239
  - Step 1: Expects the user to mention a dish name (optionally with quantity)
240
  - Step 2: Asks for quantity if not provided
241
+ - Step 3: Requests the user's phone number if not already provided
242
+ - Step 4: Requests the delivery address and validates that it includes "OJO LGA, Lagos"
243
+ - Step 5: Asks if they would like to add any extras (e.g., sides or drinks)
244
+ - Step 6: Captures extras details if applicable
245
+ - Step 7: Asks for order confirmation and finalizes the order
246
  """
247
  # Retrieve or initialize conversation state
248
  state = user_state.get(user_id)
 
251
  del user_state[user_id]
252
  state = None
253
 
254
+ # Start a new order flow if the user explicitly types "order" or "menu"
255
  if message.lower() in ["order", "menu"]:
256
  state = ConversationState()
257
  state.flow = "order"
 
289
  if quantity <= 0:
290
  return "Please enter a valid quantity (e.g., 1, 2, 3)."
291
  state.data["quantity"] = quantity
292
+ state.step = 3 # Move to phone number step
293
+ return f"You selected {found_dish} with {quantity} serving(s). Please provide your phone number for order updates."
294
  else:
295
+ state.step = 2 # Ask for quantity
296
  return f"You selected {found_dish}. How many servings would you like?"
297
  else:
298
  return "I couldn't identify the dish. Please type the dish name from our menu."
 
307
  return "Please enter a valid quantity (e.g., 1, 2, 3)."
308
  state.data["quantity"] = quantity
309
  state.step = 3
310
+ return f"Got it. {quantity} serving(s) of {state.data.get('dish')}. Please provide your phone number for order updates."
311
 
312
+ # --- Step 3: Requesting Phone Number ---
313
  if state.step == 3:
314
+ phone_pattern = r'^\+?\d{10,15}$'
315
+ if re.match(phone_pattern, message.strip()):
316
+ state.data["phone_number"] = message.strip()
317
+ state.step = 4
318
+ return "Thank you. Please provide your delivery address. (Make sure it includes 'OJO LGA, Lagos')"
319
+ else:
320
+ return "Please enter a valid phone number (e.g., +234XXXXXXXXXX or 0XXXXXXXXXX)."
321
 
322
+ # --- Step 4: Requesting Delivery Address with Local Govt Check ---
323
  if state.step == 4:
324
+ if "ojo lga, lagos" not in message.lower():
325
+ return "We only deliver to OJO LGA, Lagos. Please provide a valid delivery address that includes 'OJO LGA, Lagos'."
326
+ state.data["address"] = message
327
+ state.step = 5
328
+ return f"Thanks. Your delivery address is recorded as: {message}. Would you like to add any extras such as sides or drinks? (yes/no)"
329
+
330
+ # --- Step 5: Asking if They Want Extras ---
331
+ if state.step == 5:
332
+ if message.lower() in ["yes", "y"]:
333
+ state.step = 6
334
+ return "Please list the extras you would like to add (e.g., drinks, sides, etc.)."
335
+ elif message.lower() in ["no", "n"]:
336
+ state.data["extras"] = ""
337
+ state.step = 7
338
+ dish = state.data.get("dish", "")
339
+ quantity = state.data.get("quantity", 1)
340
+ phone = state.data.get("phone_number", "")
341
+ address = state.data.get("address", "")
342
+ summary = (f"Order Summary:\nDish: {dish}\nQuantity: {quantity}\n"
343
+ f"Phone: {phone}\nAddress: {address}\nExtras: None\nConfirm order? (yes/no)")
344
+ return summary
345
+ else:
346
+ return "Please respond with 'yes' or 'no'. Would you like to add any extras to your order? (yes/no)"
347
+
348
+ # --- Step 6: Capturing Extras Details ---
349
+ if state.step == 6:
350
+ state.data["extras"] = message
351
+ state.step = 7
352
+ dish = state.data.get("dish", "")
353
+ quantity = state.data.get("quantity", 1)
354
+ phone = state.data.get("phone_number", "")
355
+ address = state.data.get("address", "")
356
+ extras = state.data.get("extras", "")
357
+ summary = (f"Order Summary:\nDish: {dish}\nQuantity: {quantity}\n"
358
+ f"Phone: {phone}\nAddress: {address}\nExtras: {extras}\nConfirm order? (yes/no)")
359
+ return summary
360
+
361
+ # --- Step 7: Order Confirmation & Finalization ---
362
+ if state.step == 7:
363
  if message.lower() in ["yes", "y"]:
364
  order_id = f"ORD-{int(time.time())}"
365
  state.data["order_id"] = order_id
 
368
  total_price = quantity * price_per_serving
369
  state.data["price"] = str(total_price)
370
 
371
+ # Save the order asynchronously (including delivery_address, phone, extras)
372
  async def save_order():
373
  async with async_session() as session:
374
  order = Order(
 
392
  f"Dish: {order_details['dish']}\n"
393
  f"Quantity: {order_details['quantity']}\n"
394
  f"Total Price: {order_details['price']}\n"
395
+ f"Phone: {state.data.get('phone_number', '')}\n"
396
  f"Delivery Address: {order_details.get('address', 'Not Provided')}\n"
397
+ f"Extras: {state.data.get('extras', 'None')}\n"
398
  f"Status: Pending Payment"
399
  )
400
  await asyncio.to_thread(send_whatsapp_message, MANAGEMENT_WHATSAPP_NUMBER, message_body)
 
403
  "dish": state.data["dish"],
404
  "quantity": state.data["quantity"],
405
  "price": state.data["price"],
406
+ "address": state.data.get("address", "")
 
407
  }
408
  asyncio.create_task(notify_management_order(order_details))
409
 
 
417
  payment_link = payment_data["data"]["authorization_url"]
418
  return (f"Thank you for your order of {quantity} serving(s) of {dish_name}! "
419
  f"Your Order ID is {order_id}.\nPlease complete payment here: {payment_link}\n"
420
+ "You can track your order status using your Order ID.\n"
421
+ "Is there anything else you'd like to order?")
422
  else:
423
  return f"Your order has been placed with Order ID {order_id}, but we could not initialize payment. Please try again later."
424
  else:
 
567
  if selected_dish:
568
  state = ConversationState()
569
  state.flow = "order"
570
+ # Set step to 2 since the dish is already selected
571
  state.step = 2
572
  state.data["dish"] = selected_dish
573
  state.update_last_active()