package market import ( "errors" "fmt" "github.com/gin-gonic/gin" model "go-admin/app/admin/models" orm "go-admin/common/global" "go-admin/logger" "go-admin/tools" "go-admin/tools/app" "net/http" "time" ) // ErpMarketingCouponList 优惠券列表 // @Summary 优惠券列表 // @Tags 营销管理,V1.4.4 // @Produce json // @Accept json // @Param request body models.ErpMarketingCouponListReq true "优惠券列表模型" // @Success 200 {object} models.ErpMarketingCouponListResp // @Router /api/v1/marketing/coupon/list [post] func ErpMarketingCouponList(c *gin.Context) { req := &model.ErpMarketingCouponListReq{} if err := c.ShouldBindJSON(&req); err != nil { logger.Error("ShouldBindJSON err:", logger.Field("err", err)) app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") return } resp, err := req.List() if err != nil { logger.Error("ErpMarketingCouponList err:", logger.Field("err", err)) app.Error(c, http.StatusInternalServerError, err, "获取失败"+err.Error()) return } app.OK(c, resp, "OK") return } // ErpMarketingCouponCreate 新增优惠券 // @Summary 新增优惠券 // @Tags 营销管理,V1.4.4 // @Produce json // @Accept json // @Param request body models.ErpMarketingCouponCreateReq true "新增优惠券模型" // @Success 200 {object} app.Response // @Router /api/v1/marketing/coupon/create [post] func ErpMarketingCouponCreate(c *gin.Context) { var req = new(model.ErpMarketingCouponCreateReq) if err := c.ShouldBindJSON(&req); err != nil { logger.Error("ShouldBindJSON err:", logger.Field("err", err)) app.Error(c, http.StatusBadRequest, err, "参数错误:"+err.Error()) return } err := tools.Validate(req) //必填参数校验 if err != nil { app.Error(c, http.StatusBadRequest, err, err.Error()) return } if !model.IsExistingCategoryByNumber(req.CategoryNumber) { app.Error(c, http.StatusBadRequest, errors.New("未查询到该分类编号"), "未查询到该分类编号") return } err = model.CreateErpMarketingCoupon(req) if err != nil { logger.Error("CreateErpMarketingCoupon err:", logger.Field("err", err)) app.Error(c, http.StatusInternalServerError, err, err.Error()) return } app.OK(c, nil, "新增成功") return } // ErpMarketingCouponEdit 编辑优惠券 // @Summary 编辑优惠券 // @Tags 营销管理,V1.4.4 // @Produce json // @Accept json // @Param request body models.ErpMarketingCouponEditReq true "编辑优惠券模型" // @Success 200 {object} app.Response // @Router /api/v1/marketing/coupon/edit [post] func ErpMarketingCouponEdit(c *gin.Context) { var req = new(model.ErpMarketingCouponEditReq) if err := c.ShouldBindJSON(&req); err != nil { logger.Error("ShouldBindJSON err:", logger.Field("err", err)) app.Error(c, http.StatusBadRequest, err, "参数错误:"+err.Error()) return } err := tools.Validate(req) //必填参数校验 if err != nil { app.Error(c, http.StatusBadRequest, err, err.Error()) return } err = model.EditErpMarketingCoupon(req) if err != nil { logger.Error("EditErpMarketingCoupon err:", logger.Field("err", err)) app.Error(c, http.StatusInternalServerError, err, err.Error()) return } app.OK(c, nil, "编辑成功") return } // ErpMarketingCouponDetail 优惠券详情 // @Summary 优惠券详情 // @Tags 营销管理,V1.4.4 // @Produce json // @Accept json // @Param request body models.ErpMarketingCouponDetailReq true "优惠券详情模型" // @Success 200 {object} models.ErpCoupon // @Router /api/v1/marketing/coupon/detail [post] func ErpMarketingCouponDetail(c *gin.Context) { req := &model.ErpMarketingCouponDetailReq{} if err := c.ShouldBindJSON(&req); err != nil { logger.Error("ShouldBindJSON err:", logger.Field("err", err)) app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") return } err := tools.Validate(req) //必填参数校验 if err != nil { app.Error(c, http.StatusBadRequest, err, err.Error()) return } // 查询订单信息 var erpCoupon model.ErpCoupon err = orm.Eloquent.Table("erp_coupon").Where("id=?", req.ErpCouponId).Find(&erpCoupon).Error if err != nil { logger.Error("query erp_coupon err:", logger.Field("err", err)) app.Error(c, http.StatusInternalServerError, err, err.Error()) return } app.OK(c, erpCoupon, "OK") return } // ErpMarketingCouponDelete 删除优惠券 // @Summary 删除优惠券 // @Tags 营销管理,V1.4.4 // @Produce json // @Accept json // @Param request body models.ErpMarketingCouponDeleteReq true "删除优惠券模型" // @Success 200 {object} app.Response // @Router /api/v1/marketing/coupon/delete [post] func ErpMarketingCouponDelete(c *gin.Context) { var req = new(model.ErpMarketingCouponDeleteReq) if err := c.ShouldBindJSON(&req); err != nil { logger.Error("ShouldBindJSON err:", logger.Field("err", err)) app.Error(c, http.StatusBadRequest, err, "参数错误:"+err.Error()) return } err := tools.Validate(req) //必填参数校验 if err != nil { app.Error(c, http.StatusBadRequest, err, err.Error()) return } err = model.DeleteErpMarketingCoupon(req) if err != nil { logger.Error("DeleteErpMarketingCoupon err:", logger.Field("err", err)) app.Error(c, http.StatusInternalServerError, err, err.Error()) return } app.OK(c, nil, "删除成功") return } // ErpMarketingCouponStart 启动优惠券发放 // @Summary 启动优惠券发放 // @Tags 营销管理,V1.4.4 // @Produce json // @Accept json // @Param request body models.ErpMarketingCouponStartReq true "启动优惠券发放模型" // @Success 200 {object} app.Response // @Router /api/v1/marketing/coupon/start [post] func ErpMarketingCouponStart(c *gin.Context) { var req = new(model.ErpMarketingCouponStartReq) if err := c.ShouldBindJSON(&req); err != nil { logger.Error("ShouldBindJSON err:", logger.Field("err", err)) app.Error(c, http.StatusBadRequest, err, "参数错误:"+err.Error()) return } err := tools.Validate(req) //必填参数校验 if err != nil { app.Error(c, http.StatusBadRequest, err, err.Error()) return } // 检查是否有正在进行的任务 taskList, err := model.GetTaskProgress(req.ErpCouponId) if err != nil { app.Error(c, http.StatusInternalServerError, err, err.Error()) return } var waitSendTaskList []model.CouponIssuanceTask if len(taskList) != 0 { for _, task := range taskList { switch task.Status { case model.TaskInProgress: // 执行中 app.Error(c, http.StatusInternalServerError, errors.New(fmt.Sprintf("[%s]已在执行中,请勿重复启动", task.ErpCouponName)), fmt.Sprintf("[%s]已在执行中,请勿重复启动", task.ErpCouponName)) return case model.TaskCompleted: // 已完成 app.Error(c, http.StatusInternalServerError, errors.New(fmt.Sprintf("[%s]已执行完成", task.ErpCouponName)), fmt.Sprintf("[%s]已执行完成", task.ErpCouponName)) return default: waitSendTaskList = append(waitSendTaskList, task) } } } // 校验批量选择的优惠券使用人群是否相同 if !model.CheckUserType(req.ErpCouponId) { app.Error(c, http.StatusInternalServerError, errors.New("优惠券适用人群不同,不能同时启动"), "优惠券适用人群不同,不能同时启动") } // 更新短信和备注 err = orm.Eloquent.Table("erp_coupon").Where("id in ?", req.ErpCouponId). Updates(map[string]interface{}{ "remark": req.Remark, "state": model.ErpCouponSending, "start_time": time.Now(), "sms_content": req.SmsContent, "updated_at": time.Now(), }).Error if err != nil { logger.Errorf("更新任务完成状态失败: %v", err) app.Error(c, http.StatusInternalServerError, err, err.Error()) } go model.StartCouponIssuanceTask(req, waitSendTaskList) app.OK(c, nil, "启动成功") return } // ErpMarketingCouponData 优惠券数据 // @Summary 优惠券数据 // @Tags 营销管理,V1.4.4 // @Produce json // @Accept json // @Param request body models.ErpMarketingCouponDataReq true "优惠券数据模型" // @Success 200 {object} models.ErpMarketingCouponDataResp // @Router /api/v1/marketing/coupon/data [post] func ErpMarketingCouponData(c *gin.Context) { var req model.ErpMarketingCouponDataReq if err := c.ShouldBindJSON(&req); err != nil { app.Error(c, http.StatusBadRequest, err, "参数错误:"+err.Error()) return } userCouponIds, err := model.GetUserCouponIdsByErpCouponId(req.ErpCouponId) if err != nil { app.Error(c, http.StatusInternalServerError, err, err.Error()) return } // 查询使用该优惠券的订单商品 var orderCommodities []model.ErpOrderCommodity err = orm.Eloquent.Where("coupon_id in ?", userCouponIds). Joins("JOIN erp_order ON erp_order.id = erp_order_commodity.erp_order_id"). Where("erp_order.state = 'audited'").Find(&orderCommodities).Error if err != nil { app.Error(c, http.StatusInternalServerError, err, err.Error()) return } // 初始化统计数据 var totalAmount, totalDiscount float64 var orderCount, customerCount, productCount int productsMap := make(map[uint32]model.ProductInfo) customers := make(map[int]bool) // 用来去重客户 // 统计订单数据 for _, orderCommodity := range orderCommodities { // 获取订单详情 var order model.ErpOrder err = orm.Eloquent.First(&order, orderCommodity.ErpOrderId).Error if err != nil { app.Error(c, http.StatusInternalServerError, err, err.Error()) return } // 计算用券总成交额和总优惠金额 totalAmount += orderCommodity.ReceivedAmount totalDiscount += orderCommodity.CouponDiscount // 计算订单数 orderCount++ // 计算客户数 if _, exists := customers[order.Uid]; !exists { customers[order.Uid] = true customerCount++ } // 计算购买商品总件数 productCount += int(orderCommodity.Count) if _, exists := productsMap[orderCommodity.ErpCommodityId]; !exists { productsMap[orderCommodity.ErpCommodityId] = model.ProductInfo{ ProductID: int(orderCommodity.ErpCommodityId), ProductName: orderCommodity.ErpCommodityName, PayCount: int(orderCommodity.Count), PayCustomer: 1, } } else { productInfo := productsMap[orderCommodity.ErpCommodityId] productInfo.PayCount += int(orderCommodity.Count) productInfo.PayCustomer++ productsMap[orderCommodity.ErpCommodityId] = productInfo } } // 计算费效比 var costEffectiveness float64 if totalAmount > 0 { costEffectiveness = tools.RoundFloat(totalDiscount / totalAmount) } // 计算用券笔单价 var unitPrice float64 if orderCount > 0 { unitPrice = tools.RoundFloat(totalAmount / float64(orderCount)) } // 构造返回的数据结构 resp := model.ErpMarketingCouponDataResp{ TotalAmount: totalAmount, TotalDiscount: totalDiscount, CostEffectiveness: costEffectiveness, OrderCount: orderCount, UnitPrice: unitPrice, CustomerCount: customerCount, ProductCount: productCount, } // 转换商品数据 for _, productInfo := range productsMap { resp.Products = append(resp.Products, productInfo) } // 返回结果 app.OK(c, resp, "OK") } // GenerateScheme 获取小程序跳转链接 // @Summary 获取小程序跳转链接 // @Tags 营销管理,V1.4.4 // @Produce json // @Accept json // @Param request body models.GenerateSchemeReq true "获取小程序跳转链接模型" // @Success 200 {object} models.GenerateSchemeResp // @Router /api/v1/marketing/generateScheme [post] func GenerateScheme(c *gin.Context) { var req model.GenerateSchemeReq if err := c.ShouldBindJSON(&req); err != nil { app.Error(c, http.StatusBadRequest, err, "参数错误:"+err.Error()) return } err := tools.Validate(req) //必填参数校验 if err != nil { app.Error(c, http.StatusBadRequest, err, err.Error()) return } resp, err := model.WXGenerateScheme(&req) if err != nil { logger.Error("WXGenerateScheme err:", logger.Field("err", err)) app.Error(c, http.StatusInternalServerError, err, err.Error()) return } // 返回结果 app.OK(c, resp, "OK") }