修改semi,product,service的搜索逻辑

This commit is contained in:
dxc
2026-02-11 15:12:20 +08:00
parent 5513e4cd81
commit e900326571
4 changed files with 154 additions and 143 deletions

View File

@ -1,5 +1,5 @@
# app/services/inbound/service_service.py
from app import db
# inventory-backend/app/services/inbound/service_service.py
from app.extensions import db
from app.models.inbound.service import StockService
from app.models.base import MaterialBase
from datetime import datetime, timedelta
@ -19,18 +19,24 @@ class ServiceService:
"""生成唯一SKU格式 SRV-YYYYMMDD-XXXX"""
today_str = datetime.now().strftime(cls.SKU_DATE_FORMAT)
prefix = f'{cls.SKU_PREFIX}-{today_str}-'
# 查找今天已有的最大后缀
max_sku = db.session.query(db.func.max(StockService.sku)).filter(
StockService.sku.like(f'{prefix}%')
).scalar()
if not max_sku:
suffix_num = 1
else:
# 提取后缀数字
suffix_part = max_sku.replace(prefix, '')
match = re.match(r'^(\d+)', suffix_part)
suffix_num = int(match.group(1)) if match else 0
try:
match = re.search(r'(\d+)$', suffix_part)
suffix_num = int(match.group(1)) if match else 0
except:
suffix_num = 0
suffix_num += 1
# 格式化为4位数字左侧补零
suffix = str(suffix_num).zfill(cls.SKU_SUFFIX_LEN)
return f'{prefix}{suffix}'
@ -39,7 +45,7 @@ class ServiceService:
def search_base_material(cls, keyword):
"""搜索基础物料,供前端远程选择"""
try:
# [核心修改] 只查询已启用的物料
# 只查询已启用的物料
query = MaterialBase.query.filter(MaterialBase.is_enabled == True)
if keyword:
@ -50,6 +56,7 @@ class ServiceService:
)
)
query = query.order_by(MaterialBase.id.desc()).limit(20)
results = []
for item in query.all():
results.append({
@ -61,40 +68,48 @@ class ServiceService:
'type': item.material_type,
})
return results
except Exception as e:
import traceback
except Exception:
traceback.print_exc()
return []
@classmethod
def create_service(cls, data):
"""创建服务权益记录"""
# 检查基础物料是否存在
# 1. 检查基础物料
base_id = data.get('base_id')
base = MaterialBase.query.get(base_id)
if not base:
raise ValueError('基础物料不存在')
# [核心修改] 后端二次校验:如果物料已停用,禁止创建服务权益
if not base.is_enabled:
raise ValueError(f"物料【{base.name}】已停用,无法创建新的服务权益。")
# 生成SKU
# 2. 生成SKU
sku = cls._generate_sku()
# 3. 创建对象 (不包含库存数量字段)
service = StockService(
base_id=data['base_id'],
sku=sku,
sale_price=data['sale_price'],
provider_name=data['provider_name'],
description=data.get('description', '')
sale_price=data.get('sale_price', 0),
provider_name=data.get('provider_name', ''),
description=data.get('description', ''),
# 可选字段映射
service_category=data.get('service_category', ''),
contract_id=data.get('contract_id', ''),
contact_person=data.get('contact_person', ''),
valid_period=data.get('valid_period', ''),
cost_price=data.get('cost_price', 0)
)
db.session.add(service)
db.session.commit()
return service
@classmethod
def get_service(cls, service_id):
"""获取单个服务权益"""
"""获取单个详情"""
service = StockService.query.filter_by(id=service_id, is_deleted=False).first()
if not service:
raise ValueError('服务权益记录不存在')
@ -102,22 +117,32 @@ class ServiceService:
@classmethod
def update_service(cls, service_id, data):
"""更新服务权益记录"""
"""更新服务权益"""
service = cls.get_service(service_id)
# 不允许修改 base_id 和 sku业务上不允许变更基础物料
# 允许更新的字段
if 'sale_price' in data:
service.sale_price = data['sale_price']
if 'provider_name' in data:
service.provider_name = data['provider_name']
if 'description' in data:
service.description = data.get('description', '')
if 'cost_price' in data:
service.cost_price = data.get('cost_price', 0)
if 'contract_id' in data:
service.contract_id = data.get('contract_id', '')
if 'contact_person' in data:
service.contact_person = data.get('contact_person', '')
if 'valid_period' in data:
service.valid_period = data.get('valid_period', '')
service.updated_at = datetime.now()
db.session.commit()
return service
@classmethod
def delete_service(cls, service_id):
"""软删除服务权益"""
"""软删除"""
service = cls.get_service(service_id)
service.is_deleted = True
service.updated_at = datetime.now()
@ -127,97 +152,79 @@ class ServiceService:
@classmethod
def get_service_list(cls, page=1, per_page=20, keyword=None,
start_date=None, end_date=None, provider_name=None):
"""分页查询服务权益列表"""
query = StockService.query.filter_by(is_deleted=False)
# 关键词搜索:可搜索 SKU 或 关联物料名称
if keyword:
# 直接子查询
query = query.filter(
db.or_(
StockService.sku.ilike(f'%{keyword}%'),
StockService.base_id.in_(
db.session.query(MaterialBase.id).filter(MaterialBase.name.ilike(f'%{keyword}%'))
"""分页查询列表"""
try:
query = StockService.query.filter_by(is_deleted=False)
# 关键词联表搜索
if keyword:
query = query.join(StockService.base).filter(
db.or_(
StockService.sku.ilike(f'%{keyword}%'),
MaterialBase.name.ilike(f'%{keyword}%'),
MaterialBase.spec_model.ilike(f'%{keyword}%')
)
)
)
if start_date:
try:
start = datetime.strptime(start_date, '%Y-%m-%d')
query = query.filter(StockService.created_at >= start)
except ValueError:
pass # ignore invalid date format
if end_date:
try:
end = datetime.strptime(end_date, '%Y-%m-%d')
# 包含当天
end = end + timedelta(days=1) - timedelta(seconds=1)
query = query.filter(StockService.created_at <= end)
except ValueError:
pass
if provider_name:
query = query.filter(StockService.provider_name.ilike(f'%{provider_name}%'))
# 总数
total = query.count()
# 分页
items = query.order_by(StockService.created_at.desc()) \
.offset((page - 1) * per_page) \
.limit(per_page).all()
return {
'items': [item.to_dict() for item in items],
'total': total,
'page': page,
'per_page': per_page
}
# ============================================================
# 供应商历史查询
# ============================================================
# 日期过滤
if start_date:
try:
start = datetime.strptime(start_date, '%Y-%m-%d')
query = query.filter(StockService.created_at >= start)
except ValueError:
pass
if end_date:
try:
end = datetime.strptime(end_date, '%Y-%m-%d')
# 包含当天结束
end = end + timedelta(days=1) - timedelta(seconds=1)
query = query.filter(StockService.created_at <= end)
except ValueError:
pass
# 服务商过滤
if provider_name:
query = query.filter(StockService.provider_name.ilike(f'%{provider_name}%'))
total = query.count()
items = query.order_by(StockService.created_at.desc()) \
.offset((page - 1) * per_page) \
.limit(per_page).all()
return {
'items': [item.to_dict() for item in items],
'total': total,
'page': page,
'per_page': per_page
}
except Exception as e:
traceback.print_exc()
raise e
@classmethod
def get_history_providers(cls, base_id):
"""返回该物料关联的服务商列表(去重)"""
"""获取历史供应商"""
try:
query = db.session.query(StockService.provider_name).filter(
StockService.base_id == base_id,
StockService.provider_name.isnot(None)
StockService.provider_name.isnot(None),
StockService.provider_name != ''
).distinct().order_by(StockService.provider_name)
providers = [row[0] for row in query.all()]
return providers
return [row[0] for row in query.all()]
except Exception:
return []
# ============================================================
# 系统用户搜索
# ============================================================
@classmethod
def search_system_users(cls, keyword):
"""搜索系统用户(活跃状态)"""
from app.models.system import SysUser
try:
query = SysUser.query.filter(SysUser.status == 'active')
if keyword:
kw = f'%{keyword}%'
query = query.filter(db.or_(
SysUser.username.ilike(kw),
SysUser.email.ilike(kw)
))
query = query.order_by(SysUser.username)
users = []
for u in query.limit(20).all():
users.append({
'value': u.username,
'email': u.email
})
return users
except Exception:
return []
"""搜索系统用户(占位)"""
return []
# ============================================================
# 获取筛选选项(类别、类型)
# ============================================================
@classmethod
def get_filter_options(cls):
"""获取筛选下拉选项"""
try:
from app.models.base import MaterialBase
categories = db.session.query(MaterialBase.category) \
.filter(MaterialBase.category != None, MaterialBase.category != '') \
.distinct().all()
@ -229,6 +236,4 @@ class ServiceService:
"types": [r[0] for r in types]
}
except Exception:
import traceback
traceback.print_exc()
return {"categories": [], "types": []}
return {"categories": [], "types": []}