egyedi jármű szerkesztés előtti mentés
This commit is contained in:
93
backend/app/scripts/seed_cost_category_visibility.py
Normal file
93
backend/app/scripts/seed_cost_category_visibility.py
Normal file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Seed script to update CostCategory visibility and accounting_code values.
|
||||
Also drops the old 'cost_category' column from asset_costs table.
|
||||
|
||||
Usage: docker compose exec sf_api python -m app.scripts.seed_cost_category_visibility
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy import text
|
||||
from app.core.config import settings
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Visibility rules:
|
||||
# - FUEL, MAINTENANCE, SERVICE, TIRE, INSURANCE, PARKING, TOLL, OTHER -> 'both'
|
||||
# - FINANCE, ADMIN -> 'b2b'
|
||||
|
||||
VISIBILITY_MAP = {
|
||||
"FUEL": "both",
|
||||
"MAINTENANCE": "both",
|
||||
"SERVICE": "both",
|
||||
"TIRE": "both",
|
||||
"INSURANCE": "both",
|
||||
"PARKING": "both",
|
||||
"TOLL": "both",
|
||||
"OTHER": "both",
|
||||
"FINANCE": "b2b",
|
||||
"ADMIN": "b2b",
|
||||
}
|
||||
|
||||
|
||||
async def main():
|
||||
engine = create_async_engine(str(settings.SQLALCHEMY_DATABASE_URI))
|
||||
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||
|
||||
async with async_session() as session:
|
||||
# 1. Update visibility for existing categories
|
||||
logger.info("🔄 Updating visibility for existing cost categories...")
|
||||
for code, visibility in VISIBILITY_MAP.items():
|
||||
result = await session.execute(
|
||||
text("""
|
||||
UPDATE vehicle.cost_categories
|
||||
SET visibility = :visibility
|
||||
WHERE code = :code AND (visibility IS NULL OR visibility = 'both')
|
||||
"""),
|
||||
{"code": code, "visibility": visibility}
|
||||
)
|
||||
if result.rowcount > 0:
|
||||
logger.info(f" ✅ {code} -> {visibility}")
|
||||
|
||||
# 2. Set default visibility for any categories without it
|
||||
result = await session.execute(
|
||||
text("""
|
||||
UPDATE vehicle.cost_categories
|
||||
SET visibility = 'both'
|
||||
WHERE visibility IS NULL
|
||||
""")
|
||||
)
|
||||
if result.rowcount > 0:
|
||||
logger.info(f" ✅ Set default 'both' for {result.rowcount} categories")
|
||||
|
||||
# 3. Drop the old cost_category column from asset_costs
|
||||
logger.info("🔄 Dropping old 'cost_category' column from asset_costs...")
|
||||
|
||||
# Check if the column still exists
|
||||
check = await session.execute(
|
||||
text("""
|
||||
SELECT column_name FROM information_schema.columns
|
||||
WHERE table_schema = 'vehicle'
|
||||
AND table_name = 'asset_costs'
|
||||
AND column_name = 'cost_category'
|
||||
""")
|
||||
)
|
||||
if check.scalar():
|
||||
await session.execute(
|
||||
text("ALTER TABLE vehicle.asset_costs DROP COLUMN cost_category")
|
||||
)
|
||||
logger.info(" ✅ Dropped old 'cost_category' column from vehicle.asset_costs")
|
||||
else:
|
||||
logger.info(" ⏭️ Column 'cost_category' already removed")
|
||||
|
||||
await session.commit()
|
||||
logger.info("✅ All updates completed successfully!")
|
||||
|
||||
await engine.dispose()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
114
backend/app/scripts/seed_cost_subcategories.py
Normal file
114
backend/app/scripts/seed_cost_subcategories.py
Normal file
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Seed script to insert cost subcategories (hierarchy) under existing parent categories.
|
||||
|
||||
Usage:
|
||||
docker compose exec sf_api python -m app.scripts.seed_cost_subcategories
|
||||
|
||||
Subcategories added:
|
||||
- FUEL (ID=1): FUEL_PETROL (Benzin), FUEL_DIESEL (Dízel), FUEL_ELECTRIC (Elektromos töltés), FUEL_LPG (LPG)
|
||||
- MAINTENANCE (ID=2): MAINT_OIL (Olajcsere), MAINT_SERVICE (Kötelező szerviz), MAINT_BRAKES (Fékcsere)
|
||||
- FEES (ID=6): FEE_HIGHWAY (Autópálya matrica), FEE_STREET_PARKING (Közterületi parkolás), FEE_GARAGE (Parkolóház)
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy import text
|
||||
from app.core.config import settings
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Subcategory definitions: (parent_code, code, name, description, visibility)
|
||||
SUBCATEGORIES = [
|
||||
# FUEL (parent_id=1)
|
||||
("FUEL", "FUEL_PETROL", "Benzin", "Benzin üzemanyag költség", "both"),
|
||||
("FUEL", "FUEL_DIESEL", "Dízel", "Dízel üzemanyag költség", "both"),
|
||||
("FUEL", "FUEL_ELECTRIC", "Elektromos töltés", "Elektromos jármű töltési költség", "both"),
|
||||
("FUEL", "FUEL_LPG", "LPG", "LPG (autógáz) üzemanyag költség", "both"),
|
||||
|
||||
# MAINTENANCE (parent_id=2)
|
||||
("MAINTENANCE", "MAINT_SERVICE", "Kötelező szerviz", "Gyártó által előírt időszakos szerviz", "both"),
|
||||
("MAINTENANCE", "MAINT_OIL", "Olajcsere", "Motorolaj és szűrő csere", "both"),
|
||||
("MAINTENANCE", "MAINT_BRAKES", "Fékcsere", "Fékbetét, féktárcsa csere", "both"),
|
||||
|
||||
# FEES (parent_id=6)
|
||||
("FEES", "FEE_HIGHWAY", "Autópálya matrica", "Országos autópálya használati díj", "both"),
|
||||
("FEES", "FEE_STREET_PARKING", "Közterületi parkolás", "Utcai parkolóóra / parkolási díj", "both"),
|
||||
("FEES", "FEE_GARAGE", "Parkolóház", "Mélygarázs vagy parkolóház díja", "both"),
|
||||
]
|
||||
|
||||
|
||||
async def main():
|
||||
engine = create_async_engine(str(settings.SQLALCHEMY_DATABASE_URI))
|
||||
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||
|
||||
async with async_session() as session:
|
||||
# Fetch parent categories map
|
||||
result = await session.execute(
|
||||
text("SELECT id, code FROM vehicle.cost_categories WHERE parent_id IS NULL")
|
||||
)
|
||||
parent_map = {row.code: row.id for row in result.fetchall()}
|
||||
logger.info(f"Found parent categories: {parent_map}")
|
||||
|
||||
# Fetch existing codes to avoid duplicates
|
||||
result = await session.execute(
|
||||
text("SELECT code FROM vehicle.cost_categories")
|
||||
)
|
||||
existing_codes = {row.code for row in result.fetchall()}
|
||||
|
||||
inserted_count = 0
|
||||
skipped_count = 0
|
||||
|
||||
for parent_code, code, name, description, visibility in SUBCATEGORIES:
|
||||
if code in existing_codes:
|
||||
logger.info(f" ⏭️ SKIP (already exists): {code}")
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
parent_id = parent_map.get(parent_code)
|
||||
if parent_id is None:
|
||||
logger.warning(f" ⚠️ Parent code '{parent_code}' not found, skipping {code}")
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
await session.execute(
|
||||
text("""
|
||||
INSERT INTO vehicle.cost_categories (code, name, description, parent_id, visibility, is_system, created_at, updated_at)
|
||||
VALUES (:code, :name, :description, :parent_id, :visibility, true, NOW(), NOW())
|
||||
"""),
|
||||
{
|
||||
"code": code,
|
||||
"name": name,
|
||||
"description": description,
|
||||
"parent_id": parent_id,
|
||||
"visibility": visibility,
|
||||
}
|
||||
)
|
||||
logger.info(f" ✅ INSERTED: {code} -> {parent_code} (parent_id={parent_id})")
|
||||
inserted_count += 1
|
||||
|
||||
await session.commit()
|
||||
logger.info(f"✅ Done! Inserted={inserted_count}, Skipped={skipped_count}")
|
||||
|
||||
# Verify the tree structure
|
||||
result = await session.execute(
|
||||
text("""
|
||||
SELECT p.code AS parent_code, p.name AS parent_name,
|
||||
c.id, c.code, c.name, c.parent_id
|
||||
FROM vehicle.cost_categories c
|
||||
JOIN vehicle.cost_categories p ON c.parent_id = p.id
|
||||
ORDER BY p.id, c.id
|
||||
""")
|
||||
)
|
||||
rows = result.fetchall()
|
||||
logger.info("\n=== HIERARCHY TREE ===")
|
||||
for row in rows:
|
||||
logger.info(f" {row.parent_code:15s} -> {row.code:20s} ({row.name})")
|
||||
|
||||
await engine.dispose()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user