package dao import ( "errors" "fmt" "micro-bundle/internal/model" "micro-bundle/pb/bundle" "micro-bundle/pkg/app" "micro-bundle/pkg/utils" "strconv" "time" "dubbo.apache.org/dubbo-go/v3/common/logger" "github.com/duke-git/lancet/v2/datetime" "gorm.io/gorm" ) func AddBundleExtendRecord(data model.BundleExtensionRecords) error { return app.ModuleClients.BundleDB.Transaction(func(tx *gorm.DB) error { if err := tx.Create(&data).Error; err != nil { return err } if data.AvailableDurationAdditional != 0 && data.TimeUnit != 0 { record := model.BundleOrderRecords{} if err := tx.Model(&model.BundleOrderRecords{}).Where(&model.BundleOrderRecords{CustomerID: strconv.Itoa(data.UserId)}).Order("created_at desc").First(&record).Error; err != nil { return err } var expireTime time.Time if record.ExpirationTime != "" { loc, _ := time.LoadLocation("Asia/Shanghai") et, _ := time.ParseInLocation(time.DateTime, record.ExpirationTime, loc) expireTime = et } else { t, _ := time.Parse("2006-01-02 15:04:05", record.PayTime) expireTime = t logger.Infof("过期时间为空,使用默认过期时间" + expireTime.Format(time.DateTime)) } switch data.TimeUnit { case 1: expireTime = datetime.AddDay(expireTime, int64(data.AvailableDurationAdditional)) case 2: expireTime = datetime.AddMonth(expireTime, int64(data.AvailableDurationAdditional)) case 3: expireTime = datetime.AddYear(expireTime, int64(data.AvailableDurationAdditional)) default: return errors.New("时间单位有误") } record.ExpirationTime = expireTime.Format(time.DateTime) return tx.Model(&model.BundleOrderRecords{}).Where(&model.BundleOrderRecords{UUID: record.UUID}).Updates(&record).Error } return nil }) } func GetBundleExtendRecordList(req *bundle.BundleExtendRecordsListRequest) (data []model.BundleExtendRecordItemPo, total int64, err error) { session := app.ModuleClients.BundleDB.Table("fiee_bundle.bundle_extension_records AS ber"). Select(` ber.*, rn.name as user_name, u.tel_num as user_phone_number `).Joins("LEFT JOIN `micro-account`.`user` u on u.id = user_id"). Joins("LEFT JOIN `micro-account`.`real_name` rn on u.real_name_id = rn.id"). Order("created_at desc") if req.User != "" { if utils.IsPhoneNumber(req.User) { session = session.Where("u.tel_num = ?", req.User) } else { session = session.Where("rn.name like ?", "%"+req.User+"%") } } if req.Operator != "" { if utils.IsPhoneNumber(req.Operator) { session = session.Where("ber.operator_phone_number = ?", req.Operator) } else { session = session.Where("ber.operator_name like ?", "%"+req.Operator+"%") } } if req.Type != 0 { session = session.Where("ber.`type` = ?", req.Type) } if req.StartTime != 0 { session = session.Where("ber.created_at >= ?", time.UnixMilli(int64(req.StartTime))) } if req.EndTime != 0 { session = session.Where("ber.created_at <= ?", time.UnixMilli(int64(req.EndTime))) } if req.AssociatedOrderNumber != "" { session = session.Where("ber.associated_order_number like ?", "%"+req.AssociatedOrderNumber+"%") } if err = session.Count(&total).Error; err != nil { return } if req.Page != 0 && req.PageSize != 0 { session = session.Limit(int(req.PageSize)).Offset(int(req.Page-1) * int(req.PageSize)) } err = session.Find(&data).Error return } func GetBundleBalanceList(req *bundle.GetBundleBalanceListReq) (data []model.BundleBalancePo, total int64, err error) { subQuery := app.ModuleClients.BundleDB.Table("bundle_order_records as bor1"). Select("bor1.*"). Joins(`INNER JOIN ( SELECT customer_id, MAX(created_at) AS max_created_time FROM bundle_order_records GROUP BY customer_id ) bor2 ON bor1.customer_id = bor2.customer_id AND bor1.created_at = bor2.max_created_time`) session := app.ModuleClients.BundleDB.Table("`micro-account`.`user` AS u"). Select(`bb.*, bor.expiration_time as expired_time, bor.bundle_name, bor.status, bor.uuid as order_uuid, rn.name as user_name, u.tel_num as user_phone_number, u.id as user_id`). Joins("LEFT JOIN `micro-account`.real_name rn ON u.real_name_id = rn.id"). Joins("LEFT JOIN (?) as bor ON bor.customer_id = u.id", subQuery). Joins("LEFT JOIN fiee_bundle.bundle_balance bb ON u.id = bb.user_id AND bb.order_uuid = bor.uuid"). Where("rn.name IS NOT NULL"). Where("u.deleted_at = 0"). Order("bor.expiration_time desc") if req.UserName != "" { if utils.IsPhoneNumber(req.UserName) { session = session.Where("u.tel_num = ?", req.UserName) } else { session = session.Where("rn.name like ?", "%"+req.UserName+"%") } } if req.Status != 0 { session = session.Where("bor.status = ?", req.Status) } if req.BundleName != "" { session = session.Where("bor.bundle_name like ?", "%"+req.BundleName+"%") } if req.ExpiredTimeEnd != 0 { session = session.Where("bor.expiration_time <= ?", time.UnixMilli(req.ExpiredTimeEnd)) } if req.ExpiredTimeStart != 0 { session = session.Where("bor.expiration_time >= ?", time.UnixMilli(req.ExpiredTimeStart)) } if req.Bought == 2 { session = session.Where("bor.uuid IS NOT NULL") } if req.Bought == 1 { session = session.Where("bor.uuid IS NULL") } err = session.Count(&total).Error if err != nil { return } if req.Page != 0 && req.PageSize != 0 { session = session.Limit(int(req.PageSize)).Offset(int(req.Page-1) * int(req.PageSize)) } err = session.Find(&data).Error return } func GetBundleBalanceByUserId(req *bundle.GetBundleBalanceByUserIdReq) (data model.UserBundleBalancePo, err error) { err = app.ModuleClients.BundleDB.Table("fiee_bundle.bundle_balance AS bb"). Select("bb.*,bor.uuid AS order_uuid, bor.bundle_name AS bundle_name, bor.status AS bundle_status, bor.pay_time AS pay_time, bor.expiration_time AS expired_time,bor.amount AS payment_amount,bor.amount_type AS payment_type"). Joins("LEFT JOIN bundle_order_records bor ON bor.uuid = bb.order_uuid"). Joins("LEFT JOIN `micro-account`.`user` u ON u.id = bb.user_id"). Where("bor.deleted_at IS NULL"). Where("bb.user_id = ?", req.UserId). // Where("bor.expiration_time > ?", time.Now()). Order("bb.created_at desc"). First(&data).Error if err != nil { return } var additionalInfo model.UserBundleBalancePo err = app.ModuleClients.BundleDB.Model(&model.BundleExtensionRecords{}). Select("SUM(account_additional) as account_additional, SUM(images_additional) as image_additional, SUM(video_additional) as video_additional, SUM(data_additional) as data_additional"). Where("type = 1"). // 手动扩展 Where("user_id = ?", req.UserId). Where("created_at > ?", data.PayTime). // 判断扩展是否生效 First(&additionalInfo).Error if err != nil { return } data.AccountAdditional = additionalInfo.AccountAdditional data.VideoAdditional = additionalInfo.VideoAdditional data.ImageAdditional = additionalInfo.ImageAdditional data.DataAnalysisAdditional = additionalInfo.DataAnalysisAdditional return } func AddBundleBalanceByUserId(data model.BundleBalanceUsePo) error { return app.ModuleClients.BundleDB.Transaction(func(tx *gorm.DB) error { oldData := model.BundleBalance{} if err := tx.Model(&model.BundleBalance{}).Where("user_id = ?", data.UserId).Order("created_at desc").First(&oldData).Error; err != nil { return errors.New("用户还没有套餐信息") } if data.AccountNumber > 0 { // 增加账号消耗数 for range data.AccountNumber { if oldData.BundleAccountConsumptionNumber < oldData.BundleAccountNumber { // 消耗账号数优先套餐内 oldData.BundleAccountConsumptionNumber++ continue } if oldData.IncreaseAccountConsumptionNumber < oldData.IncreaseAccountNumber { // 其次消耗增值的 oldData.IncreaseAccountConsumptionNumber++ continue } return errors.New("账号数不足") } } else { // 减少账号消耗数,用于解绑账号 for range -data.AccountNumber { if oldData.IncreaseAccountConsumptionNumber > 0 { oldData.IncreaseAccountConsumptionNumber-- continue } if oldData.BundleAccountConsumptionNumber > 0 { oldData.BundleAccountConsumptionNumber-- continue } return errors.New("当前未绑定账号") } } for range data.VideoNumber { if oldData.MonthlyLimitVideoConsumptionNumber < oldData.MonthlyLimitVideoNumber { // 限制类型视频可用额度充足 if oldData.BundleLimitVideoExpiredConsumptionNumber < oldData.BundleLimitVideoExpiredNumber { // 套餐内会过期的限制类型视频充足 oldData.BundleLimitVideoExpiredConsumptionNumber++ oldData.MonthlyLimitVideoConsumptionNumber++ continue } if oldData.IncreaseLimitVideoExpiredConsumptionNumber < oldData.IncreaseLimitVideoExpiredNumber { // 增值服务会过期的限制类型视频充足 oldData.IncreaseLimitVideoExpiredConsumptionNumber++ oldData.MonthlyLimitVideoConsumptionNumber++ continue } if oldData.BundleLimitVideoConsumptionNumber < oldData.BundleLimitVideoNumber { // 套餐内不会过期的限制类型视频充足 oldData.BundleLimitVideoConsumptionNumber++ oldData.MonthlyLimitVideoConsumptionNumber++ continue } if oldData.IncreaseLimitVideoConsumptionNumber < oldData.IncreaseLimitVideoNumber { // 增值服务不会过期的限制类型视频充足 oldData.IncreaseLimitVideoConsumptionNumber++ oldData.MonthlyLimitVideoConsumptionNumber++ continue } } if oldData.BundleVideoConsumptionNumber < oldData.BundleVideoNumber { //套餐内非限制类型的视频充足 oldData.BundleVideoConsumptionNumber++ continue } if oldData.IncreaseVideoConsumptionNumber < oldData.IncreaseVideoNumber { //增值服务非限制类型的视频充足 oldData.IncreaseVideoConsumptionNumber++ continue } if oldData.ManualVideoConsumptionNumber < oldData.ManualDataAnalysisNumber { // 手动扩展类型充足 oldData.ManualVideoConsumptionNumber++ oldData.MonthlyManualVideoConsumptionNumber++ // 记录本月使用的手动扩展 continue } return errors.New("可用视频数不足") } for range data.ImageNumber { if oldData.MonthlyLimitImageConsumptionNumber < oldData.MonthlyLimitImageNumber { // 限制类型图文可用额度充足 if oldData.BundleLimitImageExpiredConsumptionNumber < oldData.BundleLimitImageExpiredNumber { // 套餐内会过期的限制类型图文充足 oldData.BundleLimitImageExpiredConsumptionNumber++ oldData.MonthlyLimitImageConsumptionNumber++ continue } if oldData.IncreaseLimitImageExpiredConsumptionNumber < oldData.IncreaseLimitImageExpiredNumber { // 增值服务会过期的限制类型图文充足 oldData.IncreaseLimitImageExpiredConsumptionNumber++ oldData.MonthlyLimitImageConsumptionNumber++ continue } if oldData.BundleLimitImageConsumptionNumber < oldData.BundleLimitImageNumber { // 套餐内不会过期的限制类型图文充足 oldData.BundleLimitImageConsumptionNumber++ oldData.MonthlyLimitImageConsumptionNumber++ continue } if oldData.IncreaseLimitImageConsumptionNumber < oldData.IncreaseLimitImageNumber { // 增值服务不会过期的限制类型图文充足 oldData.IncreaseLimitImageConsumptionNumber++ oldData.MonthlyLimitImageConsumptionNumber++ continue } } if oldData.BundleImageConsumptionNumber < oldData.BundleImageNumber { //套餐内非限制类型的图文充足 oldData.BundleImageConsumptionNumber++ continue } if oldData.IncreaseImageConsumptionNumber < oldData.IncreaseImageNumber { //增值服务非限制类型的图文充足 oldData.IncreaseImageConsumptionNumber++ continue } if oldData.ManualImageConsumptionNumber < oldData.ManualDataAnalysisNumber { // 手动扩展类型充足 oldData.ManualImageConsumptionNumber++ oldData.MonthlyManualImageConsumptionNumber++ // 记录本月使用的手动扩展 continue } return errors.New("可用图文数不足") } for range data.DataAnalysisNumber { if oldData.MonthlyLimitDataAnalysisConsumptionNumber < oldData.MonthlyLimitDataAnalysisNumber { // 限制类型数据分析可用额度充足 if oldData.BundleLimitDataAnalysisExpiredConsumptionNumber < oldData.BundleLimitDataAnalysisExpiredNumber { // 套餐内会过期的限制类型数据分析充足 oldData.BundleLimitDataAnalysisExpiredConsumptionNumber++ oldData.MonthlyLimitDataAnalysisConsumptionNumber++ continue } if oldData.IncreaseLimitDataAnalysisExpiredConsumptionNumber < oldData.IncreaseLimitDataAnalysisExpiredNumber { // 增值服务会过期的限制类型数据分析充足 oldData.IncreaseLimitDataAnalysisExpiredConsumptionNumber++ oldData.MonthlyLimitDataAnalysisConsumptionNumber++ continue } if oldData.BundleLimitDataAnalysisConsumptionNumber < oldData.BundleLimitDataAnalysisNumber { // 套餐内不会过期的限制类型数据分析充足 oldData.BundleLimitDataAnalysisConsumptionNumber++ oldData.MonthlyLimitDataAnalysisConsumptionNumber++ continue } if oldData.IncreaseLimitDataAnalysisConsumptionNumber < oldData.IncreaseLimitDataAnalysisNumber { // 增值服务不会过期的限制类型数据分析充足 oldData.IncreaseLimitDataAnalysisConsumptionNumber++ oldData.MonthlyLimitDataAnalysisConsumptionNumber++ continue } } if oldData.BundleLimitDataAnalysisNumber < oldData.BundleDataAnalysisNumber { //套餐内非限制类型的数据分析充足 oldData.BundleLimitDataAnalysisNumber++ continue } if oldData.IncreaseDataAnalysisConsumptionNumber < oldData.IncreaseDataAnalysisNumber { //增值服务非限制类型的数据分析充足 oldData.IncreaseDataAnalysisConsumptionNumber++ continue } if oldData.ManualDataAnalysisConsumptionNumber < oldData.ManualDataAnalysisNumber { // 手动扩展类型充足 oldData.ManualDataAnalysisConsumptionNumber++ oldData.MonthlyManualDataAnalysisConsumptionNumber++ // 记录本月使用的手动扩展 continue } return errors.New("可用数据分析数不足") } return tx.Model(&model.BundleBalance{}).Where("id = ?", oldData.ID).Save(&oldData).Error }) } func CreateUsedRecord(tx *gorm.DB, data model.BundleUsedRecord) error { return tx.Create(&data).Error } func ExtendBundleBalanceByUserId(data model.BundleBalanceExtendPo) error { return app.ModuleClients.BundleDB.Transaction(func(tx *gorm.DB) error { oldData := model.BundleBalance{} if err := tx.Model(&model.BundleBalance{}).Where("user_id = ?", data.UserId).Order("created_at desc").First(&oldData).Error; err != nil { return errors.New("用户还没有套餐信息") } oldData.ManualImageNumber += data.ImageNumber oldData.ManualDataAnalysisNumber += data.DataAnalysisNumber oldData.ManualVideoNumber += data.VideoNumber oldData.MonthlyNewDurationNumber += data.DurationNumber // 记录本月新增手动扩展时长 oldData.ExpiredAt.Add(time.Hour * 24 * time.Duration(data.DurationNumber)) return tx.Model(&model.BundleBalance{}).Where("id = ?", oldData.ID).Save(&oldData).Error }) } func CreateBundleBalance(data model.BundleBalance) error { return app.ModuleClients.BundleDB.Create(&data).Error } func GetUsedRecord(req *bundle.GetUsedRecordListReq) (data []model.CostLogPo, total int64, err error) { session := app.ModuleClients.BundleDB.Table("cast_cost_log as ccl").Select("ccl.*,cwe.artist_confirmed_time"). Joins("left join cast_work_extra as cwe on cwe.work_uuid = ccl.work_uuid"). Where("ccl.deleted_at = 0") if req.Title != "" { session = session.Where("title = ?", req.Title) } if req.Platform != 0 { session = session.Where(fmt.Sprintf("JSON_CONTAINS(platform_ids,'%d')", req.Platform)) } if req.Account != "" { session = session.Where(fmt.Sprintf(`JSON_CONTAINS(media_names,'"%s"')`, req.Account)) } if req.SubmitTimeEnd != 0 { session = session.Where("artist_confirmed_time <= ?", req.SubmitTimeEnd/1000) // 转换为秒级时间戳 } if req.SubmitTimeStart != 0 { session = session.Where("artist_confirmed_time >= ?", req.SubmitTimeStart/1000) } if req.User != "" { if utils.IsPhoneNumber(req.User) { session = session.Where("artist_phone = ?", req.User) } else { session = session.Where("artist_name like ?", "%"+req.User+"%") } } if req.Operator != "" { if utils.IsPhoneNumber(req.Operator) { session = session.Where("operator_phone = ?", req.Operator) } else { session = session.Where("operator_name like ?", "%"+req.Operator+"%") } } if req.Type != 0 { session = session.Where("work_category = ?", req.Type) } if err = session.Count(&total).Error; err != nil { return } if req.Page != 0 && req.PageSize != 0 { session = session.Offset(int(req.Page-1) * int(req.PageSize)).Limit(int(req.PageSize)) } err = session.Order("ccl.updated_at desc").Find(&data).Error return } func GetImageWorkDetail(req *bundle.GetImageWorkDetailReq) (data model.CastWorkImage, err error) { err = app.ModuleClients.BundleDB.Where(&model.CastWorkImage{WorkUuid: req.WorkId}).First(&data).Error return } func GetVedioWorkDetail(req *bundle.GetVedioWorkDetailReq) (data model.CastWorkVideo, err error) { err = app.ModuleClients.BundleDB.Where(&model.CastWorkVideo{WorkUuid: req.WorkId}).First(&data).Error return } func ToBeComfirmedWorks(req *bundle.ToBeComfirmedWorksReq) (data []model.CastWorkLog, total int64, unconfirmed int64, err error) { unConfirmSubQuery := app.ModuleClients.BundleDB. Table("cast_work_log"). Select("work_uuid, MAX(update_time) AS max_update_time"). Group("work_uuid").Where("work_status = ?", 4) err = app.ModuleClients.BundleDB. Table("cast_work_log AS cwl"). Joins("INNER JOIN (?) AS t ON cwl.work_uuid = t.work_uuid AND cwl.update_time = t.max_update_time", unConfirmSubQuery). Where("artist_uuid = ?", req.ArtistUuid).Where("confirmed_at = ?", 0).Count(&unconfirmed).Error if err != nil { return } subQuery := app.ModuleClients.BundleDB. Table("cast_work_log"). Select("work_uuid, MAX(update_time) AS max_update_time"). Group("work_uuid").Where("work_status in ?", []int{4, 5, 6, 7}) session := app.ModuleClients.BundleDB. Table("cast_work_log AS cwl"). Joins("INNER JOIN (?) AS t ON cwl.work_uuid = t.work_uuid AND cwl.update_time = t.max_update_time", subQuery). Where("artist_uuid = ?", req.ArtistUuid) err = session.Count(&total).Error if err != nil { return } if req.Page != 0 && req.PageSize != 0 { session.Limit(int(req.PageSize)).Offset(int(req.Page-1) * int(req.PageSize)) } err = session.Order("created_at desc").Find(&data).Error return } func ConfirmWork(req *bundle.ConfirmWorkReq) error { return app.ModuleClients.BundleDB.Model(&model.CastWorkLog{}).Where(&model.CastWorkLog{WorkUuid: req.WorkUuid}).Update("confirmed_at", time.Now().Unix()).Error } func BundleActivate(ids []uint32) error { for _, v := range ids { app.ModuleClients.BundleDB.Transaction(func(tx *gorm.DB) error { activate := model.BundleActivate{} if err := tx.Model(&model.BundleActivate{}).Where("user_id = ?", v).First(&activate).Error; err != nil { return err } if !activate.Activate { // 第一次激活重新计算余量的开始时间和过期时间 balance := model.BundleBalance{} if err := tx.Model(&model.BundleBalance{}).Where("user_id = ?", v).First(&balance).Error; err != nil { return err } balance.ExpiredAt = balance.ExpiredAt.Add(time.Since(balance.StartAt)) balance.StartAt = time.Now() if err := tx.Model(&model.BundleBalance{}).Save(balance).Error; err != nil { return err } activate.Activate = true return tx.Model(&model.BundleActivate{}).Save(activate).Error } return nil }) } return nil } func GetValueAddByOrderUUID(orderUUID string) (data []model.BundleOrderValueAdd, err error) { err = app.ModuleClients.BundleDB.Model(&model.BundleOrderValueAdd{}).Where("order_uuid = ?", orderUUID).Find(&data).Error return } func UpdateBundleBalance() error { bl := []model.BundleBalance{} if err := app.ModuleClients.BundleDB.Raw(`select * from bundle_balance bb inner join ( select max(bb.month) as month , user_id from bundle_balance bb group by bb.user_id ) newest on newest.month = bb.month and bb.user_id = newest.user_id`).Find(&bl).Error; err != nil { return err } month := time.Now().Format("2006-01") for _, v := range bl { v.MonthlyLimitVideoConsumptionNumber = 0 v.MonthlyLimitImageConsumptionNumber = 0 v.MonthlyLimitDataAnalysisConsumptionNumber = 0 // v.MonthlyInvalidBundleVideoNumber } }