基础信息读取错误,未修改完成
This commit is contained in:
139
inventory-backend/app/services/inbound/base_service.py
Normal file
139
inventory-backend/app/services/inbound/base_service.py
Normal file
@ -0,0 +1,139 @@
|
||||
from app.extensions import db
|
||||
from app.models.material import MaterialBase
|
||||
from app.models.stock import StockBuy # 需要引入库存表做删除时的依赖检查
|
||||
from sqlalchemy import or_
|
||||
import traceback
|
||||
|
||||
|
||||
class MaterialBaseService:
|
||||
@staticmethod
|
||||
def get_list(page, limit, filters=None):
|
||||
"""
|
||||
获取基础信息列表
|
||||
:param page: 页码
|
||||
:param limit: 每页条数
|
||||
:param filters: 筛选条件字典 {keyword, category, type, isEnabled}
|
||||
"""
|
||||
try:
|
||||
query = MaterialBase.query
|
||||
|
||||
if filters:
|
||||
# 1. 关键词模糊搜索 (名称 或 规格型号)
|
||||
if filters.get('keyword'):
|
||||
kw = f"%{filters['keyword']}%"
|
||||
query = query.filter(or_(
|
||||
MaterialBase.name.like(kw),
|
||||
MaterialBase.spec_model.like(kw)
|
||||
))
|
||||
|
||||
# 2. 精确筛选
|
||||
if filters.get('category'):
|
||||
query = query.filter_by(category=filters['category'])
|
||||
|
||||
if filters.get('type'):
|
||||
query = query.filter_by(material_type=filters['type'])
|
||||
|
||||
if filters.get('isEnabled') is not None:
|
||||
# 前端传 1/0,转为 Boolean
|
||||
is_active = bool(int(filters['isEnabled']))
|
||||
query = query.filter_by(is_enabled=is_active)
|
||||
|
||||
# 按 ID 倒序排列
|
||||
pagination = query.order_by(MaterialBase.id.desc()).paginate(page=page, per_page=limit, error_out=False)
|
||||
|
||||
items = [item.to_dict() for item in pagination.items]
|
||||
return {"total": pagination.total, "items": items}
|
||||
|
||||
except Exception as e:
|
||||
print(f"查询基础信息列表失败: {e}")
|
||||
# 生产环境建议记录日志
|
||||
return {"total": 0, "items": []}
|
||||
|
||||
@staticmethod
|
||||
def create_material(data):
|
||||
"""新增基础信息"""
|
||||
try:
|
||||
# 0. 基础校验
|
||||
if not data.get('name') or not data.get('spec'):
|
||||
raise ValueError("名称和规格型号不能为空")
|
||||
|
||||
# 1. 查重 (名称+规格型号 唯一)
|
||||
exist = MaterialBase.query.filter_by(
|
||||
name=data['name'],
|
||||
spec_model=data['spec']
|
||||
).first()
|
||||
if exist:
|
||||
raise ValueError(f"已存在相同名称和规格的数据 (ID: {exist.id})")
|
||||
|
||||
# 2. 创建对象 (注意前端驼峰 -> 后端下划线映射)
|
||||
new_material = MaterialBase(
|
||||
name=data['name'],
|
||||
spec_model=data['spec'], # 映射
|
||||
category=data.get('category'),
|
||||
material_type=data.get('type'), # 映射
|
||||
unit=data.get('unit'),
|
||||
visibility_level=data.get('visibilityLevel'), # 映射
|
||||
manual_link=data.get('generalManual'), # 映射
|
||||
product_image=data.get('generalImage'), # 映射
|
||||
is_enabled=True if data.get('isEnabled', 1) == 1 else False
|
||||
)
|
||||
|
||||
db.session.add(new_material)
|
||||
db.session.commit()
|
||||
return new_material
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
def update_material(m_id, data):
|
||||
"""修改基础信息"""
|
||||
try:
|
||||
material = MaterialBase.query.get(m_id)
|
||||
if not material:
|
||||
raise ValueError("数据不存在")
|
||||
|
||||
# 更新字段 (仅更新传入的字段)
|
||||
if 'name' in data: material.name = data['name']
|
||||
if 'spec' in data: material.spec_model = data['spec']
|
||||
if 'category' in data: material.category = data['category']
|
||||
if 'type' in data: material.material_type = data['type']
|
||||
if 'unit' in data: material.unit = data['unit']
|
||||
if 'visibilityLevel' in data: material.visibility_level = data['visibilityLevel']
|
||||
if 'generalManual' in data: material.manual_link = data['generalManual']
|
||||
if 'generalImage' in data: material.product_image = data['generalImage']
|
||||
|
||||
if 'isEnabled' in data:
|
||||
material.is_enabled = bool(int(data['isEnabled']))
|
||||
|
||||
db.session.commit()
|
||||
return material
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
def delete_material(m_id):
|
||||
"""删除基础信息 (带依赖检查)"""
|
||||
try:
|
||||
material = MaterialBase.query.get(m_id)
|
||||
if not material:
|
||||
raise ValueError("数据不存在")
|
||||
|
||||
# 1. 依赖检查:如果该基础信息已经在库存表(StockBuy)中使用,禁止物理删除
|
||||
# 这里假设 StockBuy 表有一个外键或字段指向 MaterialBase (e.g., base_id)
|
||||
usage_count = StockBuy.query.filter_by(base_id=m_id).count()
|
||||
if usage_count > 0:
|
||||
raise ValueError(f"无法删除:该基础信息已被 {usage_count} 条库存记录引用,请先清理库存或仅禁用此条目。")
|
||||
|
||||
# 2. 执行删除
|
||||
db.session.delete(material)
|
||||
db.session.commit()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
print(f"删除基础信息失败: {e}")
|
||||
raise e
|
||||
@ -1,119 +0,0 @@
|
||||
from app.extensions import db
|
||||
from app.models.stock import StockBuy
|
||||
from app.models.material import MaterialBase
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
||||
|
||||
class StockService:
|
||||
@staticmethod
|
||||
def create_inbound(data):
|
||||
"""
|
||||
处理入库逻辑:
|
||||
1. 根据 SKU 查找物料。
|
||||
2. 如果没找到,创建新物料 (MaterialBase)。
|
||||
3. 创建入库单 (StockBuy)。
|
||||
"""
|
||||
try:
|
||||
sku = data.get('sku_code')
|
||||
material_id = data.get('material_id')
|
||||
|
||||
# --- 第一步:确定 material_id ---
|
||||
|
||||
# 如果前端没传 ID,或者传了但我们想二次确认,都通过 SKU 查一遍
|
||||
existing_material = MaterialBase.query.filter_by(sku_code=sku).first()
|
||||
|
||||
if existing_material:
|
||||
# 场景 A: 物料已存在 -> 直接使用其 ID
|
||||
material_id = existing_material.id
|
||||
else:
|
||||
# 场景 B: 物料不存在 -> 自动创建新物料
|
||||
if not data.get('material_name'):
|
||||
raise ValueError(f"SKU [{sku}] 是新物料,必须填写【物料名称】才能入库。")
|
||||
|
||||
new_material = MaterialBase(
|
||||
sku_code=sku,
|
||||
name=data.get('material_name'),
|
||||
spec_model=data.get('spec_model'),
|
||||
unit=data.get('unit'),
|
||||
category=data.get('category')
|
||||
)
|
||||
db.session.add(new_material)
|
||||
db.session.flush() # 关键:将对象刷入暂存区,以获取自增的 ID
|
||||
material_id = new_material.id
|
||||
|
||||
# --- 第二步:创建入库单 ---
|
||||
|
||||
qty = data.get('qty_inbound')
|
||||
price = data.get('price_unit', 0)
|
||||
|
||||
new_stock = StockBuy(
|
||||
material_id=material_id,
|
||||
inbound_date=data.get('inbound_date'),
|
||||
batch_no=data.get('batch_no'),
|
||||
warehouse_loc=data.get('warehouse_loc'),
|
||||
supplier_name=data.get('supplier_name'),
|
||||
|
||||
# 数量逻辑:初始时,当前量 = 可用量 = 入库量
|
||||
qty_inbound=qty,
|
||||
qty_current=qty,
|
||||
qty_available=qty,
|
||||
|
||||
# 财务逻辑
|
||||
price_unit=price,
|
||||
price_total=float(qty) * float(price) if qty else 0
|
||||
)
|
||||
|
||||
db.session.add(new_stock)
|
||||
db.session.commit() # 统一提交事务
|
||||
|
||||
return new_stock
|
||||
|
||||
except SQLAlchemyError as e:
|
||||
db.session.rollback() # 数据库报错回滚
|
||||
raise e
|
||||
except ValueError as e:
|
||||
db.session.rollback() # 业务报错回滚
|
||||
raise e
|
||||
|
||||
@staticmethod
|
||||
def get_list(page, per_page):
|
||||
"""获取分页列表"""
|
||||
pagination = StockBuy.query.order_by(StockBuy.inbound_date.desc()).paginate(
|
||||
page=page, per_page=per_page, error_out=False
|
||||
)
|
||||
return {
|
||||
'items': [item.to_dict() for item in pagination.items],
|
||||
'total': pagination.total,
|
||||
'pages': pagination.pages,
|
||||
'current_page': pagination.page
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def update_inbound(stock_id, data):
|
||||
"""更新入库单信息 (通常不允许改物料本身,只改入库相关)"""
|
||||
stock = StockBuy.query.get_or_404(stock_id)
|
||||
|
||||
if 'warehouse_loc' in data: stock.warehouse_loc = data['warehouse_loc']
|
||||
if 'supplier_name' in data: stock.supplier_name = data['supplier_name']
|
||||
if 'batch_no' in data: stock.batch_no = data['batch_no']
|
||||
if 'price_unit' in data: stock.price_unit = data['price_unit']
|
||||
|
||||
# 如果修改了数量,需要级联更新当前库存
|
||||
if 'qty_inbound' in data:
|
||||
old_qty = float(stock.qty_inbound)
|
||||
new_qty = float(data['qty_inbound'])
|
||||
diff = new_qty - old_qty
|
||||
|
||||
stock.qty_inbound = new_qty
|
||||
stock.qty_current = float(stock.qty_current) + diff
|
||||
stock.qty_available = float(stock.qty_available) + diff
|
||||
|
||||
db.session.commit()
|
||||
return stock
|
||||
|
||||
@staticmethod
|
||||
def delete_inbound(stock_id):
|
||||
"""删除入库单"""
|
||||
stock = StockBuy.query.get_or_404(stock_id)
|
||||
db.session.delete(stock)
|
||||
db.session.commit()
|
||||
Reference in New Issue
Block a user