将半成品成品同样进行新增所属公司以及内容修改

This commit is contained in:
dxc
2026-02-24 16:16:17 +08:00
parent 42171ed612
commit 31ddb1aafd
7 changed files with 464 additions and 155 deletions

View File

@ -3,6 +3,7 @@ from app.extensions import db
import json
from app.models.base import MaterialBase
class StockProduct(db.Model):
"""
成品入库库存表
@ -44,7 +45,7 @@ class StockProduct(db.Model):
quality_report_link = db.Column(db.Text) # 质量报告
inspection_report_link = db.Column(db.Text) # 检测报告(旧字段升级为JSON)
# [新增] 成品实拍图 (JSON 存储)
# 成品实拍图 (JSON 存储)
product_photo = db.Column(db.Text)
detail_link = db.Column(db.Text)
@ -57,7 +58,7 @@ class StockProduct(db.Model):
# 全局打印流水号
global_print_id = db.Column(db.Integer)
# 关系定义 [已修改]
# 关系定义
base = db.relationship('MaterialBase', back_populates='stock_products')
def to_dict(self):
@ -79,7 +80,9 @@ class StockProduct(db.Model):
return {
'id': self.id,
'base_id': self.base_id,
# [已修改] 使用 self.base
# [新增] 公司名称
'company_name': self.base.company_name if self.base else '',
'material_name': self.base.name if self.base else '',
'spec_model': self.base.spec_model if self.base else '',
'category': self.base.category if self.base else '',
@ -115,7 +118,6 @@ class StockProduct(db.Model):
'quality_status': self.quality_status,
# [核心修改] 三个图片/链接字段全部解析为数组
'product_photo': parse_img_list(self.product_photo),
'quality_report_link': parse_img_list(self.quality_report_link),
'inspection_report_link': parse_img_list(self.inspection_report_link),

View File

@ -3,6 +3,7 @@ from app.extensions import db
import json
from app.models.base import MaterialBase
class StockSemi(db.Model):
"""
半成品入库库存表
@ -43,19 +44,19 @@ class StockSemi(db.Model):
quality_status = db.Column(db.String(50))
# [修改] 质量报告 (存储 JSON 字符串: 图片列表 + 链接)
# 质量报告 (存储 JSON 字符串: 图片列表 + 链接)
quality_report_link = db.Column(db.Text)
# [新增] 到货图片 (存储 JSON 字符串)
# 到货图片 (存储 JSON 字符串)
arrival_photo = db.Column(db.Text)
detail_link = db.Column(db.Text)
remark = db.Column(db.Text)
# [新增] 全局打印流水号
# 全局打印流水号
global_print_id = db.Column(db.Integer)
# 关系定义 [已修改]
# 关系定义
base = db.relationship('MaterialBase', back_populates='stock_semis')
def to_dict(self):
@ -78,7 +79,9 @@ class StockSemi(db.Model):
return {
'id': self.id,
'base_id': self.base_id,
# [已修改] 使用 self.base
# [新增] 公司名称
'company_name': self.base.company_name if self.base else '',
'material_name': self.base.name if self.base else '',
'spec_model': self.base.spec_model if self.base else '',
'category': self.base.category if self.base else '',
@ -115,7 +118,6 @@ class StockSemi(db.Model):
'quality_status': self.quality_status,
# [修改] 解析 JSON 字符串为数组返回给前端
'quality_report_link': parse_img_list(self.quality_report_link),
'arrival_photo': parse_img_list(self.arrival_photo),

View File

@ -33,10 +33,12 @@ class ProductInboundService:
try:
query = MaterialBase.query.filter(MaterialBase.is_enabled == True)
if keyword:
kw = f'%{keyword}%'
query = query.filter(
or_(
MaterialBase.name.ilike(f'%{keyword}%'),
MaterialBase.spec_model.ilike(f'%{keyword}%')
MaterialBase.name.ilike(kw),
MaterialBase.spec_model.ilike(kw),
MaterialBase.company_name.ilike(kw) # [新增]
)
)
query = query.order_by(MaterialBase.id.desc()).limit(20)
@ -44,6 +46,7 @@ class ProductInboundService:
for item in query.all():
results.append({
'id': item.id,
'company_name': item.company_name, # [新增]
'name': item.name,
'spec': item.spec_model,
'category': item.category,
@ -57,13 +60,12 @@ class ProductInboundService:
return []
# ============================================================
# 1.5 [新增] BOM 搜索逻辑
# 1.5 BOM 搜索逻辑
# ============================================================
@staticmethod
def search_bom_options(keyword):
from app.models.bom import BomTable
try:
# 关联查询BOM表 + 父件基础信息表
query = db.session.query(
BomTable.bom_no,
BomTable.version,
@ -71,13 +73,11 @@ class ProductInboundService:
MaterialBase.spec_model.label('parent_spec')
).join(MaterialBase, BomTable.parent_id == MaterialBase.id)
# 只查询启用的BOM
if hasattr(BomTable, 'is_enabled'):
query = query.filter(BomTable.is_enabled == True)
if keyword:
kw = f'%{keyword}%'
# 支持搜索BOM编号、父件名称、父件规格
query = query.filter(
or_(
BomTable.bom_no.ilike(kw),
@ -86,7 +86,6 @@ class ProductInboundService:
)
)
# 去重并限制数量
results = query.distinct().limit(20).all()
return [{
@ -283,23 +282,30 @@ class ProductInboundService:
# 6. 获取列表
# ============================================================
@staticmethod
def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None):
def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None, company=None):
from app.models.inbound.product import StockProduct
try:
query = db.session.query(StockProduct).outerjoin(MaterialBase, StockProduct.base_id == MaterialBase.id)
if keyword:
kw = f'%{keyword}%'
query = query.filter(or_(
MaterialBase.name.ilike(f'%{keyword}%'),
MaterialBase.spec_model.ilike(f'%{keyword}%'),
StockProduct.serial_number.ilike(f'%{keyword}%'),
StockProduct.work_order_code.ilike(f'%{keyword}%'),
StockProduct.order_id.ilike(f'%{keyword}%'),
StockProduct.sku.ilike(f'%{keyword}%')
MaterialBase.name.ilike(kw),
MaterialBase.spec_model.ilike(kw),
MaterialBase.company_name.ilike(kw), # [新增]
StockProduct.serial_number.ilike(kw),
StockProduct.work_order_code.ilike(kw),
StockProduct.order_id.ilike(kw),
StockProduct.sku.ilike(kw)
))
if category and category.strip():
query = query.filter(MaterialBase.category == category.strip())
if material_type and material_type.strip():
query = query.filter(MaterialBase.material_type == material_type.strip())
# [新增]
if company and company.strip():
query = query.filter(MaterialBase.company_name == company.strip())
if not statuses:
statuses = ['在库', '借库']
if '已出库' in statuses:
@ -324,23 +330,7 @@ class ProductInboundService:
items = []
for item in current_items:
d = item.to_dict()
date_display = ''
if item.production_date:
try:
date_display = item.production_date.strftime('%Y-%m-%d')
except:
date_display = str(item.production_date)[:10]
d['inbound_date'] = date_display
d['qty_stock'] = float(item.stock_quantity or 0)
d['qty_available'] = float(item.available_quantity or 0)
d['sum_stock'] = d['qty_stock']
d['sum_available'] = d['qty_available']
d['product_photo'] = parse_img(item.product_photo)
d['quality_report_link'] = parse_img(item.quality_report_link)
d['inspection_report_link'] = parse_img(item.inspection_report_link)
d['global_print_id'] = item.global_print_id
items.append(d)
items.append(item.to_dict()) # 使用 Model to_dict
return {"total": pagination.total, "items": items}
except:
traceback.print_exc()
@ -368,21 +358,37 @@ class ProductInboundService:
except Exception:
return []
# ============================================================
# 7. 获取筛选项
# ============================================================
@staticmethod
def get_filter_options():
try:
from app.models.base import MaterialBase
# 类别
categories = db.session.query(MaterialBase.category) \
.filter(MaterialBase.category != None, MaterialBase.category != '') \
.distinct().all()
sorted_categories = sorted([r[0] for r in categories])
# 类型
types = db.session.query(MaterialBase.material_type) \
.filter(MaterialBase.material_type != None, MaterialBase.material_type != '') \
.distinct().all()
sorted_types = sorted([r[0] for r in types])
# [新增] 公司
companies = db.session.query(MaterialBase.company_name) \
.filter(MaterialBase.company_name != None, MaterialBase.company_name != '') \
.distinct().all()
sorted_companies = sorted([r[0] for r in companies])
return {
"categories": [r[0] for r in categories],
"types": [r[0] for r in types]
"categories": sorted_categories,
"types": sorted_types,
"companies": sorted_companies
}
except Exception:
import traceback
traceback.print_exc()
return {"categories": [], "types": []}
return {"categories": [], "types": [], "companies": []}

View File

@ -43,10 +43,12 @@ class SemiInboundService:
try:
query = MaterialBase.query.filter(MaterialBase.is_enabled == True)
if keyword:
kw = f'%{keyword}%'
query = query.filter(
or_(
MaterialBase.name.ilike(f'%{keyword}%'),
MaterialBase.spec_model.ilike(f'%{keyword}%')
MaterialBase.name.ilike(kw),
MaterialBase.spec_model.ilike(kw),
MaterialBase.company_name.ilike(kw) # [新增] 支持搜公司
)
)
query = query.order_by(MaterialBase.id.desc()).limit(20)
@ -54,6 +56,7 @@ class SemiInboundService:
for item in query.all():
results.append({
'id': item.id,
'company_name': item.company_name, # [新增]
'name': item.name,
'spec': item.spec_model,
'category': item.category,
@ -67,13 +70,12 @@ class SemiInboundService:
return []
# ============================================================
# 1.5 [新增] BOM 搜索逻辑
# 1.5 BOM 搜索逻辑
# ============================================================
@staticmethod
def search_bom_options(keyword):
from app.models.bom import BomTable
try:
# 关联查询BOM表 + 父件基础信息表
query = db.session.query(
BomTable.bom_no,
BomTable.version,
@ -81,13 +83,11 @@ class SemiInboundService:
MaterialBase.spec_model.label('parent_spec')
).join(MaterialBase, BomTable.parent_id == MaterialBase.id)
# 只查询启用的BOM
if hasattr(BomTable, 'is_enabled'):
query = query.filter(BomTable.is_enabled == True)
if keyword:
kw = f'%{keyword}%'
# 支持搜索BOM编号、父件名称、父件规格
query = query.filter(
or_(
BomTable.bom_no.ilike(kw),
@ -96,7 +96,6 @@ class SemiInboundService:
)
)
# 去重并限制数量
results = query.distinct().limit(20).all()
return [{
@ -367,7 +366,7 @@ class SemiInboundService:
# 6. 获取列表
# ============================================================
@staticmethod
def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None):
def get_list(page, limit, keyword=None, statuses=None, category=None, material_type=None, company=None):
from app.models.inbound.semi import StockSemi
try:
query = db.session.query(StockSemi).outerjoin(MaterialBase, StockSemi.base_id == MaterialBase.id)
@ -377,6 +376,7 @@ class SemiInboundService:
or_(
MaterialBase.name.ilike(kw),
MaterialBase.spec_model.ilike(kw),
MaterialBase.company_name.ilike(kw), # [新增]
StockSemi.batch_number.ilike(kw),
StockSemi.serial_number.ilike(kw),
StockSemi.sku.ilike(kw),
@ -388,6 +388,11 @@ class SemiInboundService:
query = query.filter(MaterialBase.category == category.strip())
if material_type and material_type.strip():
query = query.filter(MaterialBase.material_type == material_type.strip())
# [新增] 公司筛选
if company and company.strip():
query = query.filter(MaterialBase.company_name == company.strip())
if not statuses:
statuses = ['在库', '借库']
if '已出库' in statuses:
@ -412,22 +417,7 @@ class SemiInboundService:
items = []
for item in current_items:
d = item.to_dict()
date_display = ''
if item.production_date:
try:
date_display = item.production_date.strftime('%Y-%m-%d')
except:
date_display = str(item.production_date)[:10]
d['inbound_date'] = date_display
d['qty_stock'] = float(item.stock_quantity or 0)
d['qty_available'] = float(item.available_quantity or 0)
d['sum_stock'] = d['qty_stock']
d['sum_available'] = d['qty_available']
d['arrival_photo'] = parse_img(item.arrival_photo)
d['quality_report_link'] = parse_img(item.quality_report_link)
d['global_print_id'] = item.global_print_id
items.append(d)
items.append(item.to_dict()) # 直接使用 Model 的 to_dict (已包含 company_name)
return {"total": pagination.total, "items": items}
except Exception as e:
print(f"List Error: {e}")
@ -456,21 +446,37 @@ class SemiInboundService:
except Exception:
return []
# ============================================================
# 7. 获取筛选项 (排序)
# ============================================================
@staticmethod
def get_filter_options():
try:
from app.models.base import MaterialBase
# 类别
categories = db.session.query(MaterialBase.category) \
.filter(MaterialBase.category != None, MaterialBase.category != '') \
.distinct().all()
sorted_categories = sorted([r[0] for r in categories])
# 类型
types = db.session.query(MaterialBase.material_type) \
.filter(MaterialBase.material_type != None, MaterialBase.material_type != '') \
.distinct().all()
sorted_types = sorted([r[0] for r in types])
# [新增] 公司
companies = db.session.query(MaterialBase.company_name) \
.filter(MaterialBase.company_name != None, MaterialBase.company_name != '') \
.distinct().all()
sorted_companies = sorted([r[0] for r in companies])
return {
"categories": [r[0] for r in categories],
"types": [r[0] for r in types]
"categories": sorted_categories,
"types": sorted_types,
"companies": sorted_companies
}
except Exception:
import traceback
traceback.print_exc()
return {"categories": [], "types": []}
return {"categories": [], "types": [], "companies": []}