| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- """运输管理 - 侧栏菜单角标统计"""
- from __future__ import annotations
- from collections import defaultdict
- from typing import Dict, List, Optional
- from sqlalchemy.orm import Session
- from app.models.pl_models import (
- PlDocumentReminder,
- PlFreightSettlement,
- PlPlan,
- PlPlanProduct,
- PlVehicleMaintenanceApply,
- PlVehicleRechargeApply,
- PlVehicleUreaApply,
- )
- from app.services.pl_cert_service import scan_cert_expiry
- from app.services.pl_data_scope import apply_pl_scope
- from app.services.pl_freight_settlement_service import can_user_approve_settlement
- from app.services.pl_plan_service import plan_has_hazard_products
- MENU_CODE_DOCUMENT = "pl:document:list"
- MENU_CODE_FREIGHT_APPROVAL = "pl:freight-approval:list"
- MENU_CODE_FREIGHT_DISBURSE = "pl:freight-disburse:list"
- MENU_CODE_RECHARGE_RECORD = "pl:vehicle-recharge-record:list"
- MENU_CODE_MAINT_PROCESS = "pl:vehicle-maintenance-process:list"
- MENU_CODE_UREA_DISBURSE = "pl:vehicle-urea-disburse:list"
- MENU_CODE_PLAN_CERT = "pl:plan-cert:list"
- MENU_CODE_PLAN_ARCHIVE = "pl:plan-archive:list"
- MENU_CODE_PLAN_CONTRACT = "pl:plan-contract:list"
- SUPPORTED_MENU_CODES = {
- MENU_CODE_DOCUMENT,
- MENU_CODE_FREIGHT_APPROVAL,
- MENU_CODE_FREIGHT_DISBURSE,
- MENU_CODE_RECHARGE_RECORD,
- MENU_CODE_MAINT_PROCESS,
- MENU_CODE_UREA_DISBURSE,
- MENU_CODE_PLAN_CERT,
- MENU_CODE_PLAN_ARCHIVE,
- MENU_CODE_PLAN_CONTRACT,
- }
- def _count_pending_applies(db: Session, tenant_no: str, user, model) -> int:
- query = db.query(model).filter(
- model.tenant_no == tenant_no,
- model.del_flag == 0,
- model.status == "pending",
- )
- query = apply_pl_scope(query, model, user, db, tenant_no)
- return query.count()
- def count_document_reminder_expired_pending(db: Session, tenant_no: str, user) -> int:
- scan_cert_expiry(db, tenant_no)
- db.flush()
- query = db.query(PlDocumentReminder).filter(
- PlDocumentReminder.tenant_no == tenant_no,
- PlDocumentReminder.del_flag == 0,
- PlDocumentReminder.status == "pending",
- PlDocumentReminder.days_remaining <= 0,
- )
- query = apply_pl_scope(query, PlDocumentReminder, user, db, tenant_no)
- return query.count()
- def count_freight_approval_pending(db: Session, tenant_no: str, user_id: str) -> int:
- if not user_id:
- return 0
- rows = (
- db.query(PlFreightSettlement.id)
- .filter(
- PlFreightSettlement.tenant_no == tenant_no,
- PlFreightSettlement.del_flag == 0,
- PlFreightSettlement.settlement_status == "approving",
- )
- .all()
- )
- total = 0
- for (settlement_id,) in rows:
- if can_user_approve_settlement(db, settlement_id, user_id):
- total += 1
- return total
- def count_plan_cert_pending(db: Session, tenant_no: str, user) -> int:
- query = db.query(PlPlan).filter(
- PlPlan.tenant_no == tenant_no,
- PlPlan.del_flag == 0,
- PlPlan.hazard_cert_ready == 0,
- PlPlan.archive_status != "archived",
- PlPlan.follow_status != "cancelled",
- )
- query = apply_pl_scope(query, PlPlan, user, db, tenant_no)
- plans = query.all()
- if not plans:
- return 0
- plan_ids = [plan.id for plan in plans]
- products_by_plan: dict[str, list[PlPlanProduct]] = defaultdict(list)
- product_rows = (
- db.query(PlPlanProduct)
- .filter(
- PlPlanProduct.plan_id.in_(plan_ids),
- PlPlanProduct.del_flag == 0,
- )
- .all()
- )
- for product in product_rows:
- products_by_plan[str(product.plan_id)].append(product)
- total = 0
- for plan in plans:
- products = products_by_plan.get(str(plan.id), [])
- if plan_has_hazard_products(db, tenant_no, products):
- total += 1
- return total
- def count_plan_archive_pending(db: Session, tenant_no: str, user) -> int:
- """待归档角标:与归档列表一致,仅统计已安排运输且未归档的计划。"""
- query = db.query(PlPlan).filter(
- PlPlan.tenant_no == tenant_no,
- PlPlan.del_flag == 0,
- PlPlan.archive_status == "unarchived",
- PlPlan.follow_status != "cancelled",
- PlPlan.transport_status == "arranged",
- )
- query = apply_pl_scope(query, PlPlan, user, db, tenant_no)
- return query.count()
- def count_plan_contract_gaps(db: Session, tenant_no: str, user) -> int:
- from app.services.pl_plan_contract_gap import plan_has_contract_gap_exists
- query = db.query(PlPlan).filter(
- PlPlan.tenant_no == tenant_no,
- PlPlan.del_flag == 0,
- PlPlan.follow_status != "cancelled",
- plan_has_contract_gap_exists(tenant_no),
- )
- query = apply_pl_scope(query, PlPlan, user, db, tenant_no)
- return query.count()
- def count_freight_disburse_pending(db: Session, tenant_no: str, user) -> int:
- query = db.query(PlFreightSettlement).filter(
- PlFreightSettlement.tenant_no == tenant_no,
- PlFreightSettlement.del_flag == 0,
- PlFreightSettlement.settlement_status == "approved",
- )
- query = apply_pl_scope(query, PlFreightSettlement, user, db, tenant_no)
- return query.count()
- def build_menu_badge_counts(
- db: Session,
- *,
- tenant_no: str,
- user,
- user_id: str,
- menu_codes: Optional[List[str]] = None,
- ) -> Dict[str, int]:
- requested = {c.strip() for c in (menu_codes or []) if c and c.strip()}
- if not requested:
- requested = set(SUPPORTED_MENU_CODES)
- requested &= SUPPORTED_MENU_CODES
- counts: Dict[str, int] = {}
- if MENU_CODE_DOCUMENT in requested:
- counts[MENU_CODE_DOCUMENT] = count_document_reminder_expired_pending(db, tenant_no, user)
- if MENU_CODE_FREIGHT_APPROVAL in requested:
- counts[MENU_CODE_FREIGHT_APPROVAL] = count_freight_approval_pending(db, tenant_no, user_id)
- if MENU_CODE_FREIGHT_DISBURSE in requested:
- counts[MENU_CODE_FREIGHT_DISBURSE] = count_freight_disburse_pending(db, tenant_no, user)
- if MENU_CODE_RECHARGE_RECORD in requested:
- counts[MENU_CODE_RECHARGE_RECORD] = _count_pending_applies(
- db, tenant_no, user, PlVehicleRechargeApply
- )
- if MENU_CODE_MAINT_PROCESS in requested:
- counts[MENU_CODE_MAINT_PROCESS] = _count_pending_applies(
- db, tenant_no, user, PlVehicleMaintenanceApply
- )
- if MENU_CODE_UREA_DISBURSE in requested:
- counts[MENU_CODE_UREA_DISBURSE] = _count_pending_applies(
- db, tenant_no, user, PlVehicleUreaApply
- )
- if MENU_CODE_PLAN_CERT in requested:
- counts[MENU_CODE_PLAN_CERT] = count_plan_cert_pending(db, tenant_no, user)
- if MENU_CODE_PLAN_ARCHIVE in requested:
- counts[MENU_CODE_PLAN_ARCHIVE] = count_plan_archive_pending(db, tenant_no, user)
- if MENU_CODE_PLAN_CONTRACT in requested:
- counts[MENU_CODE_PLAN_CONTRACT] = count_plan_contract_gaps(db, tenant_no, user)
- return counts
|