修改采购件对于两个搜索框的bug修复
This commit is contained in:
@ -1,4 +1,3 @@
|
||||
# app/api/v1/inbound/buy.py
|
||||
from flask import Blueprint, request, jsonify
|
||||
from app.services.inbound.buy_service import BuyInboundService
|
||||
import traceback
|
||||
@ -7,14 +6,10 @@ inbound_buy_bp = Blueprint('stock_buy', __name__)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 0. 基础物料搜索 (已修改:支持 page 参数)
|
||||
# 0. 基础物料搜索
|
||||
# ------------------------------------------------------------------
|
||||
@inbound_buy_bp.route('/search-base', methods=['GET'])
|
||||
def search_base():
|
||||
"""
|
||||
供前端下拉框远程搜索使用,支持分页
|
||||
Query Param: keyword (名称或规格), page (默认1)
|
||||
"""
|
||||
try:
|
||||
keyword = request.args.get('keyword', '')
|
||||
page = request.args.get('page', 1, type=int)
|
||||
@ -35,7 +30,7 @@ def search_base():
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 1. 获取列表
|
||||
# 1. 获取列表 (修改:接收 category 和 material_type)
|
||||
# ------------------------------------------------------------------
|
||||
@inbound_buy_bp.route('/list', methods=['GET'])
|
||||
def get_list():
|
||||
@ -44,11 +39,15 @@ def get_list():
|
||||
limit = request.args.get('pageSize', 15, type=int)
|
||||
keyword = request.args.get('keyword', '')
|
||||
|
||||
# 获取状态列表参数,前端传参格式: statuses=在库,借库
|
||||
# 新增筛选参数
|
||||
category = request.args.get('category', '')
|
||||
material_type = request.args.get('material_type', '')
|
||||
|
||||
# 状态参数处理
|
||||
statuses_str = request.args.get('statuses', '')
|
||||
statuses = statuses_str.split(',') if statuses_str else []
|
||||
|
||||
result = BuyInboundService.get_list(page, limit, keyword, statuses)
|
||||
result = BuyInboundService.get_list(page, limit, keyword, statuses, category, material_type)
|
||||
return jsonify({"code": 200, "msg": "success", "data": result})
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
@ -103,7 +102,19 @@ def delete_buy(id):
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 5. 获取关联的出库历史 (如果有)
|
||||
# 5. [新增] 获取筛选下拉选项 (修复404的关键)
|
||||
# ------------------------------------------------------------------
|
||||
@inbound_buy_bp.route('/options', methods=['GET'])
|
||||
def get_options():
|
||||
try:
|
||||
data = BuyInboundService.get_filter_options()
|
||||
return jsonify({"code": 200, "msg": "success", "data": data})
|
||||
except Exception as e:
|
||||
return jsonify({"code": 500, "msg": str(e)}), 500
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 6. 获取关联的出库历史 (如果有)
|
||||
# ------------------------------------------------------------------
|
||||
@inbound_buy_bp.route('/<int:id>/history', methods=['GET'])
|
||||
def get_history(id):
|
||||
@ -112,7 +123,7 @@ def get_history(id):
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 6. 供应商建议
|
||||
# 7. 供应商建议
|
||||
# ------------------------------------------------------------------
|
||||
@inbound_buy_bp.route('/suggestions/suppliers', methods=['GET'])
|
||||
def get_supplier_suggestions():
|
||||
@ -124,7 +135,7 @@ def get_supplier_suggestions():
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 7. 采购人建议 (全局)
|
||||
# 8. 采购人建议 (全局)
|
||||
# ------------------------------------------------------------------
|
||||
@inbound_buy_bp.route('/suggestions/users', methods=['GET'])
|
||||
def get_user_suggestions():
|
||||
@ -134,7 +145,7 @@ def get_user_suggestions():
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 8. 链接建议
|
||||
# 9. 链接建议
|
||||
# ------------------------------------------------------------------
|
||||
@inbound_buy_bp.route('/suggestions/links', methods=['GET'])
|
||||
def get_link_suggestions():
|
||||
@ -147,7 +158,7 @@ def get_link_suggestions():
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 9. [新增] 库位建议
|
||||
# 10. 库位建议
|
||||
# ------------------------------------------------------------------
|
||||
@inbound_buy_bp.route('/suggestions/locations', methods=['GET'])
|
||||
def get_location_suggestions():
|
||||
|
||||
@ -10,7 +10,7 @@ import json
|
||||
class BuyInboundService:
|
||||
|
||||
# ============================================================
|
||||
# 0. 辅助:唯一性校验 (保持不变)
|
||||
# 0. 辅助:唯一性校验
|
||||
# ============================================================
|
||||
@staticmethod
|
||||
def _check_unique(base_id, serial_number, batch_number, exclude_id=None):
|
||||
@ -34,34 +34,24 @@ class BuyInboundService:
|
||||
raise ValueError(f"该物料已存在批号【{batch_number}】,请勿重复录入,可直接在该批次下追加库存。")
|
||||
|
||||
# ============================================================
|
||||
# 1. 基础物料搜索 (修复:逻辑优先级 & 模糊匹配)
|
||||
# 1. 基础物料搜索
|
||||
# ============================================================
|
||||
@staticmethod
|
||||
def search_base_material(keyword, page=1, limit=50):
|
||||
try:
|
||||
# 1. 基础查询:只查询启用的
|
||||
query = MaterialBase.query.filter(MaterialBase.is_enabled == True)
|
||||
|
||||
if keyword:
|
||||
k = keyword.strip()
|
||||
k_str = f'%{k}%'
|
||||
|
||||
# [核心修复] 使用 and_ 确保逻辑优先级正确
|
||||
# 生成 SQL 类似: WHERE is_enabled = true AND (name LIKE %k% OR spec LIKE %k% ...)
|
||||
query = query.filter(and_(
|
||||
or_(
|
||||
MaterialBase.name.ilike(k_str), # ilike 忽略大小写
|
||||
MaterialBase.spec_model.ilike(k_str),
|
||||
MaterialBase.pinyin.ilike(k_str),
|
||||
# 如果需要支持 ID 搜索,取消下面注释
|
||||
# func.cast(MaterialBase.id, String).ilike(k_str)
|
||||
MaterialBase.name.ilike(k_str),
|
||||
MaterialBase.spec_model.ilike(k_str)
|
||||
)
|
||||
))
|
||||
|
||||
# 2. 排序:ID 倒序
|
||||
query = query.order_by(MaterialBase.id.desc())
|
||||
|
||||
# 3. 分页
|
||||
pagination = query.paginate(page=page, per_page=limit, error_out=False)
|
||||
|
||||
items = []
|
||||
@ -90,7 +80,7 @@ class BuyInboundService:
|
||||
return {"items": [], "total": 0, "page": 1, "has_next": False}
|
||||
|
||||
# ============================================================
|
||||
# 2. 新增入库逻辑 (保持不变)
|
||||
# 2. 新增入库逻辑
|
||||
# ============================================================
|
||||
@staticmethod
|
||||
def handle_inbound(data):
|
||||
@ -157,7 +147,7 @@ class BuyInboundService:
|
||||
raise e
|
||||
|
||||
# ============================================================
|
||||
# 3. 更新入库 (保持不变)
|
||||
# 3. 更新入库
|
||||
# ============================================================
|
||||
@staticmethod
|
||||
def update_inbound(stock_id, data):
|
||||
@ -197,7 +187,7 @@ class BuyInboundService:
|
||||
raise e
|
||||
|
||||
# ============================================================
|
||||
# 4. 删除 (保持不变)
|
||||
# 4. 删除
|
||||
# ============================================================
|
||||
@staticmethod
|
||||
def delete_inbound(stock_id):
|
||||
@ -212,21 +202,37 @@ class BuyInboundService:
|
||||
raise e
|
||||
|
||||
# ============================================================
|
||||
# 5. 获取列表 (保持不变)
|
||||
# 5. 获取列表
|
||||
# ============================================================
|
||||
@staticmethod
|
||||
def get_list(page, limit, keyword=None, statuses=None):
|
||||
def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None):
|
||||
try:
|
||||
query = db.session.query(StockBuy).outerjoin(MaterialBase, StockBuy.base_id == MaterialBase.id)
|
||||
|
||||
# 1. 通用关键词搜索
|
||||
if keyword:
|
||||
k_str = f'%{keyword.strip()}%'
|
||||
conditions = [StockBuy.sku.ilike(k_str), StockBuy.barcode.ilike(k_str),
|
||||
StockBuy.batch_number.ilike(k_str), StockBuy.serial_number.ilike(k_str),
|
||||
StockBuy.supplier_name.ilike(k_str), StockBuy.buyer_name.ilike(k_str),
|
||||
MaterialBase.name.ilike(k_str), MaterialBase.spec_model.ilike(k_str),
|
||||
MaterialBase.pinyin.ilike(k_str)]
|
||||
conditions = [
|
||||
StockBuy.sku.ilike(k_str),
|
||||
StockBuy.barcode.ilike(k_str),
|
||||
StockBuy.batch_number.ilike(k_str),
|
||||
StockBuy.serial_number.ilike(k_str),
|
||||
StockBuy.supplier_name.ilike(k_str),
|
||||
StockBuy.buyer_name.ilike(k_str),
|
||||
MaterialBase.name.ilike(k_str), # 名称
|
||||
MaterialBase.spec_model.ilike(k_str), # 规格
|
||||
]
|
||||
query = query.filter(or_(*conditions))
|
||||
|
||||
# 2. 类别独立搜索
|
||||
if category and category.strip():
|
||||
query = query.filter(MaterialBase.category == category.strip()) # 下拉框通常是精确匹配
|
||||
|
||||
# 3. 类型独立搜索
|
||||
if material_type and material_type.strip():
|
||||
query = query.filter(MaterialBase.material_type == material_type.strip()) # 精确匹配
|
||||
|
||||
# 4. 状态筛选
|
||||
if not statuses: statuses = ['在库', '借库']
|
||||
if '已出库' in statuses:
|
||||
query = query.filter(StockBuy.status.in_(statuses))
|
||||
@ -259,7 +265,31 @@ class BuyInboundService:
|
||||
traceback.print_exc()
|
||||
return {"total": 0, "items": []}
|
||||
|
||||
# 6-9 建议类接口保持不变 (略以节省篇幅,原样保留即可)
|
||||
# ============================================================
|
||||
# 6. [新增] 获取筛选选项(类别、类型)
|
||||
# ============================================================
|
||||
@staticmethod
|
||||
def get_filter_options():
|
||||
try:
|
||||
# 获取所有非空的类别
|
||||
categories = db.session.query(MaterialBase.category) \
|
||||
.filter(MaterialBase.category != None, MaterialBase.category != '') \
|
||||
.distinct().all()
|
||||
|
||||
# 获取所有非空的类型
|
||||
types = db.session.query(MaterialBase.material_type) \
|
||||
.filter(MaterialBase.material_type != None, MaterialBase.material_type != '') \
|
||||
.distinct().all()
|
||||
|
||||
return {
|
||||
"categories": [r[0] for r in categories],
|
||||
"types": [r[0] for r in types]
|
||||
}
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
return {"categories": [], "types": []}
|
||||
|
||||
# 7-10 建议类接口保持不变
|
||||
@staticmethod
|
||||
def get_history_suppliers(base_id):
|
||||
return [r[0] for r in db.session.query(StockBuy.supplier_name).filter(StockBuy.base_id == base_id,
|
||||
|
||||
Reference in New Issue
Block a user