| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- from __future__ import annotations
- from datetime import date
- from fastapi import APIRouter, Depends
- from sqlalchemy import func, text
- 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.models.db_models import DbInboundOutbound, DbWeighingSlip
- from app.schemas.db.dashboard import (
- DashboardCargoStat,
- DashboardPartnerCargoStat,
- DashboardStats,
- )
- router = APIRouter(prefix="/dashboard", tags=["dashboard"])
- @router.get("/stats", response_model=DashboardStats)
- def get_dashboard_stats(
- db: Session = Depends(get_db),
- user: DbUserContext = Depends(get_db_current_user),
- ) -> DashboardStats:
- tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
- today = date.today()
- today_inbound = float(
- db.query(func.coalesce(func.sum(DbInboundOutbound.quantity), 0))
- .filter(
- DbInboundOutbound.date == today,
- DbInboundOutbound.business_type == "入库",
- DbInboundOutbound.del_flag == 0,
- DbInboundOutbound.tenant_no == tenant_no,
- )
- .scalar()
- or 0
- )
- today_outbound = float(
- db.query(func.coalesce(func.sum(DbInboundOutbound.quantity), 0))
- .filter(
- DbInboundOutbound.date == today,
- DbInboundOutbound.business_type == "出库",
- DbInboundOutbound.del_flag == 0,
- DbInboundOutbound.tenant_no == tenant_no,
- )
- .scalar()
- or 0
- )
- abnormal_orders = int(
- db.query(func.count(DbWeighingSlip.id))
- .filter(
- DbWeighingSlip.is_voided == 0,
- DbWeighingSlip.del_flag == 0,
- DbWeighingSlip.tenant_no == tenant_no,
- )
- .scalar()
- or 0
- )
- return DashboardStats(
- today_inbound=today_inbound,
- today_outbound=today_outbound,
- abnormal_orders=abnormal_orders,
- )
- @router.get("/inbound/by-cargo", response_model=list[DashboardCargoStat])
- def get_inbound_by_cargo(
- db: Session = Depends(get_db),
- user: DbUserContext = Depends(get_db_current_user),
- ) -> list[DashboardCargoStat]:
- return _cargo_stats(db, user, business_type="入库")
- @router.get("/inbound/by-partner-cargo", response_model=list[DashboardPartnerCargoStat])
- def get_inbound_by_partner_cargo(
- db: Session = Depends(get_db),
- user: DbUserContext = Depends(get_db_current_user),
- ) -> list[DashboardPartnerCargoStat]:
- return _partner_cargo_stats(db, user, business_type="入库")
- @router.get("/outbound/by-cargo", response_model=list[DashboardCargoStat])
- def get_outbound_by_cargo(
- db: Session = Depends(get_db),
- user: DbUserContext = Depends(get_db_current_user),
- ) -> list[DashboardCargoStat]:
- return _cargo_stats(db, user, business_type="出库")
- @router.get("/outbound/by-partner-cargo", response_model=list[DashboardPartnerCargoStat])
- def get_outbound_by_partner_cargo(
- db: Session = Depends(get_db),
- user: DbUserContext = Depends(get_db_current_user),
- ) -> list[DashboardPartnerCargoStat]:
- return _partner_cargo_stats(db, user, business_type="出库")
- def _cargo_stats(db: Session, user: DbUserContext, *, business_type: str) -> list[DashboardCargoStat]:
- tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
- today = date.today()
- query = text(
- """
- SELECT
- COALESCE(io.product, ws.cargo_name, '未填写货物') AS label,
- COALESCE(SUM(io.quantity), 0) AS planned,
- COALESCE(SUM(ws.net_weight) / 1000.0, 0) AS actual
- FROM db_inbound_outbound io
- LEFT JOIN db_weighing_slip ws
- ON ws.inbound_outbound_id = io.id
- AND ws.is_voided = 0
- AND ws.del_flag = 0
- AND ws.tenant_no = io.tenant_no
- WHERE io.date = :today
- AND io.business_type = :business_type
- AND io.del_flag = 0
- AND io.tenant_no = :tenant_no
- GROUP BY COALESCE(io.product, ws.cargo_name, '未填写货物')
- ORDER BY planned DESC
- """
- )
- rows = db.execute(
- query,
- {"today": today, "business_type": business_type, "tenant_no": tenant_no},
- ).all()
- return [
- DashboardCargoStat(label=row.label, planned=float(row.planned), actual=float(row.actual))
- for row in rows
- ]
- def _partner_cargo_stats(
- db: Session,
- user: DbUserContext,
- *,
- business_type: str,
- ) -> list[DashboardPartnerCargoStat]:
- tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
- today = date.today()
- query = text(
- """
- SELECT
- CONCAT(
- COALESCE(io.partner_company, ''),
- ' - ',
- COALESCE(io.product, ws.cargo_name, '未填写货物')
- ) AS label,
- COALESCE(SUM(io.quantity), 0) AS planned,
- COALESCE(SUM(ws.net_weight) / 1000.0, 0) AS actual
- FROM db_inbound_outbound io
- LEFT JOIN db_weighing_slip ws
- ON ws.inbound_outbound_id = io.id
- AND ws.is_voided = 0
- AND ws.del_flag = 0
- AND ws.tenant_no = io.tenant_no
- WHERE io.date = :today
- AND io.business_type = :business_type
- AND io.del_flag = 0
- AND io.tenant_no = :tenant_no
- GROUP BY io.partner_company, io.product, ws.cargo_name
- ORDER BY io.partner_company, planned DESC
- """
- )
- rows = db.execute(
- query,
- {"today": today, "business_type": business_type, "tenant_no": tenant_no},
- ).all()
- return [
- DashboardPartnerCargoStat(
- label=row.label,
- planned=float(row.planned),
- actual=float(row.actual),
- )
- for row in rows
- ]
|