cuatrolabs-pos-ms / scripts /seed_data.py
MukeshKapoor25's picture
docs: Update terminology from "salon" to "retail" for consistency
17b18e9
Raw History Blame Contribute Delete
13.4 kB
"""
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 <uuid>
"""
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))