package logic import ( "errors" "fmt" "micro-bundle/internal/dao" "micro-bundle/pkg/app" "micro-bundle/pkg/msg" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/utils" "github.com/jinzhu/copier" "gorm.io/gorm" "micro-bundle/internal/model" "micro-bundle/pb/bundle" ) func CreateBundle(req *bundle.BundleProfile) (res *bundle.CommonResponse, err error) { res = new(bundle.CommonResponse) bundleProfile := new(model.BundleProfile) _ = copier.CopyWithOption(&bundleProfile, req, copier.Option{DeepCopy: true}) bundleProfile.UUID = utils.GetUUID() res, err = dao.CreateBundle(bundleProfile) return } func UpdateBundle(req *bundle.BundleProfile) (res *bundle.CommonResponse, err error) { res = new(bundle.CommonResponse) bundleProfile := new(model.BundleProfile) _ = copier.CopyWithOption(&bundleProfile, req, copier.Option{DeepCopy: true}) res, err = dao.UpdateBundle(bundleProfile) return } func DeleteBundle(req *bundle.DelBundleRequest) (res *bundle.CommonResponse, err error) { res = new(bundle.CommonResponse) res, err = dao.DeleteBundle(req.Uuid) return } func BundleList(req *bundle.BundleListRequest) (res *bundle.BundleListResponse, err error) { res = new(bundle.BundleListResponse) res, err = dao.BundleList(req) return } func BundleDetail(req *bundle.BundleDetailRequest) (res *bundle.BundleDetailResponse, err error) { res = new(bundle.BundleDetailResponse) res.Bundle = new(bundle.BundleProfile) res.Bundle, err = dao.BundleDetail(req.Uuid) if err != nil { res.Msg = err.Error() } return } func SaveBundle(req *bundle.BundleProfile) (res *bundle.SaveResponse, err error) { res = &bundle.SaveResponse{} if req.Language == "" { return res, errors.New("语言参数不能为空") } if req.Sort <= 0 { return res, errors.New("排序参数需为正整数") } bundleProfile := &model.BundleProfile{ Name: req.Name, Sort: req.Sort, Content: req.Content, Price: req.Price, PriceType: req.PriceType, BgImg1: req.BgImg1, BgImg2: req.BgImg2, ShelfStatus: 2, //默认初始状态为2-下架 } bundleLang := &model.BundleProfileLang{ Name: req.Name, Content: req.Content, Price: req.Price, PriceType: req.PriceType, Language: req.Language, } if req.Uuid == "" && req.Language != msg.ZH_CN { return res, errors.New("请先创建中文版本套餐") } var existValueService = make(map[string]string) if req.Uuid != "" { valueService, existErr := dao.GetValueAddServiceUuidsByBundleUuid(req.Uuid) if existErr != nil { return res, existErr } if valueService != nil && len(valueService) > 0 { for _, v := range valueService { existValueService[v] = v } } } var cancelValueAddService = make(map[string]string) selectService := make([]*model.BundleToValueAddService, 0) if req.Language == msg.ZH_CN && req.SelectValueAddService != nil && len(req.SelectValueAddService) > 0 { for _, v := range req.SelectValueAddService { detail, checkErr := dao.ValueAddServiceDetailByUuidAndLanguage(v.ValueAddUuid, req.Language) if checkErr != nil { if checkErr == gorm.ErrRecordNotFound { return res, errors.New(fmt.Sprintf("所选增值服务[%s]%s版不存在,请先创建对应增值套餐", v.ServiceName, req.Language)) } else { return res, checkErr } } if detail.PriceType != req.PriceType { if req.Uuid == "" { //中文套餐创建时,币种不一致直接返回错误 return res, errors.New(fmt.Sprintf("所选增值服务[%s]%s币种与套餐币种不一致", detail.ServiceName, req.Language)) } else { //更新时,判断是否已存在,存在则取消关联 _, ok := existValueService[v.ValueAddUuid] if ok { cancelValueAddService[v.ValueAddUuid] = detail.ServiceName continue } else { //币种不一致,新加币种时返回错误 return res, errors.New(fmt.Sprintf("所选增值服务[%s]%s币种与套餐币种不一致", detail.ServiceName, req.Language)) } } } selectService = append(selectService, &model.BundleToValueAddService{ ValueUid: v.ValueAddUuid, IsDisplay: v.IsDisplay, }) } } tx := app.ModuleClients.BundleDB.Begin() defer func() { if err != nil { tx.Rollback() } else { tx.Commit() } }() _, err = dao.BundleDetailByUuidAndLanguage(req.Uuid, req.Language) if err != nil { if err == gorm.ErrRecordNotFound { if req.Language != msg.ZH_CN { _, err = dao.BundleDetailByUuidAndLanguage(req.Uuid, msg.ZH_CN) if err != nil { if err == gorm.ErrRecordNotFound { res.Msg = "请先创建中文版本套餐" return res, errors.New("请先创建中文版本套餐") } else { return res, err } } } if req.Language == msg.ZH_CN { bundleProfile.UUID = utils.GetUUID() if err = dao.TxCreateBundle(tx, bundleProfile); err != nil { return res, errors.New("保存中文语言套餐失败: " + err.Error()) } bundleLang.UUID = bundleProfile.UUID res.Uuid = bundleProfile.UUID // 新建套餐时插入中间表 for _, s := range selectService { s.BundleUuid = bundleProfile.UUID } if len(selectService) > 0 { if err = dao.CreateBundleToValueAddService(tx, selectService); err != nil { return res, errors.New("保存套餐与增值服务关联失败: " + err.Error()) } } } else { bundleLang.UUID = req.Uuid res.Uuid = req.Uuid valueUuid, err1 := dao.GetValueAddServiceUuidsByBundleUuid(bundleLang.UUID) if err1 != nil { return res, err1 } count := 0 if valueUuid != nil && len(valueUuid) > 0 { for _, v := range valueUuid { //可以改成批量获取 valueDetail, err2 := dao.ValueAddServiceDetailByUuidAndLanguage(v, req.Language) if err2 != nil { return res, err2 } if valueDetail.PriceType != req.PriceType { if err = tx.Where("bundle_uuid =? AND value_uid =?", bundleLang.UUID, v).Delete(&model.BundleToValueAddService{}).Error; err != nil { return res, errors.New("删除套餐与增值服务关联失败: " + err.Error()) } count++ } } } res.CancelNum = int64(count) } if err = dao.TxCreateBundleLang(tx, bundleLang); err != nil { return res, errors.New("保存语言套餐失败: " + err.Error()) } res.Msg = "保存成功" return res, nil } else { return } } else { // 已存在,进行更新 // 更新前保存历史记录 // if err = dao.CreateBundleProfileHistory(tx,req.Uuid); err != nil { // return res, errors.New("保存套餐历史记录失败: " + err.Error()) // } if req.Language == msg.ZH_CN { if len(cancelValueAddService) > 0 { cancel := "以下增值服务:" for _, v := range cancelValueAddService { cancel += fmt.Sprintf("[%s]%s", v, req.Language) if err = tx.Where("bundle_uuid = ? AND value_uid = ?", req.Uuid, v).Delete(&model.BundleToValueAddService{}).Error; err != nil { return res, errors.New("删除套餐与增值服务关联失败: " + err.Error()) } } cancel += "版币种与套餐币种不一致" res.Msg = "保存cn成功 " + cancel } res.CancelNum = int64(len(cancelValueAddService)) updateBundle := map[string]interface{}{ "name": req.Name, "sort": req.Sort, "content": req.Content, "price": req.Price, "price_type": req.PriceType, "bg_img1": req.BgImg1, "bg_img2": req.BgImg2, } if err = dao.TxUpdateBundle(tx, req.Uuid, updateBundle); err != nil { return res, err } // 更新中间表函数 if err = diffUpdateBundleToValueAddService(tx, req.Uuid, selectService); err != nil { tx.Rollback() return res, err } } else { //更新其他语言时 先获取所有关联增值服务,判断币种是否一致,不一致则取消关联 valueAddService, err := dao.GetBundleToValueAddServiceByBundleUuid(req.Uuid) if err != nil { return res, err } cancelValueService := make(map[string]string) for _, v := range valueAddService { detail, checkErr := dao.ValueAddServiceDetailByUuidAndLanguage(v.ValueUid, req.Language) if checkErr != nil { if checkErr == gorm.ErrRecordNotFound { continue } else { return res, checkErr } } if detail.PriceType != req.PriceType { cancelValueService[v.ValueUid] = detail.ServiceName continue } } if int64(len(cancelValueService)) > 0 { cancel := "以下增值服务:" for k, v := range cancelValueService { cancel += fmt.Sprintf("[%s]%s", v, req.Language) if err = tx.Where("bundle_uuid = ? AND value_uid = ?", req.Uuid, k).Delete(&model.BundleToValueAddService{}).Error; err != nil { return res, errors.New("删除套餐与增值服务关联失败: " + err.Error()) } } cancel += "版币种与套餐币种不一致,已取消相关关联" res.Msg = "保存成功 " + cancel res.CancelNum = int64(len(cancelValueService)) } } updateBundleLang := map[string]interface{}{ "name": req.Name, "content": req.Content, "price": req.Price, "price_type": req.PriceType, } if err = dao.TxUpdateBundleLang(tx, req.Uuid, req.Language, updateBundleLang); err != nil { return res, err } res.Uuid = req.Uuid if res.Msg == "" { res.Msg = "保存成功" } } return res, nil } func BundleListV2(req *bundle.BundleListRequest) (res *bundle.BundleListResponse, err error) { res = new(bundle.BundleListResponse) res, err = dao.BundleListV2(req) return } func BundleDetailV2(req *bundle.BundleDetailRequest) (res *bundle.BundleDetailResponseV2, err error) { res = new(bundle.BundleDetailResponseV2) if req.Uuid == "" { res.Msg = "" return res, errors.New("uuid不能为空") } if req.Language == "" { res.Msg = "" return res, errors.New("language不能为空") } res, err = dao.BundleDetailV2(req) if err != nil { res.Msg = err.Error() } return } func HandShelf(req *bundle.HandShelfRequest) (res *bundle.CommonResponse, err error) { res = new(bundle.CommonResponse) if req.ShelfStatus != 1 && req.ShelfStatus != 2 { res.Msg = "" return res, errors.New("无效的上下架状态") } res, err = dao.HandShelf(req.Uuid, req.ShelfStatus) return } // 差异更新套餐与增值服务中间表 func diffUpdateBundleToValueAddService(tx *gorm.DB, bundleUuid string, selectService []*model.BundleToValueAddService) error { oldUuids, err := dao.GetValueAddServiceUuidsByBundleUuid(bundleUuid) if err != nil { return errors.New("查询旧套餐与增值服务关联失败: " + err.Error()) } newUuids := make(map[string]*model.BundleToValueAddService) for _, s := range selectService { newUuids[s.ValueUid] = s } oldSet := make(map[string]struct{}) for _, uid := range oldUuids { oldSet[uid] = struct{}{} } // 需要新增的 toAdd := make([]*model.BundleToValueAddService, 0) for uid, s := range newUuids { if _, exist := oldSet[uid]; !exist { s.BundleUuid = bundleUuid toAdd = append(toAdd, s) } } // 需要删除的 toDel := make([]string, 0) for _, uid := range oldUuids { if _, exist := newUuids[uid]; !exist { toDel = append(toDel, uid) } } if len(toDel) > 0 { if err = tx.Where("bundle_uuid = ? AND value_uid IN ?", bundleUuid, toDel).Delete(&model.BundleToValueAddService{}).Error; err != nil { return errors.New("删除套餐与增值服务关联失败: " + err.Error()) } } if len(toAdd) > 0 { if err = dao.CreateBundleToValueAddService(tx, toAdd); err != nil { return errors.New("保存套餐与增值服务关联失败: " + err.Error()) } } return nil }