Support filtered and selected export on apply and disburse/process board pages. Co-authored-by: Cursor <cursoragent@cursor.com>
306 lines
11 KiB
Python
306 lines
11 KiB
Python
"""车辆尿素 API"""
|
|
from datetime import date, datetime
|
|
from typing import List, Optional
|
|
|
|
from pydantic import BaseModel, Field
|
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.database import get_db
|
|
from app.core.db_auth import DbUserContext, get_db_current_user
|
|
from app.core.tenant_context import get_tenant_no
|
|
from app.utils.excel_export import (
|
|
EXPORT_MAX_ROWS,
|
|
ExportColumn,
|
|
ExportValidationError,
|
|
export_rows_to_xlsx_response,
|
|
filter_export_columns,
|
|
)
|
|
from app.schemas.pl.vehicle_urea import (
|
|
VehicleUreaApplyCreate,
|
|
VehicleUreaApplyListResponse,
|
|
VehicleUreaApplyRead,
|
|
VehicleUreaApplyUpdate,
|
|
VehicleUreaDisburseBoardListResponse,
|
|
VehicleUreaDisburseCreate,
|
|
VehicleUreaDisburseRead,
|
|
VehicleUreaDisburseUpdate,
|
|
)
|
|
from app.services import pl_vehicle_urea_service as svc
|
|
|
|
apply_router = APIRouter(prefix="/vehicle-urea-apply", tags=["运输计划-车辆尿素申请"])
|
|
disburse_router = APIRouter(prefix="/vehicle-urea-disburse", tags=["运输计划-车辆尿素发放"])
|
|
|
|
|
|
@apply_router.get("/", response_model=VehicleUreaApplyListResponse)
|
|
def list_applies(
|
|
q: Optional[str] = Query(default=None),
|
|
status: Optional[str] = Query(default=None),
|
|
apply_date_from: Optional[date] = Query(default=None, alias="applyDateFrom"),
|
|
apply_date_to: Optional[date] = Query(default=None, alias="applyDateTo"),
|
|
applicant_id: Optional[str] = Query(default=None, alias="applicantId"),
|
|
page: int = Query(default=1, ge=1),
|
|
page_size: int = Query(default=20, ge=1, le=500, alias="pageSize"),
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
) -> VehicleUreaApplyListResponse:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
items, total = svc.list_applies(
|
|
db,
|
|
tenant_no,
|
|
user,
|
|
q=q,
|
|
status=status,
|
|
apply_date_from=apply_date_from,
|
|
apply_date_to=apply_date_to,
|
|
applicant_id=applicant_id,
|
|
page=page,
|
|
page_size=page_size,
|
|
)
|
|
return VehicleUreaApplyListResponse(
|
|
items=items, total=total, page=page, pageSize=page_size
|
|
)
|
|
|
|
|
|
|
|
UREA_APPLY_EXPORT_COLUMNS = [
|
|
ExportColumn(title="申请单号", field="applyNo"),
|
|
ExportColumn(title="车牌号", field="licensePlate"),
|
|
ExportColumn(title="申请时间", field="applyDate"),
|
|
ExportColumn(title="入库时间", field="warehouseInDate"),
|
|
ExportColumn(title="单位", field="unit"),
|
|
ExportColumn(title="入库数量", field="quantity"),
|
|
ExportColumn(title="申请人", field="applicantName"),
|
|
ExportColumn(title="状态", field="status"),
|
|
]
|
|
|
|
|
|
class UreaApplyExportBody(BaseModel):
|
|
q: Optional[str] = None
|
|
status: Optional[str] = None
|
|
apply_date_from: Optional[date] = Field(default=None, alias="applyDateFrom")
|
|
apply_date_to: Optional[date] = Field(default=None, alias="applyDateTo")
|
|
ids: Optional[List[str]] = None
|
|
columns: Optional[List[str]] = None
|
|
model_config = {"populate_by_name": True}
|
|
|
|
|
|
@apply_router.post("/export")
|
|
def export_urea_applies(
|
|
body: UreaApplyExportBody,
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
):
|
|
try:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
items, _ = svc.list_applies(
|
|
db, tenant_no, user,
|
|
q=body.q, status=body.status,
|
|
apply_date_from=body.apply_date_from, apply_date_to=body.apply_date_to,
|
|
ids=body.ids, page=1, page_size=EXPORT_MAX_ROWS, max_page_size=EXPORT_MAX_ROWS,
|
|
)
|
|
|
|
rows = []
|
|
for item in items:
|
|
data = item.model_dump(by_alias=True)
|
|
for k, v in list(data.items()):
|
|
if hasattr(v, 'isoformat'):
|
|
data[k] = str(v)[:19]
|
|
rows.append(data)
|
|
|
|
cols = filter_export_columns(UREA_APPLY_EXPORT_COLUMNS, body.columns)
|
|
date_str = datetime.now().strftime("%Y%m%d")
|
|
return export_rows_to_xlsx_response(
|
|
db, tenant_no=tenant_no, sheet_title="尿素申请", columns=cols, rows=rows,
|
|
filename_stem=f"尿素申请_{date_str}",
|
|
)
|
|
except ExportValidationError as e:
|
|
raise HTTPException(status_code=400, detail=str(e)) from e
|
|
|
|
|
|
@apply_router.get("/{id}", response_model=VehicleUreaApplyRead)
|
|
def get_apply(
|
|
id: str,
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
) -> VehicleUreaApplyRead:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
return svc.get_apply(db, tenant_no, user, id)
|
|
|
|
|
|
@apply_router.post("/", response_model=VehicleUreaApplyRead, status_code=status.HTTP_201_CREATED)
|
|
def create_apply(
|
|
payload: VehicleUreaApplyCreate,
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
) -> VehicleUreaApplyRead:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
return svc.create_apply(db, tenant_no, user, payload)
|
|
|
|
|
|
@apply_router.put("/{id}", response_model=VehicleUreaApplyRead)
|
|
def update_apply(
|
|
id: str,
|
|
payload: VehicleUreaApplyUpdate,
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
) -> VehicleUreaApplyRead:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
return svc.update_apply(db, tenant_no, user, id, payload)
|
|
|
|
|
|
@apply_router.post("/{id}/cancel", response_model=VehicleUreaApplyRead)
|
|
def cancel_apply(
|
|
id: str,
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
) -> VehicleUreaApplyRead:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
return svc.cancel_apply(db, tenant_no, user, id)
|
|
|
|
|
|
@apply_router.delete("/{ids}", status_code=status.HTTP_204_NO_CONTENT)
|
|
def delete_applies(
|
|
ids: str,
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
) -> None:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
apply_ids = [item for item in ids.split(",") if item]
|
|
svc.delete_applies(db, tenant_no, user, apply_ids)
|
|
|
|
|
|
@disburse_router.get("/disburse-board", response_model=VehicleUreaDisburseBoardListResponse)
|
|
def list_disburse_board(
|
|
q: Optional[str] = Query(default=None),
|
|
apply_status: Optional[str] = Query(default=None, alias="applyStatus"),
|
|
apply_date_from: Optional[date] = Query(default=None, alias="applyDateFrom"),
|
|
apply_date_to: Optional[date] = Query(default=None, alias="applyDateTo"),
|
|
disburse_date_from: Optional[date] = Query(default=None, alias="disburseDateFrom"),
|
|
disburse_date_to: Optional[date] = Query(default=None, alias="disburseDateTo"),
|
|
page: int = Query(default=1, ge=1),
|
|
page_size: int = Query(default=20, ge=1, le=500, alias="pageSize"),
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
) -> VehicleUreaDisburseBoardListResponse:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
items, total = svc.list_disburse_board(
|
|
db,
|
|
tenant_no,
|
|
user,
|
|
q=q,
|
|
apply_status=apply_status,
|
|
apply_date_from=apply_date_from,
|
|
apply_date_to=apply_date_to,
|
|
disburse_date_from=disburse_date_from,
|
|
disburse_date_to=disburse_date_to,
|
|
page=page,
|
|
page_size=page_size,
|
|
)
|
|
return VehicleUreaDisburseBoardListResponse(
|
|
items=items, total=total, page=page, pageSize=page_size
|
|
)
|
|
|
|
|
|
|
|
UREA_DISBURSE_EXPORT_COLUMNS = [
|
|
ExportColumn(title="申请单号", field="applyNo"),
|
|
ExportColumn(title="车牌号", field="licensePlate"),
|
|
ExportColumn(title="申请时间", field="applyDate"),
|
|
ExportColumn(title="入库时间", field="warehouseInDate"),
|
|
ExportColumn(title="申请人", field="applicantName"),
|
|
ExportColumn(title="单位", field="unit"),
|
|
ExportColumn(title="入库数量", field="quantity"),
|
|
ExportColumn(title="申请状态", field="applyStatus"),
|
|
ExportColumn(title="发放日期", field="disburseDate"),
|
|
ExportColumn(title="发放金额", field="amount"),
|
|
]
|
|
|
|
|
|
class UreaDisburseExportBody(BaseModel):
|
|
q: Optional[str] = None
|
|
apply_status: Optional[str] = Field(default=None, alias="applyStatus")
|
|
apply_date_from: Optional[date] = Field(default=None, alias="applyDateFrom")
|
|
apply_date_to: Optional[date] = Field(default=None, alias="applyDateTo")
|
|
disburse_date_from: Optional[date] = Field(default=None, alias="disburseDateFrom")
|
|
disburse_date_to: Optional[date] = Field(default=None, alias="disburseDateTo")
|
|
ids: Optional[List[str]] = None
|
|
columns: Optional[List[str]] = None
|
|
model_config = {"populate_by_name": True}
|
|
|
|
|
|
@disburse_router.post("/disburse-board/export")
|
|
def export_urea_disburse_board(
|
|
body: UreaDisburseExportBody,
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
):
|
|
try:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
items, _ = svc.list_disburse_board(
|
|
db, tenant_no, user,
|
|
q=body.q, apply_status=body.apply_status,
|
|
apply_date_from=body.apply_date_from, apply_date_to=body.apply_date_to,
|
|
disburse_date_from=body.disburse_date_from, disburse_date_to=body.disburse_date_to,
|
|
ids=body.ids, page=1, page_size=EXPORT_MAX_ROWS, max_page_size=EXPORT_MAX_ROWS,
|
|
)
|
|
|
|
rows = []
|
|
for item in items:
|
|
data = item.model_dump(by_alias=True)
|
|
for k, v in list(data.items()):
|
|
if hasattr(v, 'isoformat'):
|
|
data[k] = str(v)[:19]
|
|
rows.append(data)
|
|
|
|
cols = filter_export_columns(UREA_DISBURSE_EXPORT_COLUMNS, body.columns)
|
|
date_str = datetime.now().strftime("%Y%m%d")
|
|
return export_rows_to_xlsx_response(
|
|
db, tenant_no=tenant_no, sheet_title="尿素发放", columns=cols, rows=rows,
|
|
filename_stem=f"尿素发放_{date_str}",
|
|
)
|
|
except ExportValidationError as e:
|
|
raise HTTPException(status_code=400, detail=str(e)) from e
|
|
|
|
|
|
@disburse_router.get("/{id}", response_model=VehicleUreaDisburseRead)
|
|
def get_disburse(
|
|
id: str,
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
) -> VehicleUreaDisburseRead:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
return svc.get_disburse(db, tenant_no, user, id)
|
|
|
|
|
|
@disburse_router.post("/", response_model=VehicleUreaDisburseRead, status_code=status.HTTP_201_CREATED)
|
|
def create_disburse(
|
|
payload: VehicleUreaDisburseCreate,
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
) -> VehicleUreaDisburseRead:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
return svc.create_disburse(db, tenant_no, user, payload)
|
|
|
|
|
|
@disburse_router.put("/{id}", response_model=VehicleUreaDisburseRead)
|
|
def update_disburse(
|
|
id: str,
|
|
payload: VehicleUreaDisburseUpdate,
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
) -> VehicleUreaDisburseRead:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
return svc.update_disburse(db, tenant_no, user, id, payload)
|
|
|
|
|
|
@disburse_router.delete("/{ids}", status_code=status.HTTP_204_NO_CONTENT)
|
|
def delete_disburses(
|
|
ids: str,
|
|
db: Session = Depends(get_db),
|
|
user: DbUserContext = Depends(get_db_current_user),
|
|
) -> None:
|
|
tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
|
|
disburse_ids = [item for item in ids.split(",") if item]
|
|
svc.delete_disburses(db, tenant_no, user, disburse_ids)
|