feat(repair): decouple material base, sync global sku sequence and add scan/print features

This commit is contained in:
DXC
2026-04-08 19:36:14 +08:00
parent cf7dc04db7
commit 3085d9f447
6 changed files with 464 additions and 136 deletions

View File

@ -3,8 +3,7 @@ from app.extensions import db
from app.models.transaction import TransRepair
from app.models.base import MaterialBase
from datetime import datetime, timezone
import random
import string
from sqlalchemy import text
class RepairInboundService:
@ -13,27 +12,42 @@ class RepairInboundService:
def _generate_repair_no():
"""
生成唯一的维修单号
格式: REP-YYYYMMDD-XXXX (X为随机大写字母或数字)
防重复策略:
1. 先尝试生成4位随机序列
2. 检查数据库中是否存在该单号
3. 如果冲突重试最多10次
4. 如果10次都冲突加入时间戳毫秒数确保唯一
格式: REP-YYYYMMDD-0001 (按天递增)
策略: 查询当天最大的repair_no提取流水号+1
"""
for _ in range(10):
date_str = datetime.now().strftime('%Y%m%d')
random_str = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
repair_no = f"REP-{date_str}-{random_str}"
# 检查是否已存在
exists = TransRepair.query.filter_by(repair_no=repair_no).first()
if not exists:
return repair_no
today = datetime.now().strftime('%Y%m%d')
prefix = f"REP-{today}-"
# 兜底策略:使用时间戳毫秒
timestamp = int(datetime.now().timestamp() * 1000) % 100000
date_str = datetime.now().strftime('%Y%m%d')
return f"REP-{date_str}-{timestamp:05d}"
# 查询当天最大的维修单号
latest = TransRepair.query.filter(
TransRepair.repair_no.like(f"{prefix}%")
).order_by(TransRepair.repair_no.desc()).first()
if latest and latest.repair_no:
try:
# 提取最后的流水号
last_seq = int(latest.repair_no.split('-')[-1])
new_seq = last_seq + 1
except (ValueError, IndexError):
new_seq = 1
else:
new_seq = 1
return f"{prefix}{new_seq:04d}"
@staticmethod
def _generate_sku():
"""
获取全局自增序列号生成10位SKU
格式: str(seq).zfill(10)
"""
try:
seq_sql = text("SELECT nextval('global_print_seq')")
result = db.session.execute(seq_sql)
next_global_id = result.scalar()
return str(next_global_id).zfill(10) if next_global_id else None
except:
return None
@staticmethod
def get_list(params):
@ -57,10 +71,15 @@ class RepairInboundService:
if params.get('repair_status'):
query = query.filter(TransRepair.repair_status == params['repair_status'])
# 关联 MaterialBase 查询物料名称
# 关联 MaterialBase 查询物料名称 或 直接搜索 TransRepair.material_name
if params.get('material_name'):
query = query.join(MaterialBase, TransRepair.base_id == MaterialBase.id).filter(
MaterialBase.name.ilike(f"%{params['material_name']}%")
material_name_filter = params['material_name']
# 优先搜索直接存储的 material_name其次搜索关联的 base.name
query = query.outerjoin(MaterialBase, TransRepair.base_id == MaterialBase.id).filter(
db.or_(
TransRepair.material_name.ilike(f"%{material_name_filter}%"),
MaterialBase.name.ilike(f"%{material_name_filter}%")
)
)
# 按创建时间倒序
@ -92,28 +111,35 @@ class RepairInboundService:
"""
新增维修单
核心要求:
1. 生成以 REP- 打头的自增维修单号
2. 支持自动获取传入的 base_id 获取基础物料名称
1. 生成以 REP- 打头的自增维修单号 (按天递增)
2. 从全局序列获取10位SKU (global_print_seq)
3. 支持不关联 base_id (独立录入模式)
4. 新增客户名称和客户所在地字段
"""
# 生成维修单号
repair_no = RepairInboundService._generate_repair_no()
# 获取物料信息
material_name = None
company_name = None
# 获取全局SKU
sku = data.get('sku')
if not sku:
sku = RepairInboundService._generate_sku()
# 获取物料信息 (可选)
material_name = data.get('material_name')
company_name = None
if data.get('base_id'):
base = MaterialBase.query.get(data['base_id'])
if base:
material_name = base.name
material_name = base.name or material_name
company_name = base.company_name
if not sku:
sku = base.code
repair = TransRepair(
repair_no=repair_no,
base_id=data.get('base_id'),
sku=sku or data.get('sku'),
sku=sku,
material_name=material_name,
serial_number=data.get('serial_number'),
arrival_date=data.get('arrival_date'),
repair_status=data.get('repair_status', '待检测'),
@ -123,6 +149,9 @@ class RepairInboundService:
repair_manager=data.get('repair_manager'),
shipping_date=data.get('shipping_date'),
related_contract_id=data.get('related_contract_id'),
# 新增客户字段
customer_name=data.get('customer_name'),
customer_location=data.get('customer_location'),
cost_price=data.get('cost_price'),
sale_price=data.get('sale_price'),
company_id=data.get('company_id'),
@ -151,10 +180,10 @@ class RepairInboundService:
# 可更新字段
updatable_fields = [
'base_id', 'sku', 'serial_number', 'arrival_date', 'repair_status',
'base_id', 'sku', 'material_name', 'serial_number', 'arrival_date', 'repair_status',
'fault_description', 'expected_repair_time', 'repair_result',
'repair_manager', 'shipping_date', 'related_contract_id',
'cost_price', 'sale_price', 'company_id'
'customer_name', 'customer_location', 'cost_price', 'sale_price', 'company_id'
]
for field in updatable_fields: