- Frontend: Next.js 14 with TypeScript - Backend: FastAPI with SQLAlchemy - Agent: Carmodoo sync agent - Deployment: Docker Compose based staging/production setup - Scripts: Automated deployment with rollback support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
155 lines
4.8 KiB
Python
155 lines
4.8 KiB
Python
"""
|
|
Migration script: Generate PDFs for existing performance check records
|
|
|
|
This script:
|
|
1. Finds all CarPerformanceCheck records that have check_number but no pdf_path
|
|
2. Generates PDF for each using Playwright
|
|
3. Updates the pdf_path in the database
|
|
|
|
Usage:
|
|
cd backend
|
|
python scripts/migrate_performance_check_to_pdf.py
|
|
|
|
Requirements:
|
|
pip install playwright
|
|
playwright install chromium
|
|
"""
|
|
|
|
import asyncio
|
|
import sys
|
|
import os
|
|
|
|
# Add parent directory to path for imports
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
from sqlalchemy import create_engine
|
|
from sqlalchemy.orm import sessionmaker
|
|
from app.database import Base
|
|
from app.models import CarPerformanceCheck
|
|
from app.services.pdf_service import capture_performance_check_pdf, PLAYWRIGHT_AVAILABLE
|
|
|
|
# Database connection
|
|
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./autonetsellcar.db")
|
|
|
|
|
|
async def migrate_performance_checks():
|
|
"""Migrate existing performance checks to PDF format"""
|
|
|
|
if not PLAYWRIGHT_AVAILABLE:
|
|
print("ERROR: Playwright is not installed. Please run:")
|
|
print(" pip install playwright")
|
|
print(" playwright install chromium")
|
|
return
|
|
|
|
# Create database session
|
|
engine = create_engine(DATABASE_URL)
|
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
db = SessionLocal()
|
|
|
|
try:
|
|
# Find all performance checks without PDF
|
|
records = db.query(CarPerformanceCheck).filter(
|
|
CarPerformanceCheck.check_number.isnot(None),
|
|
CarPerformanceCheck.check_number != "",
|
|
(CarPerformanceCheck.pdf_path.is_(None)) | (CarPerformanceCheck.pdf_path == "")
|
|
).all()
|
|
|
|
total = len(records)
|
|
print(f"Found {total} performance check records to migrate")
|
|
|
|
if total == 0:
|
|
print("No records to migrate. Done.")
|
|
return
|
|
|
|
success_count = 0
|
|
error_count = 0
|
|
|
|
for i, record in enumerate(records, 1):
|
|
print(f"\n[{i}/{total}] Processing car_id={record.car_id}, check_number={record.check_number}")
|
|
|
|
try:
|
|
pdf_path = await capture_performance_check_pdf(
|
|
record.check_number,
|
|
record.car_id
|
|
)
|
|
|
|
if pdf_path:
|
|
record.pdf_path = pdf_path
|
|
db.commit()
|
|
print(f" SUCCESS: {pdf_path}")
|
|
success_count += 1
|
|
else:
|
|
print(f" FAILED: PDF generation returned None")
|
|
error_count += 1
|
|
|
|
except Exception as e:
|
|
print(f" ERROR: {e}")
|
|
error_count += 1
|
|
db.rollback()
|
|
|
|
# Small delay to avoid overwhelming the server
|
|
await asyncio.sleep(1)
|
|
|
|
print(f"\n{'='*50}")
|
|
print(f"Migration completed!")
|
|
print(f" Total: {total}")
|
|
print(f" Success: {success_count}")
|
|
print(f" Errors: {error_count}")
|
|
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
async def check_status():
|
|
"""Check current migration status"""
|
|
|
|
engine = create_engine(DATABASE_URL)
|
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
db = SessionLocal()
|
|
|
|
try:
|
|
total = db.query(CarPerformanceCheck).count()
|
|
with_check_num = db.query(CarPerformanceCheck).filter(
|
|
CarPerformanceCheck.check_number.isnot(None),
|
|
CarPerformanceCheck.check_number != ""
|
|
).count()
|
|
with_pdf = db.query(CarPerformanceCheck).filter(
|
|
CarPerformanceCheck.pdf_path.isnot(None),
|
|
CarPerformanceCheck.pdf_path != ""
|
|
).count()
|
|
|
|
print(f"Performance Check Status:")
|
|
print(f" Total records: {total}")
|
|
print(f" With check_number: {with_check_num}")
|
|
print(f" With PDF: {with_pdf}")
|
|
print(f" Pending migration: {with_check_num - with_pdf}")
|
|
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(description="Migrate performance checks to PDF")
|
|
parser.add_argument("--status", action="store_true", help="Show current status only")
|
|
parser.add_argument("--dry-run", action="store_true", help="Show what would be done without making changes")
|
|
args = parser.parse_args()
|
|
|
|
if args.status:
|
|
asyncio.run(check_status())
|
|
else:
|
|
print("Starting performance check PDF migration...")
|
|
print("This will generate PDFs for all existing performance check records.")
|
|
print()
|
|
|
|
if args.dry_run:
|
|
print("DRY RUN - No changes will be made")
|
|
asyncio.run(check_status())
|
|
else:
|
|
confirm = input("Continue? (y/n): ")
|
|
if confirm.lower() == 'y':
|
|
asyncio.run(migrate_performance_checks())
|
|
else:
|
|
print("Cancelled.")
|