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 }