108 lines
3.5 KiB
Python
108 lines
3.5 KiB
Python
"""市场物料库存变动记录 CRUD"""
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import Any, Dict, List, Optional, Tuple
|
|
|
|
from sqlalchemy import func, or_
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.models.material import BizMaterialStockLog
|
|
from app.models.models import SysUser
|
|
|
|
|
|
def _user_nick_name_map(db: Session, user_ids: List[str]) -> Dict[str, str]:
|
|
ids = list({x for x in user_ids if x})
|
|
if not ids:
|
|
return {}
|
|
rows = db.query(SysUser.id, SysUser.nick_name).filter(SysUser.id.in_(ids)).all()
|
|
return {u.id: (u.nick_name or "").strip() for u in rows}
|
|
|
|
|
|
def _dec(v: Any) -> float:
|
|
if v is None:
|
|
return 0.0
|
|
return float(v)
|
|
|
|
|
|
def _fmt_dt(t: Optional[datetime]) -> str:
|
|
return t.strftime("%Y-%m-%d %H:%M:%S") if t else ""
|
|
|
|
|
|
def _row_to_dict(r: BizMaterialStockLog, *, create_by_name: str = "") -> Dict[str, Any]:
|
|
create_by = r.create_by or ""
|
|
return {
|
|
"id": r.id,
|
|
"materialId": r.material_id,
|
|
"materialCode": r.material_code or "",
|
|
"materialName": r.material_name or "",
|
|
"changeType": r.change_type,
|
|
"changeQty": _dec(r.change_qty),
|
|
"stockBefore": _dec(r.stock_before),
|
|
"stockAfter": _dec(r.stock_after),
|
|
"receiver": r.receiver or "",
|
|
"purpose": r.purpose or "",
|
|
"remark": r.remark or "",
|
|
"createBy": create_by,
|
|
"createByName": create_by_name or create_by,
|
|
"createTime": _fmt_dt(r.create_time),
|
|
"updateTime": _fmt_dt(r.update_time),
|
|
}
|
|
|
|
|
|
def list_stock_logs(
|
|
db: Session,
|
|
tenant_no: str,
|
|
*,
|
|
page: int = 1,
|
|
page_size: int = 10,
|
|
material_id: Optional[str] = None,
|
|
change_type: Optional[str] = None,
|
|
start_time: Optional[str] = None,
|
|
end_time: Optional[str] = None,
|
|
keyword: Optional[str] = None,
|
|
user_info=None,
|
|
) -> Tuple[List[Dict[str, Any]], int]:
|
|
def _filtered():
|
|
q0 = db.query(BizMaterialStockLog).filter(
|
|
BizMaterialStockLog.tenant_no == tenant_no,
|
|
BizMaterialStockLog.del_flag == 0,
|
|
)
|
|
if material_id:
|
|
q0 = q0.filter(BizMaterialStockLog.material_id == material_id)
|
|
if change_type:
|
|
q0 = q0.filter(BizMaterialStockLog.change_type == change_type)
|
|
if start_time:
|
|
q0 = q0.filter(BizMaterialStockLog.create_time >= start_time)
|
|
if end_time:
|
|
q0 = q0.filter(BizMaterialStockLog.create_time <= end_time + " 23:59:59")
|
|
kw = (keyword or "").strip()
|
|
if kw:
|
|
like = f"%{kw}%"
|
|
q0 = q0.filter(
|
|
or_(
|
|
BizMaterialStockLog.material_code.ilike(like),
|
|
BizMaterialStockLog.material_name.ilike(like),
|
|
)
|
|
)
|
|
if user_info:
|
|
from app.core.data_scope import apply_data_scope
|
|
q0 = apply_data_scope(q0, BizMaterialStockLog, user_info, db, tenant_no)
|
|
return q0
|
|
|
|
total = _filtered().order_by(None).with_entities(func.count(BizMaterialStockLog.id)).scalar() or 0
|
|
page = max(1, page)
|
|
page_size = min(max(1, page_size), 100)
|
|
rows = (
|
|
_filtered()
|
|
.order_by(BizMaterialStockLog.create_time.desc())
|
|
.offset((page - 1) * page_size)
|
|
.limit(page_size)
|
|
.all()
|
|
)
|
|
name_map = _user_nick_name_map(db, [x.create_by for x in rows if x.create_by])
|
|
return [
|
|
_row_to_dict(x, create_by_name=name_map.get(x.create_by or "", ""))
|
|
for x in rows
|
|
], int(total)
|