17a0218b32
- 新增 mini_business_logs 表(business_id/log_date/method/content/created_by) - MiniBusiness 模型添加 logs relationship(cascade delete) - 5个端点: GET列表/POST新增/PUT编辑/DELETE删除 - 跟进方式: 电话/微信/上门/邮件/其他 - lifespan 自动建表+索引 Co-Authored-By: Claude <noreply@anthropic.com>
144 lines
4.8 KiB
Python
144 lines
4.8 KiB
Python
"""MiniBusinessLog CRUD API — follow-up log entries for mini business opportunities."""
|
|
|
|
import uuid
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from app.database import get_db
|
|
from app.middleware.auth import get_current_user, require_any_role
|
|
from app.models.mini_business import MiniBusiness
|
|
from app.models.mini_business_log import MiniBusinessLog
|
|
from app.models.user import User
|
|
from app.schemas.mini_business_log import (
|
|
MiniBusinessLogCreate, MiniBusinessLogUpdate, MiniBusinessLogOut,
|
|
)
|
|
|
|
router = APIRouter(prefix="/mini-business", tags=["MiniBusiness Logs"])
|
|
|
|
|
|
async def _get_log(db: AsyncSession, log_id: str) -> MiniBusinessLog:
|
|
result = await db.execute(select(MiniBusinessLog).where(MiniBusinessLog.id == log_id))
|
|
log = result.scalar_one_or_none()
|
|
if not log:
|
|
raise HTTPException(status_code=404, detail="跟进记录不存在")
|
|
return log
|
|
|
|
|
|
@router.get("/{business_id}/logs")
|
|
async def list_logs(
|
|
business_id: str,
|
|
current_user: dict = Depends(get_current_user),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""List follow-up logs for a mini business, newest first."""
|
|
# Verify business exists and user has access
|
|
mb = await db.get(MiniBusiness, business_id)
|
|
if not mb:
|
|
raise HTTPException(status_code=404, detail="商机不存在")
|
|
if current_user["role"] == "manager" and str(mb.manager_id) != current_user["user_id"]:
|
|
raise HTTPException(status_code=403, detail="Access denied")
|
|
|
|
result = await db.execute(
|
|
select(MiniBusinessLog)
|
|
.where(MiniBusinessLog.business_id == business_id)
|
|
.order_by(MiniBusinessLog.log_date.desc(), MiniBusinessLog.created_at.desc())
|
|
)
|
|
logs = result.scalars().all()
|
|
|
|
# Resolve creator names
|
|
user_ids = {log.created_by for log in logs}
|
|
users = (await db.execute(select(User).where(User.id.in_(user_ids)))).scalars().all()
|
|
user_map = {u.id: u.name for u in users}
|
|
|
|
return [
|
|
{
|
|
"id": log.id,
|
|
"business_id": log.business_id,
|
|
"log_date": str(log.log_date),
|
|
"method": log.method,
|
|
"content": log.content,
|
|
"created_by": log.created_by,
|
|
"created_by_name": user_map.get(log.created_by, ""),
|
|
"created_at": str(log.created_at) if log.created_at else None,
|
|
}
|
|
for log in logs
|
|
]
|
|
|
|
|
|
@router.post("/{business_id}/logs")
|
|
async def create_log(
|
|
business_id: str,
|
|
data: MiniBusinessLogCreate,
|
|
current_user: dict = Depends(require_any_role),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Add a follow-up log entry."""
|
|
mb = await db.get(MiniBusiness, business_id)
|
|
if not mb:
|
|
raise HTTPException(status_code=404, detail="商机不存在")
|
|
if current_user["role"] == "manager" and str(mb.manager_id) != current_user["user_id"]:
|
|
raise HTTPException(status_code=403, detail="Access denied")
|
|
|
|
log = MiniBusinessLog(
|
|
business_id=uuid.UUID(business_id),
|
|
log_date=data.log_date,
|
|
method=data.method,
|
|
content=data.content,
|
|
created_by=uuid.UUID(current_user["user_id"]),
|
|
)
|
|
db.add(log)
|
|
await db.commit()
|
|
await db.refresh(log)
|
|
|
|
creator = await db.get(User, log.created_by)
|
|
return {
|
|
"id": log.id,
|
|
"business_id": log.business_id,
|
|
"log_date": str(log.log_date),
|
|
"method": log.method,
|
|
"content": log.content,
|
|
"created_by": log.created_by,
|
|
"created_by_name": creator.name if creator else "",
|
|
"created_at": str(log.created_at) if log.created_at else None,
|
|
}
|
|
|
|
|
|
@router.put("/logs/{log_id}")
|
|
async def update_log(
|
|
log_id: str,
|
|
data: MiniBusinessLogUpdate,
|
|
current_user: dict = Depends(require_any_role),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Update a follow-up log entry."""
|
|
log = await _get_log(db, log_id)
|
|
|
|
# Managers can only edit their own logs; directors/leaders can edit any
|
|
if current_user["role"] == "manager" and str(log.created_by) != current_user["user_id"]:
|
|
raise HTTPException(status_code=403, detail="Access denied")
|
|
|
|
update_data = data.model_dump(exclude_unset=True)
|
|
for k, v in update_data.items():
|
|
setattr(log, k, v)
|
|
|
|
await db.commit()
|
|
await db.refresh(log)
|
|
return {"id": log.id, "log_date": str(log.log_date), "method": log.method, "content": log.content}
|
|
|
|
|
|
@router.delete("/logs/{log_id}")
|
|
async def delete_log(
|
|
log_id: str,
|
|
current_user: dict = Depends(require_any_role),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""Delete a follow-up log entry."""
|
|
log = await _get_log(db, log_id)
|
|
|
|
if current_user["role"] == "manager" and str(log.created_by) != current_user["user_id"]:
|
|
raise HTTPException(status_code=403, detail="Access denied")
|
|
|
|
await db.delete(log)
|
|
await db.commit()
|
|
return {"status": "deleted"}
|