zombee11/scorecardapi
1
1from fastapi import APIRouter, Depends, HTTPException, Query, status2from sqlalchemy import func, select3from sqlalchemy.orm import Session4 5from app.api.dependencies import require_auth6from app.db.session import get_db7from app.models.rule import RuleMaster8from app.schemas.rule import RuleCreate, RuleResponse, RuleStatusUpdate, RuleUpdate9from app.services.audit import rule_to_dict, write_rule_audit10from app.services.rule_repository import RuleRepository11 12router = APIRouter(prefix="/rules", tags=["Rule Management"], dependencies=[Depends(require_auth)])13repo = RuleRepository()14 15 16@router.get("", response_model=list[RuleResponse])17def list_rules(18 tenant_id: str | None = None,19 product_type: str | None = None,20 dealer_id: str | None = None,21 rule_type: str | None = None,22 is_active: bool | None = Query(default=None),23 db: Session = Depends(get_db),24) -> list[RuleMaster]:25 return repo.list_rules(db, tenant_id, product_type, dealer_id, rule_type, is_active)26 27 28@router.post("", response_model=RuleResponse, status_code=status.HTTP_201_CREATED)29def create_rule(payload: RuleCreate, db: Session = Depends(get_db)) -> RuleMaster:30 dealer_filter = (31 RuleMaster.dealer_id.is_(None)32 if payload.dealer_id is None33 else RuleMaster.dealer_id == payload.dealer_id34 )35 latest_version = db.scalar(36 select(func.max(RuleMaster.version)).where(37 RuleMaster.rule_code == payload.rule_code,38 RuleMaster.tenant_id == payload.tenant_id,39 RuleMaster.product_type == payload.product_type,40 dealer_filter,41 )42 )43 rule = RuleMaster(**payload.model_dump(), version=(latest_version or 0) + 1)44 db.add(rule)45 db.flush()46 write_rule_audit(db, rule.id, "CREATE", payload.created_by, None, rule_to_dict(rule))47 db.commit()48 db.refresh(rule)49 repo.invalidate(rule.tenant_id, rule.product_type, rule.dealer_id)50 return rule51 52 53@router.put("/{rule_id}", response_model=RuleResponse)54def update_rule(rule_id: int, payload: RuleUpdate, db: Session = Depends(get_db)) -> RuleMaster:55 rule = db.get(RuleMaster, rule_id)56 if not rule:57 raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Rule not found")58 before = rule_to_dict(rule)59 updates = payload.model_dump(exclude_unset=True)60 actor = updates.pop("actor", "system")61 for field, value in updates.items():62 setattr(rule, field, value)63 write_rule_audit(db, rule.id, "UPDATE", actor, before, rule_to_dict(rule))64 db.commit()65 db.refresh(rule)66 repo.invalidate(rule.tenant_id, rule.product_type, rule.dealer_id)67 return rule68 69 70@router.patch("/{rule_id}/status", response_model=RuleResponse)71def update_rule_status(72 rule_id: int, payload: RuleStatusUpdate, db: Session = Depends(get_db)73) -> RuleMaster:74 rule = db.get(RuleMaster, rule_id)75 if not rule:76 raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Rule not found")77 before = rule_to_dict(rule)78 rule.is_active = payload.is_active79 write_rule_audit(db, rule.id, "STATUS_UPDATE", payload.actor, before, rule_to_dict(rule))80 db.commit()81 db.refresh(rule)82 repo.invalidate(rule.tenant_id, rule.product_type, rule.dealer_id)83 return rule84 