package service import ( "encoding/json" "errors" "fmt" "hospital-admin-api/api/dao" "hospital-admin-api/api/dto" "hospital-admin-api/api/model" "hospital-admin-api/api/requests" "hospital-admin-api/extend/rabbitMq" "hospital-admin-api/global" "hospital-admin-api/utils" "strconv" "strings" "time" ) type CouponService struct { } // GetSystemCoupon 系统优惠卷详情 func (r *CouponService) GetSystemCoupon(couponId int64) (g *dto.CouponDto, err error) { couponDao := dao.CouponDao{} coupon, err := couponDao.GetCouponById(couponId) if err != nil || coupon == nil { return nil, errors.New(err.Error()) } // 获取优惠卷发放数据 couponGrantDao := dao.CouponGrantDao{} couponGrants, err := couponGrantDao.GetCouponGrantListPreloadByCouponId(coupon.CouponId) // 处理返回值 g = dto.GetCouponDto(coupon) // 加载发放优惠卷数据 if len(couponGrants) > 0 { g = g.LoadCouponGrant(couponGrants) } // 加载关联问诊类型 if coupon.InquiryType != "" { g.LoadInquiryType(coupon.InquiryType) } return g, nil } // AddSystemCoupon 新增系统优惠卷 func (r *CouponService) AddSystemCoupon(req requests.AddSystemCoupon) (bool, error) { // 满减 if *req.CouponType == 2 { if *req.WithAmount == 0 { return false, errors.New("请填入符合满减标准金额") } } // 数量 if *req.CouponType == 3 { if *req.MinUsableNumber == 0 { return false, errors.New("请填入单商品最小可使用数量") } } // 发放对象-近期消费 if *req.DistributionObject == 4 { if *req.DistributionWithDay == 0 { return false, errors.New("请填入发放关联天数") } } // 适用范围-全场通用 if *req.ApplicationScope == 1 { // 满减 if *req.CouponType == 2 { if *req.WithAmount == 0 { return false, errors.New("请填入符合满减标准金额") } if *req.WithAmount > *req.CouponPrice { return false, errors.New("满减标准金额不可超过优惠卷金额") } } // 数量 if *req.CouponType == 3 { if *req.MinUsableNumber == 0 { return false, errors.New("请填入单商品最小可使用数量") } } } // 适用范围-问诊 if *req.ApplicationScope == 2 { // 关联问诊类型 if len(req.InquiryType) == 0 { return false, errors.New("请填入关联问诊类型") } } // 适用范围-按品牌适用 if *req.ApplicationScope == 3 { // 关联品牌id if req.BrandId == nil { return false, errors.New("请填入关联品牌") } } // 适用范围-单品使用 if *req.ApplicationScope == 5 { // 关联商品id if len(req.ProductId) == 0 { return false, errors.New("请填入关联商品") } productDao := dao.ProductDao{} for _, s := range req.ProductId { // 将 id 转换为 int64 类型 productId, err := strconv.ParseInt(s, 10, 64) if err != nil { return false, errors.New("新增失败") } _, err = productDao.GetProductById(productId) if err != nil { return false, errors.New("存在错误商品") } } } // 有效类型-绝对时效 if *req.ValidType == 1 { if req.ValidStartTime == nil { return false, errors.New("请填入开始使用时间") } if req.ValidEndTime == nil { return false, errors.New("请填入结束使用时间") } } // 有效类型-相对时效 if *req.ValidType == 2 { if req.ValidDays == nil { return false, errors.New("请填入有效天数") } } // 开始事务 tx := global.Db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() fmt.Println(r) } }() // 新增优惠卷表 coupon := &model.Coupon{ CouponName: req.CouponName, CouponIcon: utils.AddOssDomain(req.CouponIcon), CouponClient: *req.CouponClient, CouponType: *req.CouponType, CouponStatus: *req.CouponClient, DistributionObject: *req.DistributionObject, ApplicationScope: *req.ApplicationScope, IsMutex: req.IsMutex, IsDisplay: *req.IsDisplay, CouponCount: *req.CouponCount, CouponPrice: *req.CouponPrice, ValidType: *req.ValidType, IsPopup: *req.IsPopup, } // 关联品牌id if req.BrandId != nil { // 将 id 转换为 int64 类型 brandId, err := strconv.ParseInt(*req.BrandId, 10, 64) if err != nil { tx.Rollback() return false, errors.New("新增失败") } coupon.BrandId = &brandId } // 时间区间 if req.ValidStartTime != nil { // 获取本地时区 location, err := time.LoadLocation("Local") if err != nil { tx.Rollback() return false, errors.New("新增失败") } t, err := time.ParseInLocation("2006-01-02 15:04:05", *req.ValidStartTime, location) if err != nil { tx.Rollback() return false, errors.New("新增失败") } validStartTime := model.LocalTime(t) coupon.ValidStartTime = &validStartTime } if req.ValidEndTime != nil { // 获取本地时区 location, err := time.LoadLocation("Local") if err != nil { tx.Rollback() return false, errors.New("新增失败") } t, err := time.ParseInLocation("2006-01-02 15:04:05", *req.ValidEndTime, location) if err != nil { tx.Rollback() return false, errors.New("新增失败") } ValidEndTime := model.LocalTime(t) coupon.ValidEndTime = &ValidEndTime } // 关联商品id if req.ProductId != nil { productId := strings.Join(req.ProductId, ",") if productId != "" { coupon.ProductId = productId } } // 关联问诊类型 if len(req.InquiryType) > 0 { coupon.InquiryType = strings.Join(req.InquiryType, ",") } // 发放关联天数 if req.DistributionWithDay != nil { coupon.DistributionWithDay = *req.DistributionWithDay } // 发放关联天数 if req.DistributionWithDay != nil { coupon.DistributionWithDay = *req.DistributionWithDay } // 单商品最小可使用数量 if req.MinUsableNumber != nil { coupon.MinUsableNumber = req.MinUsableNumber } // 符合满减标准金额 if req.WithAmount != nil { coupon.WithAmount = *req.WithAmount } // 有效天数 if req.ValidDays != nil { coupon.ValidDays = *req.ValidDays } // 再次发放间隔天数 if req.ReissueIntervalDays != nil { coupon.ReissueIntervalDays = *req.ReissueIntervalDays } // 允许再次发放 if req.IsReissuableAfterExpire != nil { coupon.IsReissuableAfterExpire = *req.IsReissuableAfterExpire } // 优惠卷描述 if req.CouponDesc != nil { coupon.CouponDesc = *req.CouponDesc } couponDao := dao.CouponDao{} coupon, err := couponDao.AddCoupon(tx, coupon) if err != nil || coupon == nil { tx.Rollback() return false, errors.New(err.Error()) } // 增加优惠卷过期队列 if coupon.ValidType == 1 { validEndTime := time.Time(*coupon.ValidEndTime) // 计算当天的结束时间 now := time.Now() year, month, day := now.Date() location := now.Location() endOfDay := time.Date(year, month, day, 23, 59, 59, 0, location) if validEndTime.Before(endOfDay) { // 需添加队列 // 建立队列连接 rabbitMQ, err := rabbitMq.NewRabbitMQClient() if err != nil { tx.Rollback() return false, errors.New("发放失败") } defer rabbitMQ.Close() data := make(map[string]interface{}) data["coupon_id"] = fmt.Sprintf("%d", coupon.CouponId) delay := validEndTime.Sub(now) if delay < 10 { delay = 10 * time.Second } err = rabbitMQ.PublishWithDelay("coupon.expired.delay.queue", "amqp.delay.direct", "CouponExpired", data, delay) if err != nil { tx.Rollback() return false, err } } } tx.Commit() return true, nil } // PutSystemCoupon 修改系统优惠卷 func (r *CouponService) PutSystemCoupon(couponId int64, req requests.PutSystemCoupon) (bool, error) { couponDao := dao.CouponDao{} coupon, err := couponDao.GetCouponById(couponId) if err != nil { return false, err } if coupon.CouponStatus != 1 { return false, errors.New("优惠卷非正常状态,不支持更改") } // 开始事务 tx := global.Db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() couponData := make(map[string]interface{}) // 优惠卷名称 if req.CouponName != coupon.CouponName { couponData["coupon_name"] = req.CouponName } // 头像 if req.CouponIcon != "" { if req.CouponIcon != coupon.CouponIcon { couponData["coupon_icon"] = req.CouponIcon } } // 发放对象 if req.DistributionObject != nil { if *req.DistributionObject != coupon.DistributionObject { couponData["distribution_object"] = req.DistributionObject } } // 关联问诊类型 if coupon.ApplicationScope == 2 { if len(req.InquiryType) > 0 { inquiryType := strings.Join(req.InquiryType, ",") if inquiryType != coupon.InquiryType { couponData["inquiry_type"] = inquiryType } } } // 关联品牌id if coupon.ApplicationScope == 3 { // 将 id 转换为 int64 类型 brandId, err := strconv.ParseInt(*req.BrandId, 10, 64) if err != nil { tx.Rollback() return false, errors.New("修改失败") } if &brandId != coupon.BrandId { couponData["brand_id"] = req.BrandId } } // 是否互斥 if req.IsMutex != nil { if req.IsMutex != coupon.IsMutex { couponData["is_mutex"] = req.IsMutex } } // 是否展示 if req.IsDisplay != nil { if *req.IsDisplay != coupon.IsDisplay { couponData["is_display"] = req.IsDisplay } } // 发放关联天数 if coupon.DistributionObject == 4 { if req.DistributionWithDay != nil { if *req.DistributionWithDay != coupon.DistributionWithDay { couponData["distribution_with_day"] = req.DistributionWithDay } } } // 单商品最小可使用数量 if coupon.ApplicationScope == 1 && coupon.CouponType == 3 { if req.MinUsableNumber != nil { couponData["min_usable_number"] = req.MinUsableNumber } } // 发放数量 if req.CouponCount != nil { if *req.CouponCount != coupon.CouponCount { if *req.CouponCount <= coupon.CouponTakeCount { tx.Rollback() return false, errors.New("发放数量,不可低于已发放数量") } couponData["coupon_count"] = req.CouponCount } } // 优惠卷金额 if req.CouponPrice != nil { if *req.CouponPrice != coupon.CouponPrice { couponData["coupon_price"] = req.CouponPrice } } // 关联商品id if len(req.ProductId) > 0 { productId := strings.Join(req.ProductId, ",") if productId != coupon.ProductId { productDao := dao.ProductDao{} for _, s := range req.ProductId { // 将 id 转换为 int64 类型 productId, err := strconv.ParseInt(s, 10, 64) if err != nil { tx.Rollback() return false, errors.New("修改失败") } _, err = productDao.GetProductById(productId) if err != nil { tx.Rollback() return false, errors.New("存在错误商品") } } couponData["product_id"] = productId } } // 确认收货后的再次发放间隔天数 if req.ReissueIntervalDays != nil { if *req.ReissueIntervalDays != coupon.ReissueIntervalDays { couponData["reissue_interval_days"] = req.ReissueIntervalDays } } // 过期之后是否允许再次发放 if req.IsReissuableAfterExpire != nil { if *req.IsReissuableAfterExpire != coupon.IsReissuableAfterExpire { couponData["is_reissuable_after_expire"] = req.IsReissuableAfterExpire } } // 是否首页弹窗 if *req.IsPopup != coupon.IsPopup { couponData["is_popup"] = req.IsPopup } // 优惠卷描述 if req.CouponDesc != nil { if *req.CouponDesc != coupon.CouponDesc { couponData["coupon_desc"] = req.CouponDesc } } err = couponDao.EditCouponById(tx, coupon.CouponId, couponData) if err != nil || coupon == nil { tx.Rollback() return false, errors.New(err.Error()) } // 新增队列 tx.Commit() return true, nil } // PutSystemCouponStatus 修改系统优惠卷状态 func (r *CouponService) PutSystemCouponStatus(couponId int64, req requests.PutSystemCouponStatus) (bool, error) { couponDao := dao.CouponDao{} coupon, err := couponDao.GetCouponById(couponId) if err != nil { return false, err } // 状态未变 if coupon.CouponStatus == req.CouponStatus { return true, nil } if coupon.CouponStatus == 2 { return false, errors.New("优惠卷已强制失效,无法再次操作") } if coupon.CouponStatus == 3 { return false, errors.New("优惠卷已结束,无法再次操作") } if coupon.CouponStatus == 4 { return false, errors.New("优惠卷已删除,无法再次操作") } // 开始事务 tx := global.Db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() couponData := make(map[string]interface{}) couponData["coupon_status"] = req.CouponStatus err = couponDao.EditCouponById(tx, coupon.CouponId, couponData) if err != nil || coupon == nil { tx.Rollback() return false, errors.New(err.Error()) } tx.Commit() return true, nil } // GrantSystemCoupon 发放系统优惠卷 func (r *CouponService) GrantSystemCoupon(couponId, adminUserId int64, req requests.GrantSystemCoupon) (bool, error) { if req.Type == 2 { return false, errors.New("暂时只支持具体用户发放") } couponDao := dao.CouponDao{} coupon, err := couponDao.GetCouponById(couponId) if err != nil { return false, err } if coupon.CouponStatus != 1 { return false, errors.New("优惠卷非正常状态,不支持发放") } // 检测优惠卷剩余数量 remainingQuantity := coupon.CouponCount - coupon.CouponTakeCount if remainingQuantity <= 0 { return false, errors.New("优惠卷数量不足,无法发放") } // 检测优惠卷可发放数量 if req.TotalQuantity > remainingQuantity { return false, errors.New("优惠卷数量不足,无法发放") } // 检测优惠卷过期时间 now := time.Now() if coupon.ValidType == 1 { // 1:绝对时效 validStartTime := time.Time(*coupon.ValidStartTime) if now.Before(validStartTime) { return false, errors.New("优惠卷还未启用") } validEndTime := time.Time(*coupon.ValidEndTime) if now.Add(time.Minute * 10).After(validEndTime) { return false, errors.New("优惠卷即将过期,不支持发放") } } // 获取优惠卷发放记录表 couponGrantDao := dao.CouponGrantDao{} maps := make(map[string]interface{}) maps["coupon_id"] = coupon.CouponId maps["grant_result"] = 2 couponGrants, _ := couponGrantDao.GetCouponGrantList(maps) if len(couponGrants) > 0 { return false, errors.New("请等待上次发放结束后再执行此操作") } // 将 id 转换为 int64 类型 userId, err := strconv.ParseInt(req.UserId, 10, 64) if err != nil { return false, errors.New("发放失败") } userDao := dao.UserDao{} user, _ := userDao.GetUserById(userId) if user == nil { return false, errors.New("用户错误") } // 获取患者数据 userPatientDao := dao.UserPatientDao{} userPatient, _ := userPatientDao.GetUserPatientByUserId(userId) if userPatient == nil { return false, errors.New("用户错误") } // 检测用户是否已领取该优惠卷 userCouponDao := dao.UserCouponDao{} //// 废弃,不进行检测是否已发放 //maps = make(map[string]interface{}) //maps["user_id"] = user.UserId //maps["coupon_id"] = coupon.CouponId //maps["user_coupon_status"] = 0 //userCoupons, _ := userCouponDao.GetUserCouponList(maps) //if len(userCoupons) >= req.SingleQuantity { // return false, errors.New("用户已有该优惠卷") //} // 开始事务 tx := global.Db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } }() // 增加优惠卷发放数量 err = couponDao.Inc(tx, couponId, "coupon_take_count", req.SingleQuantity) if err != nil { tx.Rollback() return false, errors.New("发放失败") } // 检测优惠卷是否全部发放完毕 if (req.TotalQuantity - remainingQuantity) == 0 { maps := make(map[string]interface{}) maps["coupon_status"] = 3 err := couponDao.EditCouponById(tx, coupon.CouponId, maps) if err != nil { tx.Rollback() return false, errors.New("发放失败") } } // 发放优惠卷 for i := 0; i < req.SingleQuantity; i++ { // 添加用户优惠卷表 UserCouponModel := &model.UserCoupon{ UserId: user.UserId, PatientId: userPatient.PatientId, CouponId: couponId, CouponUseDate: nil, } // 有效类型(1:绝对时效,xxx-xxx时间段有效 2:相对时效 n天内有效) if coupon.ValidType == 1 { UserCouponModel.ValidStartTime = time.Time(*coupon.ValidStartTime) UserCouponModel.ValidEndTime = time.Time(*coupon.ValidEndTime) } if coupon.ValidType == 2 { UserCouponModel.ValidStartTime = now UserCouponModel.ValidEndTime = now.AddDate(0, 0, coupon.ValidDays) } userCoupon, _ := userCouponDao.AddUserCoupon(tx, UserCouponModel) if userCoupon == nil { tx.Rollback() return false, errors.New("发放失败") } // 添加弹窗表 if coupon.IsPopup == 1 { popupModel := &model.Popup{ UserId: user.UserId, AppType: 1, ClientType: 1, PopupType: 2, PopupTitle: "红包福利", PopupContent: "", } popupContent := make(map[string]interface{}) popupContent["user_coupon_id"] = fmt.Sprintf("%d", userCoupon.UserCouponId) popupContent["coupon_price"] = coupon.CouponPrice popupContent["application_scope"] = coupon.ApplicationScope popupContent["inquiry_type"] = coupon.InquiryType popupContent["valid_type"] = coupon.ValidType popupContent["valid_days"] = coupon.ValidDays popupContent["valid_start_time"] = coupon.ValidStartTime popupContent["valid_end_time"] = coupon.ValidEndTime popupContentData, err := json.Marshal(popupContent) if err != nil { tx.Rollback() return false, errors.New("发放失败") } popupModel.PopupContent = string(popupContentData) popupDao := dao.PopupDao{} popup, _ := popupDao.AddPopup(tx, popupModel) if popup == nil { tx.Rollback() return false, errors.New("发放失败") } } // 增加优惠卷过期队列 // 计算当天的结束时间 year, month, day := now.Date() location := now.Location() endOfDay := time.Date(year, month, day, 23, 59, 59, 0, location) if userCoupon.ValidEndTime.Before(endOfDay) { // 需添加队列 // 建立队列连接 rabbitMQ, err := rabbitMq.NewRabbitMQClient() if err != nil { tx.Rollback() return false, errors.New("发放失败") } defer rabbitMQ.Close() data := make(map[string]interface{}) data["user_coupon_id"] = fmt.Sprintf("%d", userCoupon.UserCouponId) delay := userCoupon.ValidEndTime.Sub(time.Now()) if delay < 10 { delay = 10 * time.Second } err = rabbitMQ.PublishWithDelay("user.coupon.expired.delay.queue", "amqp.delay.direct", "UserCouponExpired", data, delay) if err != nil { tx.Rollback() return false, err } } go func() { // 发送通知 res, _ := PatientDistributeCoupon(coupon.CouponName, user.UserId) if !res { utils.LogJsonErr("CouponService-GrantSystemCoupon", "优惠卷通知发送失败") } }() } // 添加优惠卷发放记录表 couponGrantModel := &model.CouponGrant{ CouponId: coupon.CouponId, GrantType: req.Type, UserId: userId, TotalQuantity: req.TotalQuantity, GrantQuantity: req.SingleQuantity, GrantResult: 1, StopReason: "", AdminUserId: adminUserId, } _, err = couponGrantDao.AddCouponGrant(tx, couponGrantModel) if err != nil { tx.Rollback() return false, err } tx.Commit() return true, nil }