""" Seed data script for POS Microservice. Populates MongoDB with sample catalogue services, staff, and customers. Usage: python scripts/seed_data.py Or with custom merchant_id: python scripts/seed_data.py --merchant-id """ import asyncio import argparse import sys from pathlib import Path from uuid import uuid4 from datetime import datetime # Add parent directory to path to import app modules sys.path.insert(0, str(Path(__file__).parent.parent)) from app.nosql import connect_to_mongo, close_mongo_connection, get_database from app.core.config import settings # Use standard UUID for consistency across services MERCHANT_ID = "01234567-89ab-cdef-0123-456789abcdef" # Cuatro Beauty Ltd UUID # Sample Services SAMPLE_SERVICES = [ { "name": "Hair Cut – Women", "code": "HC-WOMEN-45", "category_id": "hair", "category_name": "Hair", "description": "Includes wash, cut and blow-dry", "duration_mins": 45, "price": 700, "gst_rate": 18, }, { "name": "Hair Cut – Men", "code": "HC-MEN-30", "category_id": "hair", "category_name": "Hair", "description": "Standard men's haircut", "duration_mins": 30, "price": 400, "gst_rate": 18, }, { "name": "Hair Color – Full", "code": "COL-FULL-120", "category_id": "hair", "category_name": "Hair", "description": "Complete hair coloring with premium products", "duration_mins": 120, "price": 3500, "gst_rate": 18, }, { "name": "Hair Spa Treatment", "code": "SPA-HAIR-60", "category_id": "spa", "category_name": "Spa", "description": "Deep conditioning and scalp treatment", "duration_mins": 60, "price": 1500, "gst_rate": 18, }, { "name": "Facial – Classic", "code": "FACE-CLS-45", "category_id": "facial", "category_name": "Facial", "description": "Deep cleansing facial with mask", "duration_mins": 45, "price": 1200, "gst_rate": 18, }, { "name": "Manicure", "code": "MANI-30", "category_id": "nails", "category_name": "Nails", "description": "Classic manicure with nail polish", "duration_mins": 30, "price": 500, "gst_rate": 18, }, { "name": "Pedicure", "code": "PEDI-45", "category_id": "nails", "category_name": "Nails", "description": "Classic pedicure with foot massage", "duration_mins": 45, "price": 700, "gst_rate": 18, }, { "name": "Blow Dry & Styling", "code": "STYLE-30", "category_id": "hair", "category_name": "Hair", "description": "Professional blow dry and styling", "duration_mins": 30, "price": 600, "gst_rate": 18, }, { "name": "Makeup – Party", "code": "MKP-PARTY-60", "category_id": "makeup", "category_name": "Makeup", "description": "Party makeup with false lashes", "duration_mins": 60, "price": 2500, "gst_rate": 18, }, { "name": "Waxing – Full Arms", "code": "WAX-ARMS-20", "category_id": "waxing", "category_name": "Waxing", "description": "Full arms waxing", "duration_mins": 20, "price": 400, "gst_rate": 18, }, ] # Sample Staff SAMPLE_STAFF = [ { "name": "Priya Sharma", "role": "Senior Stylist", "staff_code": "STF001", "phone": "+91-9876543210", "email": "priya.sharma@retail.com", "skills": ["Haircut", "Color", "Styling", "Hair Spa"], "working_hours": [ {"day": "Mon", "from": "10:00", "to": "19:00"}, {"day": "Tue", "from": "10:00", "to": "19:00"}, {"day": "Wed", "from": "10:00", "to": "19:00"}, {"day": "Thu", "from": "10:00", "to": "19:00"}, {"day": "Fri", "from": "10:00", "to": "19:00"}, {"day": "Sat", "from": "11:00", "to": "18:00"}, ], }, { "name": "Rajesh Kumar", "role": "Stylist", "staff_code": "STF002", "phone": "+91-9876543211", "email": "rajesh.kumar@retail.com", "skills": ["Haircut", "Styling", "Beard Trim"], "working_hours": [ {"day": "Mon", "from": "10:00", "to": "19:00"}, {"day": "Tue", "from": "10:00", "to": "19:00"}, {"day": "Wed", "from": "10:00", "to": "19:00"}, {"day": "Thu", "from": "10:00", "to": "19:00"}, {"day": "Fri", "from": "10:00", "to": "19:00"}, ], }, { "name": "Anjali Verma", "role": "Makeup Artist", "staff_code": "STF003", "phone": "+91-9876543212", "email": "anjali.verma@retail.com", "skills": ["Makeup", "Facial", "Bridal Makeup"], "working_hours": [ {"day": "Tue", "from": "11:00", "to": "20:00"}, {"day": "Wed", "from": "11:00", "to": "20:00"}, {"day": "Thu", "from": "11:00", "to": "20:00"}, {"day": "Fri", "from": "11:00", "to": "20:00"}, {"day": "Sat", "from": "10:00", "to": "19:00"}, {"day": "Sun", "from": "10:00", "to": "17:00"}, ], }, { "name": "Meera Patel", "role": "Nail Technician", "staff_code": "STF004", "phone": "+91-9876543213", "email": "meera.patel@retail.com", "skills": ["Manicure", "Pedicure", "Nail Art"], "working_hours": [ {"day": "Mon", "from": "10:00", "to": "19:00"}, {"day": "Tue", "from": "10:00", "to": "19:00"}, {"day": "Wed", "from": "10:00", "to": "19:00"}, {"day": "Thu", "from": "10:00", "to": "19:00"}, {"day": "Fri", "from": "10:00", "to": "19:00"}, {"day": "Sat", "from": "11:00", "to": "18:00"}, ], }, ] # Sample Customers SAMPLE_CUSTOMERS = [ { "name": "Neha Kapoor", "phone": "+91-9988776655", "email": "neha.kapoor@example.com", "notes": "Regular customer, prefers morning appointments", }, { "name": "Arjun Reddy", "phone": "+91-9988776656", "email": "arjun.reddy@example.com", "notes": "Walk-in customer", }, { "name": "Kavya Nair", "phone": "+91-9988776657", "email": "kavya.nair@example.com", "notes": "Prefers specific stylist - Priya", }, ] async def seed_services(merchant_id: str): """Seed catalogue services.""" db = get_database() if db is None: print("❌ MongoDB not connected. Cannot seed data.") return False collection = db["catalogue_services"] print("\n📋 Seeding Catalogue Services...") created_count = 0 skipped_count = 0 for service in SAMPLE_SERVICES: # Check if service code already exists existing = await collection.find_one({ "merchant_id": merchant_id, "code": service["code"] }) if existing: print(f" ⏭️ Skipped: {service['name']} (code: {service['code']}) - already exists") skipped_count += 1 continue service_id = str(uuid4()) now = datetime.utcnow() doc = { "_id": service_id, "merchant_id": merchant_id, "name": service["name"], "code": service["code"], "category": { "id": service["category_id"], "name": service["category_name"] }, "description": service["description"], "duration_mins": service["duration_mins"], "pricing": { "price": service["price"], "currency": "INR", "gst_rate": service["gst_rate"] }, "status": "active", "sort_order": created_count, "created_at": now, "updated_at": now } await collection.insert_one(doc) print(f" ✅ Created: {service['name']} (₹{service['price']}, {service['duration_mins']} mins)") created_count += 1 print(f"\n 📊 Services: {created_count} created, {skipped_count} skipped") return True async def seed_staff(merchant_id: str): """Seed staff members.""" db = get_database() if db is None: print("❌ MongoDB not connected. Cannot seed data.") return False collection = db["pos_staff"] print("\n👥 Seeding Staff...") created_count = 0 skipped_count = 0 for staff in SAMPLE_STAFF: # Check if staff code already exists existing = await collection.find_one({ "merchant_id": merchant_id, "staff_code": staff["staff_code"] }) if existing: print(f" ⏭️ Skipped: {staff['name']} ({staff['staff_code']}) - already exists") skipped_count += 1 continue staff_id = f"staff_{uuid4().hex[:16]}" now = datetime.utcnow() doc = { "staff_id": staff_id, "merchant_id": merchant_id, "name": staff["name"], "role": staff["role"], "staff_code": staff["staff_code"], "contact": { "phone": staff["phone"], "email": staff["email"] }, "skills": staff["skills"], "status": "active", "working_hours": staff["working_hours"], "created_at": now, "updated_at": now } await collection.insert_one(doc) print(f" ✅ Created: {staff['name']} - {staff['role']}") created_count += 1 print(f"\n 📊 Staff: {created_count} created, {skipped_count} skipped") return True async def seed_customers(merchant_id: str): """Seed sample customers.""" db = get_database() if db is None: print("❌ MongoDB not connected. Cannot seed data.") return False collection = db["pos_customers"] print("\n👤 Seeding Customers...") created_count = 0 skipped_count = 0 for customer in SAMPLE_CUSTOMERS: # Check if customer phone already exists existing = await collection.find_one({ "merchant_id": merchant_id, "phone": customer["phone"] }) if existing: print(f" ⏭️ Skipped: {customer['name']} ({customer['phone']}) - already exists") skipped_count += 1 continue customer_id = str(uuid4()) now = datetime.utcnow() doc = { "customer_id": customer_id, "merchant_id": merchant_id, "name": customer["name"], "phone": customer["phone"], "email": customer["email"], "notes": customer["notes"], "created_at": now, "updated_at": now } await collection.insert_one(doc) print(f" ✅ Created: {customer['name']} ({customer['phone']})") created_count += 1 print(f"\n 📊 Customers: {created_count} created, {skipped_count} skipped") return True async def main(merchant_id: str): """Main seed function.""" print("="*60) print("🌱 POS Microservice - Seed Data Script") print("="*60) print(f"\n📍 Merchant ID: {merchant_id}") print(f"📍 MongoDB URI: {settings.MONGODB_URI}") print(f"📍 Database: {settings.MONGODB_DB_NAME}") # Connect to MongoDB try: await connect_to_mongo() except Exception as e: print(f"\n❌ Failed to connect to MongoDB: {e}") print("\n💡 Make sure MongoDB is running:") print(" docker run -d --name mongo -p 27017:27017 mongo:6") return # Seed data try: success = True success = await seed_services(merchant_id) and success success = await seed_staff(merchant_id) and success success = await seed_customers(merchant_id) and success if success: print("\n" + "="*60) print("✅ Seed data completed successfully!") print("="*60) print("\n💡 You can now:") print(" 1. Start the API: uvicorn app.main:app --reload --port 8282") print(f" 2. List services: GET /api/v1/pos/catalogue/services?merchant_id={merchant_id}") print(f" 3. Create appointments with the seeded services and staff") else: print("\n⚠️ Seed data completed with some issues") except Exception as e: print(f"\n❌ Error during seeding: {e}") import traceback traceback.print_exc() finally: await close_mongo_connection() if __name__ == "__main__": parser = argparse.ArgumentParser(description="Seed POS microservice data") parser.add_argument( "--merchant-id", type=str, default=MERCHANT_ID, help=f"Merchant UUID (default: {MERCHANT_ID})" ) args = parser.parse_args() asyncio.run(main(args.merchant_id))