mh_goadmin_server/app/admin/apis/market/marketing.go

395 lines
12 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 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")
}