717 lines
17 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.GetCouponPreloadById(couponId)
if err != nil || coupon == nil {
return nil, errors.New(err.Error())
}
// 处理返回值
g = dto.GetCouponDto(coupon)
// 加载发放优惠卷数据
if len(coupon.CouponGrant) > 0 {
g = g.LoadCouponGrant(coupon.CouponGrant)
}
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.CouponType == 3 {
if *req.MinUsableNumber == 0 {
return false, errors.New("请填入单商品最小可使用数量")
}
}
}
// 适用范围-问诊
if *req.ApplicationScope == 2 {
// 关联问诊类型
if req.InquiryType == nil {
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 {
t, err := time.Parse("2006-01-02 15:04:05", *req.ValidStartTime)
if err != nil {
tx.Rollback()
return false, errors.New("新增失败")
}
validStartTime := model.LocalTime(t)
coupon.ValidStartTime = &validStartTime
}
if req.ValidEndTime != nil {
t, err := time.Parse("2006-01-02 15:04:05", *req.ValidEndTime)
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 req.InquiryType != nil {
coupon.InquiryType = *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())
}
// 增加优惠卷过期队列
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 req.InquiryType != nil {
if *req.InquiryType != coupon.InquiryType {
couponData["inquiry_type"] = req.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.InquiryType
}
}
// 是否互斥
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.InquiryType
}
}
}
// 单商品最小可使用数量
if coupon.ApplicationScope == 1 && coupon.CouponType == 3 {
if req.MinUsableNumber != nil {
couponData["min_usable_number"] = req.InquiryType
}
}
// 发放数量
if req.CouponCount != nil {
if *req.CouponCount != coupon.CouponCount {
if *req.CouponCount <= coupon.CouponTakeCount {
tx.Rollback()
return false, errors.New("发放数量,不可低于已发放数量")
}
couponData["coupon_count"] = req.InquiryType
}
}
// 优惠卷金额
if req.CouponPrice != nil {
if *req.CouponPrice != coupon.CouponPrice {
couponData["coupon_price"] = req.InquiryType
}
}
// 关联商品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("优惠卷非正常状态,不支持发放")
}
// 检测订单过期时间
now := time.Now()
validEndTime := time.Time(*coupon.ValidEndTime)
if now.After(validEndTime) {
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 = now.Add(time.Minute * 10)
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.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()
}
}()
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("发放失败")
}
// 增加优惠卷发放数量
err = couponDao.Inc(tx, couponId, "coupon_take_count", 1)
if err != 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
}