Files
KCGL/inventory-backend/app/services/bom_draft_service.py

145 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from app.extensions import db
from app.models.bom_draft import BomDraftTable
from app.models.base import MaterialBase
from app.services.bom_service import BomService
import logging
logger = logging.getLogger(__name__)
class BomDraftService:
@staticmethod
def save_draft(bom_no, version, parent_id, children):
try:
# 1. 删除旧草稿
old = BomDraftTable.query.filter_by(bom_no=bom_no, version=version).all()
for rec in old:
db.session.delete(rec)
db.session.flush()
# 2. 如果没有任何子件,必须插入一条只包含 parent_id 的占位头数据
if not children:
dummy_draft = BomDraftTable(
bom_no=bom_no, version=version, parent_id=parent_id,
child_id=None, dosage=0, loss_rate=0, remark=''
)
db.session.add(dummy_draft)
else:
# 正常批量插入新草稿行
for child in children:
draft = BomDraftTable(
bom_no=bom_no, version=version, parent_id=parent_id,
child_id=child.get('child_id'),
dosage=child.get('dosage', 0),
loss_rate=child.get('loss_rate', 0),
remark=child.get('remark', '')
)
db.session.add(draft)
db.session.commit()
except Exception as e:
db.session.rollback()
logger.error(f"[BomDraft] save_draft 失败 bom_no={bom_no}: {e}")
raise
return bom_no
@staticmethod
def get_draft_detail(bom_no, version):
rows = db.session.query(
BomDraftTable,
MaterialBase.name.label('child_name'),
MaterialBase.spec_model.label('child_spec')
).outerjoin(
MaterialBase, BomDraftTable.child_id == MaterialBase.id
).filter(
BomDraftTable.bom_no == bom_no,
BomDraftTable.version == version
).all()
if not rows:
return None
first = rows[0].BomDraftTable
parent_id = first.parent_id
parent_material = MaterialBase.query.get(parent_id) if parent_id else None
children = []
for draft, child_name, child_spec in rows:
# 过滤掉保存 BOM 头时插入的占位空行
if draft.child_id is not None:
children.append({
'child_id': draft.child_id,
'child_name': child_name or '',
'child_spec': child_spec or '',
'dosage': float(draft.dosage) if draft.dosage else 0.0,
'loss_rate': float(draft.loss_rate) if draft.loss_rate else 0.0,
'remark': draft.remark or '',
})
return {
'bom_no': bom_no,
'version': first.version,
'parent_id': parent_id,
'parent_name': parent_material.name if parent_material else '',
'parent_spec': parent_material.spec_model if parent_material else '',
'children': children,
}
@staticmethod
def publish_draft(bom_no, version):
"""
发布草稿为正式 BOM
1. 获取草稿数据
2. 强校验(父件不为空、子件列表非空、所有子件 ID>0、用量>0
3. 调用 BomService.save_bom 写入正式 bom_table
4. 清空草稿数据
"""
try:
# 步骤 1
draft = BomDraftService.get_draft_detail(bom_no, version)
if not draft:
raise ValueError('草稿不存在')
# 步骤 2强校验
if not draft.get('parent_id'):
raise ValueError('发布失败:父件不能为空')
children = draft.get('children', [])
if not children:
raise ValueError('发布失败:子件列表不能为空')
for child in children:
if not child.get('child_id') or child['child_id'] <= 0:
raise ValueError('发布失败子件ID必须大于0')
dosage = child.get('dosage')
if not dosage or dosage <= 0:
raise ValueError('发布失败子件用量必须大于0')
# 步骤 3复用正式 BOM 的写入逻辑(跨版本查重 + 缓存清理均在 save_bom 内完成)
publish_data = {
'bom_no': bom_no,
'version': version,
'parent_id': draft['parent_id'],
'children': [
{
'child_id': child['child_id'],
'dosage': child['dosage'],
'remark': child.get('remark', ''),
}
for child in children
],
}
BomService.save_bom(publish_data)
# 步骤 4清空草稿数据
old_rows = BomDraftTable.query.filter_by(bom_no=bom_no, version=version).all()
for rec in old_rows:
db.session.delete(rec)
db.session.commit()
logger.info(f"[BomDraft] publish_draft bom_no={bom_no} version={version} -> 已发布并清空草稿")
except Exception as e:
db.session.rollback()
logger.error(f"[BomDraft] publish_draft 失败 bom_no={bom_no}: {e}")
raise
return bom_no