package svc import ( "applet/app/db" "applet/app/db/model" "applet/app/e" "applet/app/enum" "applet/app/md" "applet/app/utils" "applet/app/utils/cache" "encoding/json" "errors" "fmt" "github.com/gin-gonic/gin" "github.com/shopspring/decimal" "time" "xorm.io/xorm" ) func OrderCate(c *gin.Context) { var cate = []map[string]string{ {"name": "全部", "value": ""}, {"name": "待付款", "value": "0"}, {"name": "待提货", "value": "1"}, {"name": "已完成", "value": "2"}, {"name": "已取消", "value": "3"}, } e.OutSuc(c, cate, nil) return } func OrderList(c *gin.Context) { var arg map[string]string if err := c.ShouldBindJSON(&arg); err != nil { e.OutErr(c, e.ERR_INVALID_ARGS, err) return } user := GetUser(c) arg["uid"] = utils.IntToStr(user.Info.Uid) data := db.GetOrderList(MasterDb(c), arg) var state = []string{"待付款", "待提货", "已完成", "已取消"} list := make([]map[string]string, 0) if data != nil { now := time.Now().Unix() for _, v := range *data { store := db.GetStoreIdEg(MasterDb(c), utils.IntToStr(v.StoreUid)) info := db.GetOrderInfoEg(MasterDb(c), utils.Int64ToStr(v.Oid)) downTime := "0" if v.State == 0 { downTime = utils.IntToStr(int(v.CreateAt.Unix() + 15*60 - now)) if now > v.CreateAt.Unix()+15*60 { v.State = 3 } if utils.StrToInt(downTime) < 0 { downTime = "0" } } img := "" title := "" storeName := "" if store != nil { storeName = store.Name } if info != nil { img = info.Img title = info.Title } tmp := map[string]string{ "oid": utils.Int64ToStr(v.Oid), "label": "自提", "state": utils.IntToStr(v.State), "state_str": state[v.State], "store_name": storeName, "img": img, "title": title, "amount": v.Amount, "num": utils.IntToStr(v.Num), "timer": "", "down_time": downTime, } if v.Type == 1 { tmp["label"] = "外卖" } if v.IsNow == 1 { tmp["timer"] = "立即提货" } else if v.Timer != "" { tmp["timer"] = "提货时间:" + v.Timer } list = append(list, tmp) } } e.OutSuc(c, list, nil) return } func OrderDetail(c *gin.Context) { var arg map[string]string if err := c.ShouldBindJSON(&arg); err != nil { e.OutErr(c, e.ERR_INVALID_ARGS, err) return } data := db.GetOrderEg(MasterDb(c), arg["oid"]) var state = []string{"待付款", "待提货", "已完成", "已取消"} now := time.Now().Unix() store := db.GetStoreIdEg(MasterDb(c), utils.IntToStr(data.StoreUid)) downTime := "0" if data.State == 0 { downTime = utils.IntToStr(int(data.CreateAt.Unix() + 15*60 - now)) if now > data.CreateAt.Unix()+15*60 { data.State = 3 } if utils.StrToInt(downTime) < 0 { downTime = "0" } } img := "" title := "" storeName := "" storeAddress := "" lat := "" lng := "" km := "" if store != nil { storeName = store.Name storeAddress = store.Address lat = store.Lat lng = store.Lng km = "" if arg["lat"] != "" && arg["lng"] != "" { km1 := utils.CalculateDistance(utils.StrToFloat64(lat), utils.StrToFloat64(lng), utils.StrToFloat64(arg["lat"]), utils.StrToFloat64(arg["lng"])) if km1 < 1 { km = utils.Float64ToStr(km1*1000) + "m" } else { km = utils.Float64ToStr(km1) + "km" } } } confirmAt := "" if data.ConfirmAt.IsZero() == false { confirmAt = data.ConfirmAt.Format("2006-01-02 15:04:05") } payMethod := "-" if data.PayMethod > 0 { payMethod = md.PayMethodIdToName[data.PayMethod] } orderInfo := []map[string]string{ {"title": "订单编号", "content": utils.Int64ToStr(data.Oid)}, {"title": "下单时间", "content": data.CreateAt.Format("2006-01-02 15:04:05")}, {"title": "提货时间", "content": confirmAt}, {"title": "预留电话", "content": data.Phone}, {"title": "支付方式", "content": payMethod}, {"title": "备注信息", "content": data.Memo}, } goodsInfo := make([]map[string]string, 0) info := db.GetOrderInfoAllEg(MasterDb(c), utils.Int64ToStr(data.Oid)) if info != nil { for _, v := range *info { tmp := map[string]string{ "img": v.Img, "title": v.Title, "price": v.Price, "num": utils.IntToStr(v.Num), "sku_str": "", } skuData := make([]md.Sku, 0) json.Unmarshal([]byte(v.SkuInfo), &skuData) skuStr := "" for _, v1 := range skuData { if skuStr != "" { skuStr += ";" } skuStr += v1.Value } tmp["sku_str"] = skuStr goodsInfo = append(goodsInfo, tmp) } } tmp := map[string]interface{}{ "oid": utils.Int64ToStr(data.Oid), "label": "自提", "state": utils.IntToStr(data.State), "state_str": state[data.State], "store_name": storeName, "store_address": storeAddress, "lat": lat, "lng": lng, "km": km, "img": img, "title": title, "amount": data.Amount, "num": utils.IntToStr(data.Num), "timer": "", "code": data.Code, "down_time": downTime, "order_info": orderInfo, "goods_info": goodsInfo, "goods_count": utils.IntToStr(len(goodsInfo)), } if data.Type == 1 { tmp["label"] = "外卖" } if data.IsNow == 1 { tmp["timer"] = "立即提货" } else if data.Timer != "" { tmp["timer"] = data.Timer } e.OutSuc(c, tmp, nil) return } func OrderCoupon(c *gin.Context) { var arg md.OrderTotal if err := c.ShouldBindJSON(&arg); err != nil { e.OutErr(c, e.ERR_INVALID_ARGS, err) return } totalPrice := commGoods(c, arg) returnData := CommCoupon(c, totalPrice) e.OutSuc(c, returnData, nil) return } func CommCoupon(c *gin.Context, totalPrice string) map[string]interface{} { var err error engine := MasterDb(c) user := GetUser(c) now := time.Now().Format("2006-01-02 15:04:05") var ActCouponUserList []*model.CommunityTeamCouponUser sess := engine.Table("act_coupon_user"). Where("store_type=? and uid = ? AND is_use = ? AND (valid_time_start < ? AND valid_time_end > ?)", 0, user.Info.Uid, 0, now, now) err = sess.Find(&ActCouponUserList) if err != nil { return map[string]interface{}{} } var ids = make([]int, 0) for _, v := range ActCouponUserList { ids = append(ids, v.MerchantSchemeId) } var merchantScheme []model.CommunityTeamCoupon engine.In("id", ids).Find(&merchantScheme) var merchantSchemeMap = make(map[int]model.CommunityTeamCoupon) for _, v := range merchantScheme { merchantSchemeMap[v.Id] = v } var couponList []md.CouponList // 可使用的 couponList = make([]md.CouponList, 0) count := 0 for _, item := range ActCouponUserList { var coupon = md.CouponList{ Id: utils.Int64ToStr(item.Id), Title: item.Name, Timer: item.ValidTimeStart.Format("2006.01.02") + "-" + item.ValidTimeEnd.Format("2006.01.02"), Label: "全部商品可用", Img: item.Img, Content: item.ActivityStatement, IsCanUse: "0", NotUseStr: "", } var cal struct { Reach string `json:"reach"` Reduce string `json:"reduce"` } err = json.Unmarshal([]byte(item.Cal), &cal) if err != nil { return map[string]interface{}{} } switch item.Kind { case int(enum.ActCouponTypeImmediate): if utils.AnyToFloat64(totalPrice) >= utils.AnyToFloat64(cal.Reduce) { coupon.IsCanUse = "1" } case int(enum.ActCouponTypeReachReduce): if utils.AnyToFloat64(totalPrice) >= utils.AnyToFloat64(cal.Reduce) { coupon.IsCanUse = "1" } case int(enum.ActCouponTypeReachDiscount): if utils.AnyToFloat64(totalPrice) >= utils.AnyToFloat64(cal.Reduce) && utils.AnyToFloat64(cal.Reduce) > 0 { coupon.IsCanUse = "1" } if utils.AnyToFloat64(cal.Reduce) == 0 { coupon.IsCanUse = "1" } } if coupon.IsCanUse != "1" { coupon.NotUseStr = "订单金额未满" + cal.Reduce + "元" } if coupon.IsCanUse == "1" { count++ } couponList = append(couponList, coupon) } returnData := map[string]interface{}{ "total": utils.IntToStr(count), "coupon_list": couponList, } return returnData } func OrderCancel(c *gin.Context) { var arg map[string]string if err := c.ShouldBindJSON(&arg); err != nil { e.OutErr(c, e.ERR_INVALID_ARGS, err) return } // 加锁 防止并发提取 mutexKey := fmt.Sprintf("%s:team.OrderCancel:%s", c.GetString("mid"), arg["oid"]) withdrawAvailable, err := cache.Do("SET", mutexKey, 1, "EX", 5, "NX") if err != nil { e.OutErr(c, e.ERR, err) return } if withdrawAvailable != "OK" { e.OutErr(c, e.ERR, e.NewErr(400000, "请求过于频繁,请稍后再试")) return } sess := MasterDb(c).NewSession() defer sess.Close() sess.Begin() order := db.GetOrder(sess, arg["oid"]) if order == nil { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "订单不存在")) return } if order.State > 0 { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "订单不能取消")) return } orderInfo := db.GetOrderInfo(sess, arg["oid"]) if orderInfo != nil { goodsMap := make(map[int]int) skuMap := make(map[int]int) for _, v := range *orderInfo { goodsMap[v.GoodsId] += v.Num skuMap[v.SkuId] += v.Num } for k, v := range goodsMap { sql := `update community_team_goods set stock=stock+%d where id=%d` sql = fmt.Sprintf(sql, v, k) _, err := db.QueryNativeStringWithSess(sess, sql) if err != nil { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "订单取消失败")) return } } for k, v := range skuMap { sql := `update community_team_sku set stock=stock+%d where sku_id=%d` sql = fmt.Sprintf(sql, v, k) _, err := db.QueryNativeStringWithSess(sess, sql) if err != nil { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "订单取消失败")) return } } } order.State = 3 order.UpdateAt = time.Now() update, err := sess.Where("id=?", order.Id).Cols("state,update_at").Update(order) if update == 0 || err != nil { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "订单取消失败")) return } if order.CouponId > 0 { update, err = sess.Where("id=?", order.CouponId).Cols("is_use").Update(&model.CommunityTeamCouponUser{IsUse: 0}) if update == 0 || err != nil { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "订单取消失败")) return } } sess.Commit() e.OutSuc(c, "success", nil) return } func OrderCreate(c *gin.Context) { var arg md.OrderTotal if err := c.ShouldBindJSON(&arg); err != nil { e.OutErr(c, e.ERR_INVALID_ARGS, err) return } user := GetUser(c) // 加锁 防止并发提取 mutexKey := fmt.Sprintf("%s:team.OrderCreate:%s", c.GetString("mid"), utils.IntToStr(user.Info.Uid)) withdrawAvailable, err := cache.Do("SET", mutexKey, 1, "EX", 5, "NX") if err != nil { e.OutErr(c, e.ERR, err) return } if withdrawAvailable != "OK" { e.OutErr(c, e.ERR, e.NewErr(400000, "请求过于频繁,请稍后再试")) return } sess := MasterDb(c).NewSession() defer sess.Close() err = sess.Begin() if err != nil { e.OutErr(c, 400, err.Error()) return } totalPrice := commGoods(c, arg) coupon := "0" totalPrice, coupon, err = CouponProcess(c, sess, totalPrice, arg) if err != nil { sess.Rollback() e.OutErr(c, 400, err.Error()) return } ordId := utils.OrderUUID(user.Info.Uid) // 获取店铺信息 store := db.GetStoreId(sess, arg.StoreId) num := 0 for _, item := range arg.GoodsInfo { num += utils.StrToInt(item.Num) } var order = &model.CommunityTeamOrder{ Uid: user.Info.Uid, StoreUid: utils.StrToInt(arg.StoreId), Commission: utils.Float64ToStr(utils.FloatFormat(utils.AnyToFloat64(totalPrice)*(utils.AnyToFloat64(store.Commission)/100), 2)), CreateAt: time.Now(), UpdateAt: time.Now(), BuyPhone: arg.BuyPhone, Coupon: coupon, Num: num, IsNow: utils.StrToInt(arg.IsNow), Timer: arg.Timer, Memo: arg.Memo, Oid: utils.StrToInt64(ordId), Amount: totalPrice, MealNum: utils.StrToInt(arg.MealNum), } if utils.StrToFloat64(coupon) > 0 { order.CouponId = utils.StrToInt(arg.CouponId) } insert, err := sess.Insert(order) if insert == 0 || err != nil { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "下单失败")) return } for _, item := range arg.GoodsInfo { // 获取详细信息 goodsInterface, has, err := db.GetComm(MasterDb(c), &model.CommunityTeamGoods{Id: utils.StrToInt(item.GoodsId)}) if err != nil || !has { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "商品不存在")) return } goodsModel := goodsInterface.(*model.CommunityTeamGoods) var skuInterface interface{} if item.SkuId != "-1" { skuInterface, _, _ = db.GetComm(MasterDb(c), &model.CommunityTeamSku{GoodsId: utils.StrToInt(item.GoodsId), SkuId: utils.StrToInt64(item.SkuId)}) } else { skuInterface, _, _ = db.GetComm(MasterDb(c), &model.CommunityTeamSku{GoodsId: utils.StrToInt(item.GoodsId)}) } if err != nil || !has { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "商品不存在")) return } skuModel := skuInterface.(*model.CommunityTeamSku) var goodsSaleCount int // 走普通逻辑 stock := skuModel.Stock - utils.StrToInt(item.Num) saleCount := skuModel.SaleCount + utils.StrToInt(item.Num) goodsSaleCount = goodsModel.SaleCount + utils.StrToInt(item.Num) if stock < 0 { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "库存不足")) return } update, err := sess.Where("sku_id=?", skuModel.SkuId).Cols("stock", "sale_count").Update(&model.CommunityTeamSku{Stock: stock, SaleCount: saleCount}) if err != nil { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "商品不存在")) return } if update != 1 { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "商品不存在")) return } // 更新销量 goodsModel.SaleCount = goodsSaleCount goodsModel.Stock = goodsModel.Stock - utils.StrToInt(item.Num) _, err = sess.Where("id = ?", goodsModel.Id).Cols("sale_count,stock").Update(goodsModel) if err != nil { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "商品不存在")) return } // 插入订单 insert, err := sess.Insert(&model.CommunityTeamOrderInfo{ Oid: utils.StrToInt64(ordId), Title: goodsModel.Title, Img: goodsModel.Img, Price: skuModel.Price, Num: utils.StrToInt(item.Num), SkuInfo: skuModel.Sku, GoodsId: skuModel.GoodsId, SkuId: int(skuModel.SkuId), }) if err != nil { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "下单失败")) return } if insert != 1 { sess.Rollback() e.OutErr(c, 400, e.NewErr(400, "下单失败")) return } } // 更新优惠券使用状态 if utils.StrToInt(arg.CouponId) > 0 { affect, err := sess.Where("id = ?", arg.CouponId). Update(&model.CommunityTeamCouponUser{IsUse: 1}) if err != nil { e.OutErr(c, 400, e.NewErr(400, "下单失败")) return } if affect != 1 { e.OutErr(c, 400, e.NewErr(400, "下单失败")) return } } err = sess.Commit() if err != nil { sess.Rollback() e.OutErr(c, 400, err.Error()) return } sess.Commit() return } func OrderTotal(c *gin.Context) { var arg md.OrderTotal if err := c.ShouldBindJSON(&arg); err != nil { e.OutErr(c, e.ERR_INVALID_ARGS, err) return } sess := MasterDb(c).NewSession() defer sess.Close() err := sess.Begin() if err != nil { e.OutErr(c, 400, err.Error()) return } totalPrice := commGoods(c, arg) oldTotalPrice := totalPrice coupon := "0" totalPrice, coupon, err = CouponProcess(c, sess, totalPrice, arg) if err != nil { sess.Rollback() e.OutErr(c, 400, err.Error()) return } user := GetUser(c) result := map[string]interface{}{ "balance_money": GetCommissionPrec(c, user.Profile.FinValid, SysCfgGet(c, "commission_prec"), SysCfgGet(c, "is_show_point")), "small_amount": GetCommissionPrec(c, oldTotalPrice, SysCfgGet(c, "commission_prec"), SysCfgGet(c, "is_show_point")), "all_amount": GetCommissionPrec(c, totalPrice, SysCfgGet(c, "commission_prec"), SysCfgGet(c, "is_show_point")), "coupon": GetCommissionPrec(c, coupon, SysCfgGet(c, "commission_prec"), SysCfgGet(c, "is_show_point")), } sess.Commit() e.OutSuc(c, result, nil) return } func CouponProcess(c *gin.Context, sess *xorm.Session, total string, args md.OrderTotal) (string, string, error) { if utils.StrToInt(args.CouponId) == 0 { return total, "0", nil } now := time.Now().Format("2006-01-02 15:04:05") user := GetUser(c) var goodsIds []int var skuIds []string for _, item := range args.GoodsInfo { goodsIds = append(goodsIds, utils.StrToInt(item.GoodsId)) skuIds = append(skuIds, utils.AnyToString(item.SkuId)) } // 获取优惠券信息 var mallUserCoupon model.CommunityTeamCouponUser isExist, err := sess. Where("id = ? AND uid = ? AND is_use = ? AND (valid_time_start < ? AND valid_time_end > ?)", args.CouponId, user.Info.Uid, 0, now, now). Get(&mallUserCoupon) if err != nil { return "", "", err } if !isExist { return "", "", errors.New("无相关优惠券信息") } var cal struct { Reach string `json:"reach"` Reduce string `json:"reduce"` } _ = json.Unmarshal([]byte(mallUserCoupon.Cal), &cal) reach, err := decimal.NewFromString(cal.Reach) reduce, err := decimal.NewFromString(cal.Reduce) if err != nil { return "", "", err } var specialTotal = total // 是否满足优惠条件 if !reach.IsZero() { // 满减及有门槛折扣 if utils.StrToFloat64(specialTotal) < utils.StrToFloat64(reach.String()) { return "", "", errors.New("不满足优惠条件") } } else { if mallUserCoupon.Kind == 1 { //立减 if utils.StrToFloat64(specialTotal) < utils.StrToFloat64(reduce.String()) { return "", "", errors.New("付款金额有误") } } } // 计算优惠后支付金额 couponTotal := "0" if mallUserCoupon.Kind == int(enum.ActCouponTypeImmediate) || mallUserCoupon.Kind == int(enum.ActCouponTypeReachReduce) { // 立减 || 满减 couponTotal = reduce.String() total = utils.Float64ToStr(utils.StrToFloat64(total) - utils.StrToFloat64(reduce.String())) } else { // 折扣 couponTotal = utils.Float64ToStr(utils.StrToFloat64(total) - utils.StrToFloat64(total)*utils.StrToFloat64(reduce.String())/10) total = utils.Float64ToStr(utils.StrToFloat64(total) * utils.StrToFloat64(reduce.String()) / 10) } return total, couponTotal, nil } func commGoods(c *gin.Context, arg md.OrderTotal) (totalPrice string) { engine := MasterDb(c) var totalPriceAmt float64 = 0 for _, item := range arg.GoodsInfo { goodsInterface, _, _ := db.GetComm(engine, &model.CommunityTeamGoods{Id: utils.StrToInt(item.GoodsId)}) goodsModel := goodsInterface.(*model.CommunityTeamGoods) var skuInterface interface{} if item.SkuId != "-1" { skuInterface, _, _ = db.GetComm(engine, &model.CommunityTeamSku{GoodsId: utils.StrToInt(item.GoodsId), SkuId: utils.StrToInt64(item.SkuId)}) } else { skuInterface, _, _ = db.GetComm(engine, &model.CommunityTeamSku{GoodsId: utils.StrToInt(item.GoodsId)}) } skuModel := skuInterface.(*model.CommunityTeamSku) priceOne := goodsModel.Price if item.SkuId != "-1" { priceOne = skuModel.Price } totalPriceAmt += utils.StrToFloat64(priceOne) * utils.StrToFloat64(item.Num) } return utils.Float64ToStr(totalPriceAmt) }