Files
bj_power/bj_power_mes/internal/logic/product.go
T
SunYF f274da044c feat: 重构BOM架构,新增基础设置与虚拟工位管理功能
本次重构删除原有BOM物料清单表,改用工单工艺组合×工艺物料清单作为唯一用料来源;新增系统基础设置表支持WMS地址、日志保留天数等配置,新增虚拟工位作业管理后台接口与前端页签控制功能,同时优化工位号校验逻辑、事件日志自动清理与工单用料查询能力。
2026-09-23 11:41:28 +08:00

132 lines
4.8 KiB
Go
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.
package logic
import (
"context"
"errors"
"fmt"
"strings"
"bj_power_mes/ent/workorder"
"bj_power_mes/internal/wmsclient"
)
// 产品型号(成品档案):编码主数据单一来源 = WMSmaterials item_type=3)。
// MES 本页实时代理 WMS;不再保留本地 product_types 缓存/双写(方案 A:WMS 不可达即报错,
// 不降级读本地缓存,避免给界面喂空/陈旧数据)。
type ProductTypeReq struct {
Id int `json:"id"`
Name string `json:"name"`
Code string `json:"code"`
Spec string `json:"spec"`
Unit string `json:"unit"`
Category string `json:"category"`
ManageMode int `json:"manageMode"` // 1结构件(批次)/2电气件(SN);MES 成品只列这两个
IsActive bool `json:"isActive"`
}
func (s *Service) CreateProductType(ctx context.Context, req ProductTypeReq) error {
active := req.IsActive
if !req.IsActive {
active = true
}
if strings.TrimSpace(req.Name) == "" {
return errors.New("名称为必填项")
}
if strings.TrimSpace(req.Spec) == "" {
return errors.New("规格型号为必填项")
}
if strings.TrimSpace(req.Unit) == "" {
return errors.New("单位为必填项")
}
if err := s.ctx.Wms.CreateProductType(ctx, req.Code, req.Name, req.Spec, req.Unit, req.Category, active, req.ManageMode); err != nil {
return errors.New("WMS 不可达或拒绝写入(编码主数据以 WMS 为单一来源):" + err.Error())
}
return nil
}
func (s *Service) UpdateProductType(ctx context.Context, req ProductTypeReq) error {
if req.Id == 0 {
return errors.New("缺少 id")
}
if strings.TrimSpace(req.Name) == "" {
return errors.New("名称为必填项")
}
if strings.TrimSpace(req.Spec) == "" {
return errors.New("规格型号为必填项")
}
if strings.TrimSpace(req.Unit) == "" {
return errors.New("单位为必填项")
}
if err := s.ctx.Wms.UpdateProductType(ctx, req.Id, req.Name, req.Spec, req.Unit, req.Category, req.IsActive, req.ManageMode); err != nil {
return errors.New("WMS 不可达或拒绝写入:" + err.Error())
}
return nil
}
// DeleteProductType 删除保护:被工单/BOM 引用过的型号禁删(MES 侧引用校验,
// WMS 侧库存引用由 WMS 内部接口再校验一层)
func (s *Service) DeleteProductType(ctx context.Context, id int) error {
row, err := s.ProductTypeByID(ctx, id)
if err != nil {
return err
}
woCnt, _ := s.ctx.EntClient.WorkOrder.Query().Where(workorder.ProductCode(row.Code)).Count(ctx)
if woCnt > 0 {
return fmt.Errorf("该物料档案已被 %d 张工单引用,不可删除;建议停用(下架)", woCnt)
}
if err := s.ctx.Wms.DeleteProductType(ctx, id); err != nil {
return errors.New("WMS 不可达或拒绝删除:" + err.Error())
}
return nil
}
// ListProductTypes 全量列表(下拉/兼容形态,id asc 新建在底部)。
// 纯 WMS 代理:WMS 不可达直接报错(不再降级本地缓存)。degraded 恒为 true(仅兼容前端字段)。
func (s *Service) ListProductTypes(ctx context.Context, isActive string) ([]wmsclient.ProductTypeRow, bool, error) {
list, err := s.ctx.Wms.ProductTypes(ctx, isActive)
if err != nil {
return nil, false, errors.New("WMS 不可达,无法读取成品档案:" + err.Error())
}
return list, true, nil
}
// ListProductTypesPage 分页+搜索(管理页真分页)。
// 2026-09-08 禁止关键字混搜:编码/名称/类别各自独立模糊。
// 纯 WMS 代理:WMS 不可达直接报错。wmsOnline 恒为 true(仅兼容前端字段)。
func (s *Service) ListProductTypesPage(ctx context.Context, code, name, category, isActive string, page, pageSize int) (int64, []wmsclient.ProductTypeRow, bool, error) {
total, list, err := s.ctx.Wms.ProductTypePage(ctx, code, name, category, isActive, page, pageSize)
if err != nil {
return 0, nil, false, errors.New("WMS 不可达,无法读取成品档案:" + err.Error())
}
return total, list, true, nil
}
// ProductTypeByID 从 WMS 取成品档案(item_type=3)按 idWMS 不可达即报错。
func (s *Service) ProductTypeByID(ctx context.Context, id int) (*wmsclient.ProductTypeRow, error) {
list, err := s.ctx.Wms.ProductTypes(ctx, "")
if err != nil {
return nil, errors.New("WMS 不可达,无法读取成品档案:" + err.Error())
}
for i := range list {
if list[i].ID == id {
return &list[i], nil
}
}
return nil, errors.New("物料档案不存在")
}
// ProductTypeByCode 从 WMS 取成品档案按 code。
func (s *Service) ProductTypeByCode(ctx context.Context, code string) (*wmsclient.ProductTypeRow, error) {
list, err := s.ctx.Wms.ProductTypes(ctx, "")
if err != nil {
return nil, errors.New("WMS 不可达,无法读取成品档案:" + err.Error())
}
for i := range list {
if list[i].Code == code {
return &list[i], nil
}
}
return nil, errors.New("物料档案不存在")
}