package service
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/go-xorm/xorm"
|
|
"leit.com/leit_seat_aps/common"
|
|
"leit.com/leit_seat_aps/db"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// 车型业务对象
|
|
type BL_Carmodel struct {
|
|
Carmodelid string
|
|
Cm_pf_dict map[string]string // 车型分配的零件族
|
|
Cm_sg_dict map[string]string // 车型分配的供应组
|
|
Cm_attr_dict map[int]BL_Carmodel_Atcod // 车型分配的属性字典
|
|
Carmodeltab db.Me_carmodel
|
|
SpecDict map[int]BL_Carmodel_Spec // 用于存储当前车型的各种配置
|
|
}
|
|
|
|
// 车型分配的属性对象
|
|
type BL_Carmodel_Atcod struct {
|
|
Carmodelid string // 车型ID
|
|
Attrcode int // 属性ID
|
|
Mandatory int // 是否强制需要
|
|
Verifyrule string // 验证规则
|
|
Carmodel_attrtab db.Me_carmodel_atcodlst
|
|
}
|
|
|
|
// 车型版本规格
|
|
type BL_Carmodel_Spec struct {
|
|
Carmodelid string // 车型ID
|
|
Version int
|
|
Cmvtab db.Me_carmodel_ver
|
|
SGPartDict map[string]db.Me_carmodel_ver_partlst
|
|
Partlst []db.Me_carmodel_ver_partlst
|
|
AttrDict map[int]BL_OrdAttribute
|
|
VerrorDict map[string]BL_VerifyError // 校验报错信息
|
|
}
|
|
|
|
// 车型显示属性
|
|
type BL_Carmodel_Display struct {
|
|
Pos int
|
|
Attrcode int // 属性ID
|
|
Attrval string // 属性值
|
|
AttrvalDesc string // 值描述
|
|
AttrShortCode string // 值短码
|
|
}
|
|
|
|
// 验证OEM订单当前是否满足车型匹配需求:即零件族是否符合规范
|
|
func (bl_cm *BL_Carmodel) IsBelongToThisModel(cotablst []db.Pln_custorder) (belong bool) {
|
|
var (
|
|
i, j int
|
|
pfdict, sgdict map[string]string
|
|
pf, sg string
|
|
ok bool
|
|
)
|
|
|
|
// 获取客户订单集的零件族清单和供应组清单
|
|
pfdict = make(map[string]string)
|
|
sgdict = make(map[string]string)
|
|
for i = 0; i < len(cotablst); i++ {
|
|
pfdict[cotablst[i].Partfamilyid] = cotablst[i].Partfamilyid
|
|
for j = 0; j < len(cotablst[i].Sgpartlst); j++ {
|
|
sgdict[cotablst[i].Sgpartlst[j].Supplygroupid] = cotablst[i].Sgpartlst[j].Supplygroupid
|
|
}
|
|
}
|
|
|
|
// 判断零件族数量是否一致,一个客户订单对应一个零件族
|
|
if len(pfdict) != len(bl_cm.Cm_pf_dict) {
|
|
belong = false
|
|
return
|
|
}
|
|
|
|
// 判断各零件族ID是否一致
|
|
for pf, _ = range pfdict {
|
|
if _, ok = bl_cm.Cm_pf_dict[pf]; !ok {
|
|
belong = false
|
|
return
|
|
}
|
|
}
|
|
|
|
// 判断供应组数量是否一致
|
|
if len(sgdict) != len(bl_cm.Cm_sg_dict) {
|
|
belong = false
|
|
return
|
|
}
|
|
|
|
// 判断各供应组ID是否一致
|
|
for sg, _ = range sgdict {
|
|
if _, ok = bl_cm.Cm_sg_dict[sg]; !ok {
|
|
belong = false
|
|
return
|
|
}
|
|
}
|
|
|
|
belong = true
|
|
return
|
|
}
|
|
|
|
// 判断给定的客户订单清单是否属于当前车型规格
|
|
func (bl_cmspec *BL_Carmodel_Spec) IsBelongToThisSpec(cotablst []db.Pln_custorder) (belong bool) {
|
|
var (
|
|
i, j, sumqty int
|
|
key string
|
|
cmpartab db.Me_carmodel_ver_partlst
|
|
ok bool
|
|
)
|
|
|
|
// 判断零件数是否一致
|
|
sumqty = 0
|
|
for i = 0; i < len(cotablst); i++ {
|
|
sumqty = sumqty + len(cotablst[i].Sgpartlst)
|
|
}
|
|
|
|
if sumqty != len(bl_cmspec.SGPartDict) {
|
|
belong = false
|
|
return
|
|
}
|
|
|
|
// 逐个零件判断:SG_Partid
|
|
for i = 0; i < len(cotablst); i++ {
|
|
for j = 0; j < len(cotablst[i].Sgpartlst); j++ {
|
|
// 判断 供应组_零件ID 是否存在
|
|
key = cotablst[i].Sgpartlst[j].Supplygroupid + "_" + cotablst[i].Sgpartlst[j].Partid
|
|
if cmpartab, ok = bl_cmspec.SGPartDict[key]; !ok {
|
|
belong = false
|
|
return
|
|
}
|
|
// 存在则判断零件数量是否一致
|
|
if cotablst[i].Sgpartlst[j].Partqty != cmpartab.Partqty {
|
|
belong = false
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
belong = true
|
|
return
|
|
}
|
|
|
|
// 验证OEM订单当前是否满足车型匹配需求:即零件族是否符合规范
|
|
func (bl_cm *BL_Carmodel) IsNewSpecToThisModel(cotablst []db.Pln_custorder) (isnew bool, ver int) {
|
|
var (
|
|
bl_cmspec BL_Carmodel_Spec
|
|
)
|
|
|
|
isnew = true
|
|
for _, bl_cmspec = range bl_cm.SpecDict {
|
|
if bl_cmspec.IsBelongToThisSpec(cotablst) {
|
|
isnew = false
|
|
ver = bl_cmspec.Version
|
|
return
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// 创建新车型规格
|
|
func (bl_cm *BL_Carmodel) CreateNewCarmodel(cotablst []db.Pln_custorder, bl_proj *BL_Project, session *xorm.Session) (bl_cmspec BL_Carmodel_Spec, err error) {
|
|
var (
|
|
ver int
|
|
cmvtab db.Me_carmodel_ver
|
|
)
|
|
|
|
// 初始化
|
|
cmvtab = db.Me_carmodel_ver{}
|
|
if ver, err = cmvtab.GetLatestCarmodelVersion(bl_cm.Carmodelid); err != nil {
|
|
return
|
|
}
|
|
// 新版本号+1
|
|
ver = ver + 1
|
|
|
|
bl_cmspec = BL_Carmodel_Spec{Carmodelid: bl_cm.Carmodelid, Version: ver}
|
|
// 获取车型版本的属性
|
|
bl_cmspec.GetSpecAtcodList(cotablst, bl_proj)
|
|
// 验证车型版本属性
|
|
bl_cmspec.ValidateSpecAttribute(bl_cm)
|
|
// 保存车型版本相关数据
|
|
if err = bl_cmspec.Save(bl_cm, bl_proj, session); err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// 获取车型规格的零件清单和属性清单
|
|
func (bl_cmspec *BL_Carmodel_Spec) GetSpecAtcodList(cotablst []db.Pln_custorder, bl_proj *BL_Project) {
|
|
var (
|
|
i, j int
|
|
cmvpttab db.Me_carmodel_ver_partlst
|
|
bl_part BL_Part
|
|
bl_attr BL_OrdAttribute
|
|
bl_partattr BL_PartAttribute
|
|
key string
|
|
ok bool
|
|
)
|
|
|
|
bl_cmspec.Partlst = []db.Me_carmodel_ver_partlst{}
|
|
bl_cmspec.AttrDict = make(map[int]BL_OrdAttribute)
|
|
bl_cmspec.SGPartDict = make(map[string]db.Me_carmodel_ver_partlst)
|
|
|
|
// 获取零件清单和属性清单
|
|
for i = 0; i < len(cotablst); i++ {
|
|
for j = 0; j < len(cotablst[i].Sgpartlst); j++ {
|
|
cmvpttab = db.Me_carmodel_ver_partlst{Finr: db.G_FINR}
|
|
cmvpttab.Carmodelid = bl_cmspec.Carmodelid
|
|
cmvpttab.Version = bl_cmspec.Version
|
|
cmvpttab.Supplygroupid = cotablst[i].Sgpartlst[j].Supplygroupid
|
|
cmvpttab.Partid = cotablst[i].Sgpartlst[j].Partid
|
|
cmvpttab.Partqty = cotablst[i].Sgpartlst[j].Partqty
|
|
bl_cmspec.Partlst = append(bl_cmspec.Partlst, cmvpttab)
|
|
// 填充型号规格的零件字典
|
|
key = cmvpttab.Supplygroupid + "_" + cmvpttab.Partid
|
|
bl_cmspec.SGPartDict[key] = cmvpttab
|
|
// 获取零件对象,从而获取属性对象
|
|
if bl_part, ok = bl_proj.Partdict[cmvpttab.Partid]; !ok {
|
|
// 日志记录错误
|
|
continue
|
|
}
|
|
// 填充型号规格的属性字典
|
|
for _, bl_partattr = range bl_part.AtcodDict {
|
|
if bl_attr, ok = bl_cmspec.AttrDict[bl_partattr.Attrcode]; !ok {
|
|
bl_attr = BL_OrdAttribute{Attrcode: bl_partattr.Attrcode}
|
|
bl_attr.Attrvaldict = make(map[string]string)
|
|
bl_attr.Attrvaldict[bl_partattr.Attrvalue] = bl_partattr.Attrvalue
|
|
}
|
|
bl_attr.Attrvaldict[bl_partattr.Attrvalue] = bl_partattr.Attrvalue
|
|
bl_cmspec.AttrDict[bl_attr.Attrcode] = bl_attr
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// 验证车型规格属性
|
|
func (bl_cmspec *BL_Carmodel_Spec) ValidateSpecAttribute(bl_cm *BL_Carmodel) {
|
|
var (
|
|
bl_cmatcod BL_Carmodel_Atcod
|
|
bl_attr BL_OrdAttribute
|
|
verr BL_VerifyError
|
|
ok bool
|
|
)
|
|
|
|
// 初始化
|
|
bl_cmspec.VerrorDict = make(map[string]BL_VerifyError)
|
|
|
|
// 遍历车型的验证属性
|
|
for _, bl_cmatcod = range bl_cm.Cm_attr_dict {
|
|
// 属性必须存在
|
|
if bl_cmatcod.Carmodel_attrtab.Mandatory > 0 {
|
|
if _, ok = bl_cmspec.AttrDict[bl_cmatcod.Attrcode]; !ok {
|
|
verr = BL_VerifyError{}
|
|
verr.Errortype = common.CO_VERIFY_ATCOD_NOTEXIST
|
|
verr.Attrcode = bl_cmatcod.Attrcode
|
|
verr.Errorinfo = fmt.Sprintf("强制要求的属性: %d 不存在!", bl_cmatcod.Attrcode)
|
|
bl_cmspec.VerrorDict[verr.GetDictKey()] = verr
|
|
}
|
|
}
|
|
|
|
// 校验属性值
|
|
switch bl_cmatcod.Carmodel_attrtab.Verifyrule {
|
|
// 属性值唯一
|
|
case common.VERIFY_RULE_ATVAL_UNIQ:
|
|
if bl_attr, ok = bl_cmspec.AttrDict[bl_cmatcod.Attrcode]; ok {
|
|
if len(bl_attr.Attrvaldict) > 1 {
|
|
verr = BL_VerifyError{}
|
|
verr.Errortype = common.CO_VERIFY_ATCOD_VALUE_CONFLICT
|
|
verr.Attrcode = bl_cmatcod.Attrcode
|
|
verr.Errorinfo = fmt.Sprintf("属性: %d 存在多个冲突值!", bl_cmatcod.Attrcode)
|
|
bl_cmspec.VerrorDict[verr.GetDictKey()] = verr
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// 获取车型规格的显示属性
|
|
func (bl_cmspec *BL_Carmodel_Spec) GenerateSpecDescr(bl_cm *BL_Carmodel, bl_proj *BL_Project) (spec string) {
|
|
var (
|
|
bl_cmatcod BL_Carmodel_Atcod
|
|
bl_cmdisp BL_Carmodel_Display
|
|
inter interface{}
|
|
bl_cmdisplst []interface{}
|
|
bl_attr BL_Attribute
|
|
bl_ordattr BL_OrdAttribute
|
|
valst []string
|
|
val string
|
|
i, pos, idx int
|
|
err error
|
|
ok bool
|
|
)
|
|
// 遍历车型指定属性
|
|
bl_cmdisplst = []interface{}{}
|
|
for _, bl_cmatcod = range bl_cm.Cm_attr_dict {
|
|
if bl_cmatcod.Carmodel_attrtab.Attrvalue2 != "" {
|
|
valst = strings.Split(bl_cmatcod.Carmodel_attrtab.Attrvalue2, ":")
|
|
if len(valst) >= 2 && valst[0] == "DISPLAY" {
|
|
if pos, err = strconv.Atoi(valst[1]); err != nil {
|
|
continue
|
|
}
|
|
|
|
// 获取属性
|
|
if bl_attr, ok = bl_proj.Attrdict[bl_cmatcod.Attrcode]; !ok {
|
|
continue
|
|
}
|
|
// 在当前spec中获取属性(值必须是唯一)
|
|
if bl_ordattr, ok = bl_cmspec.AttrDict[bl_cmatcod.Attrcode]; !ok {
|
|
continue
|
|
}
|
|
|
|
// 生成显示属性
|
|
for _, val = range bl_ordattr.Attrvaldict {
|
|
}
|
|
idx = bl_attr.GetValPos(val)
|
|
if idx < 0 {
|
|
continue
|
|
}
|
|
|
|
bl_cmdisp = BL_Carmodel_Display{}
|
|
bl_cmdisp.Pos = pos
|
|
bl_cmdisp.Attrcode = bl_cmatcod.Carmodel_attrtab.Attrcode
|
|
bl_cmdisp.Attrval = bl_attr.Atvaltablst[idx].Attrvalue
|
|
bl_cmdisp.AttrvalDesc = bl_attr.Atvaltablst[idx].Descr
|
|
bl_cmdisp.AttrShortCode = bl_attr.Atvaltablst[idx].Shortcode
|
|
bl_cmdisplst = append(bl_cmdisplst, bl_cmdisp)
|
|
}
|
|
}
|
|
}
|
|
// 指定pos字段排序
|
|
common.SortBody(bl_cmdisplst, func(p, q *interface{}) bool {
|
|
v := reflect.ValueOf(*p)
|
|
i := v.FieldByName("Pos")
|
|
v = reflect.ValueOf(*q)
|
|
j := v.FieldByName("Pos")
|
|
return i.Int() < j.Int()
|
|
})
|
|
// 拼接值返回
|
|
spec = ""
|
|
for i, inter = range bl_cmdisplst {
|
|
// 断言转换类型
|
|
if bl_cmdisp, ok = inter.(BL_Carmodel_Display); !ok {
|
|
continue
|
|
}
|
|
if i == 0 {
|
|
spec = bl_cmdisp.Attrval
|
|
} else {
|
|
spec = spec + " " + bl_cmdisp.Attrval
|
|
}
|
|
}
|
|
// 超长处理,自动截取
|
|
if len(spec) > 160 {
|
|
return spec[:160]
|
|
}
|
|
return
|
|
}
|
|
|
|
// 获取车型规格的显示属性
|
|
func (bl_cmspec *BL_Carmodel_Spec) GenerateSpecDescrNew(bl_cm *BL_Carmodel, bl_proj *BL_Project) (spec string) {
|
|
var (
|
|
bl_cmatcod BL_Carmodel_Atcod
|
|
bl_cmdisp BL_Carmodel_Display
|
|
inter interface{}
|
|
bl_cmdisplst []interface{}
|
|
bl_attr BL_Attribute
|
|
bl_ordattr BL_OrdAttribute
|
|
val string
|
|
iAtcod int
|
|
i, idx int
|
|
ok bool
|
|
)
|
|
|
|
bl_cmdisplst = []interface{}{}
|
|
// 遍历车型指定属性
|
|
for i = 0; i < len(bl_cm.Carmodeltab.Atcodlst); i++ {
|
|
switch bl_cm.Carmodeltab.Atcodlst[i].Verifyrule {
|
|
// 显示属性
|
|
case common.VERIFY_RULE_ATVAL_DISP:
|
|
iAtcod = bl_cm.Carmodeltab.Atcodlst[i].Attrcode
|
|
// 获取属性
|
|
if bl_attr, ok = bl_proj.Attrdict[iAtcod]; !ok {
|
|
continue
|
|
}
|
|
|
|
bl_cmdisp = BL_Carmodel_Display{}
|
|
bl_cmdisp.Pos = bl_cm.Carmodeltab.Atcodlst[i].Pos
|
|
bl_cmdisp.Attrcode = bl_cmatcod.Carmodel_attrtab.Attrcode
|
|
|
|
// 如果属性不存在则取-
|
|
if bl_ordattr, ok = bl_cmspec.AttrDict[iAtcod]; !ok {
|
|
bl_cmdisp.AttrShortCode = "-"
|
|
bl_cmdisplst = append(bl_cmdisplst, bl_cmdisp)
|
|
continue
|
|
}
|
|
|
|
// 生成显示属性
|
|
for _, val = range bl_ordattr.Attrvaldict {
|
|
idx = bl_attr.GetValPos(val)
|
|
if idx < 0 {
|
|
bl_cmdisp.AttrShortCode = "-"
|
|
bl_cmdisplst = append(bl_cmdisplst, bl_cmdisp)
|
|
continue
|
|
}
|
|
}
|
|
|
|
bl_cmdisp.Attrval = bl_attr.Atvaltablst[idx].Attrvalue
|
|
bl_cmdisp.AttrvalDesc = bl_attr.Atvaltablst[idx].Descr
|
|
if strings.TrimSpace(bl_attr.Atvaltablst[idx].Shortcode) == "" {
|
|
bl_cmdisp.AttrShortCode = "-"
|
|
} else {
|
|
bl_cmdisp.AttrShortCode = bl_attr.Atvaltablst[idx].Shortcode
|
|
}
|
|
bl_cmdisplst = append(bl_cmdisplst, bl_cmdisp)
|
|
}
|
|
}
|
|
|
|
// 指定pos字段排序
|
|
common.SortBody(bl_cmdisplst, func(p, q *interface{}) bool {
|
|
v := reflect.ValueOf(*p)
|
|
i := v.FieldByName("Pos")
|
|
v = reflect.ValueOf(*q)
|
|
j := v.FieldByName("Pos")
|
|
return i.Int() < j.Int()
|
|
})
|
|
// 拼接值返回
|
|
spec = ""
|
|
for i, inter = range bl_cmdisplst {
|
|
// 断言转换类型
|
|
if bl_cmdisp, ok = inter.(BL_Carmodel_Display); !ok {
|
|
continue
|
|
}
|
|
if i == 0 {
|
|
spec = bl_cmdisp.AttrShortCode
|
|
} else {
|
|
spec = spec + bl_cmdisp.AttrShortCode
|
|
}
|
|
}
|
|
// 超长处理,自动截取
|
|
if len(spec) > 160 {
|
|
return spec[:160]
|
|
}
|
|
return
|
|
}
|
|
|
|
// 保存车型规格
|
|
func (bl_cmspec *BL_Carmodel_Spec) Save(bl_cm *BL_Carmodel, bl_proj *BL_Project, session *xorm.Session) (err error) {
|
|
var (
|
|
i int
|
|
bl_attr BL_OrdAttribute
|
|
bl_verr BL_VerifyError
|
|
attrval string
|
|
cmvattab db.Me_carmodel_ver_atcodlst
|
|
cmvertab db.Me_carmodel_ver_errorlst
|
|
)
|
|
|
|
// 保存版本头
|
|
bl_cmspec.Cmvtab = db.Me_carmodel_ver{Finr: db.G_FINR}
|
|
bl_cmspec.Cmvtab.Carmodelid = bl_cmspec.Carmodelid
|
|
bl_cmspec.Cmvtab.Version = bl_cmspec.Version
|
|
bl_cmspec.Cmvtab.Status = common.CM_SPEC_UNAPPROVED
|
|
if len(bl_cmspec.VerrorDict) > 0 {
|
|
bl_cmspec.Cmvtab.Handlestatus = common.CM_PARSE_ERROR
|
|
} else {
|
|
bl_cmspec.Cmvtab.Handlestatus = common.CM_PARSE_OK
|
|
}
|
|
bl_cmspec.Cmvtab.Spec = bl_cmspec.GenerateSpecDescrNew(bl_cm, bl_proj)
|
|
bl_cmspec.Cmvtab.Credatuz = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss")
|
|
bl_cmspec.Cmvtab.Lastuser = "cm_service"
|
|
if err = bl_cmspec.Cmvtab.Insert(session); err != nil {
|
|
return
|
|
}
|
|
|
|
// 保存零件清单
|
|
for i = 0; i < len(bl_cmspec.Partlst); i++ {
|
|
bl_cmspec.Partlst[i].Credatuz = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss")
|
|
bl_cmspec.Partlst[i].Lastuser = "cm_service"
|
|
if err = bl_cmspec.Partlst[i].Insert(session); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
// 保存属性清单
|
|
i = 1
|
|
for _, bl_attr = range bl_cmspec.AttrDict {
|
|
cmvattab = db.Me_carmodel_ver_atcodlst{Finr: db.G_FINR}
|
|
cmvattab.Carmodelid = bl_cmspec.Carmodelid
|
|
cmvattab.Version = bl_cmspec.Version
|
|
cmvattab.Attrcode = bl_attr.Attrcode
|
|
for _, attrval = range bl_attr.Attrvaldict {
|
|
cmvattab.Pos = i
|
|
cmvattab.Attrvalue = attrval
|
|
cmvattab.Credatuz = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss")
|
|
cmvattab.Lastuser = "cm_service"
|
|
if err = cmvattab.Insert(session); err != nil {
|
|
return
|
|
}
|
|
i++
|
|
}
|
|
}
|
|
|
|
// 保存验证错误
|
|
i = 1
|
|
for _, bl_verr = range bl_cmspec.VerrorDict {
|
|
cmvertab = db.Me_carmodel_ver_errorlst{Finr: db.G_FINR}
|
|
cmvertab.Carmodelid = bl_cmspec.Carmodelid
|
|
cmvertab.Version = bl_cmspec.Version
|
|
cmvertab.Pos = i
|
|
cmvertab.Attrcode = bl_verr.Attrcode
|
|
cmvertab.Errortype = bl_verr.Errortype
|
|
cmvertab.Errorinfo = bl_verr.Errorinfo
|
|
cmvertab.Errorstatus = "O"
|
|
cmvertab.Credatuz = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss")
|
|
cmvertab.Lastuser = "cm_service"
|
|
if err = cmvertab.Insert(session); err != nil {
|
|
return
|
|
}
|
|
|
|
i++
|
|
}
|
|
|
|
return
|
|
}
|