package aftersales import ( "fmt" "recook/internal/back" "recook/internal/dbc" "recook/internal/libs/snow" "recook/internal/model/aftersales" "recook/internal/model/goods" "recook/internal/model/order" "recook/internal/v2/hook" "recook/internal/v2/lib/common" "recook/internal/v2/lib/jcook" "recook/internal/v2/model/recook/after" "recook/tools" "time" "github.com/gin-gonic/gin" "github.com/golangkit/formatime" "github.com/shopspring/decimal" ) type applyRefundParam struct { UserID uint `json:"userId"` OrderGoodsIDs []uint `json:"orderGoodsIds"` Coin decimal.Decimal `json:"coin"` //允许发货订单发起仅退款的数字, ReasonContent string `json:"reasonContent"` //如果是已发货的话,必须填写申请理由 ReasonImg string `json:"reasonImg"` } // RefundOrder 退款 // //标记订单有售后痕迹 //生成退款记录 // //钱包支付;退回商品用过的的余额 //退回优惠券 //退回运费 func RefundOrder(c *gin.Context) { var p applyRefundParam err := tools.ParseParams(&p, c) if err != nil { back.Fail(c, err.Error()) return } if len(p.OrderGoodsIDs) == 0 { back.Fail(c, "参数不完整") return } var temp order.GoodsDetail err = dbc.DB.First(&temp, p.OrderGoodsIDs[0]).Error if err != nil { back.Fail(c, err.Error()) return } var orderTemp order.Information err = dbc.DB.First(&orderTemp, temp.OrderID).Error if err != nil { back.Fail(c, err.Error()) return } if (orderTemp.Kind == 1 || orderTemp.Kind == 2) && orderTemp.JCookStatus == 0 { var ogs []order.GoodsDetail err = dbc.DB.Find(&ogs, "order_id = ?", orderTemp.ID).Error if err != nil { back.Fail(c, err.Error()) return } ids := make([]uint, 0) for _, v := range ogs { ids = append(ids, v.ID) } p.OrderGoodsIDs = ids } orderGoodsList := make([]order.GoodsDetail, 0, 0) for _, v := range p.OrderGoodsIDs { var one order.GoodsDetail err = dbc.DB.First(&one, v).Error if err != nil { back.Fail(c, err.Error()) return } var count uint dbc.DB.Table((&aftersales.Goods{}).TableName()).Where(aftersales.Goods{ OrderGoodsID: v, }).Count(&count) if count >= 3 { back.Fail(c, one.GoodsName+"已超过三次售后申请,不可再次申请") return } orderGoodsList = append(orderGoodsList, one) } var orderInfo order.Information if err = dbc.DB.First(&orderInfo, orderGoodsList[0].OrderID).Error; err != nil { back.Fail(c, err.Error()) return } if orderInfo.Status == 4 { back.Fail(c, "已超过售后期限") return } if time.Now().Unix() >= orderInfo.CreatedAt.Time.AddDate(0, 0, 18).Unix() { back.Fail(c, "关账时间已过,无法发起售后") return } var asCount uint dbc.DB.Table((&aftersales.Goods{}).TableName()).Where("order_id = ?", orderInfo.ID).Count(&asCount) if asCount > 20 { back.Fail(c, "单笔订单售后次数最多20次,您已经超过上线") return } for _, v := range orderGoodsList { if v.PayStatus == 0 { back.Fail(c, "当前订单未支付") return } if v.AssType != 0 { back.Fail(c, "请勿重复申请") return } if v.GoodsAmount.LessThan(p.Coin) { back.Err(c, "计算错误!!! 退款金额大于总金额") return } //如果是已经发货的 if v.ExpressStatus == 1 { if len(p.ReasonContent) == 0 { back.Fail(c, "请填写申请理由") return } if p.Coin.LessThanOrEqual(decimal.NewFromInt(0)) { back.Fail(c, "申请补偿订单必须大于0") return } } } var goodsIds []uint for _, detail := range orderGoodsList { goodsIds = append(goodsIds, detail.GoodsID) } var goodsInfos []goods.Information dbc.DB.Model(&goods.Information{}).Find(&goodsInfos, "id in (?)", goodsIds) goodsInfoMap := map[uint]goods.Information{} for _, info := range goodsInfos { goodsInfoMap[info.ID] = info } var ids []uint for i, v := range orderGoodsList { goodsDetail := orderGoodsList[i] asGoods := aftersales.Goods{ AncestorID: v.AncestorID, ParentID: v.ParentID, SharerID: orderInfo.SharerID, UserID: v.UserID, UserRole: orderInfo.UserRole, OrderID: v.OrderID, OrderGoodsID: v.ID, VendorID: v.VendorID, VendorName: v.VendorName, BrandName: v.BrandName, CategoryName: v.CategoryName, GoodsID: v.GoodsID, GoodsName: v.GoodsName, SkuName: v.SkuName, SkuCode: v.SkuCode, MainPhotoURL: v.MainPhotoURL, Quantity: v.Quantity, OrderTime: v.OrderTime, OrderTotalAmount: orderInfo.ActualTotalAmount, RefundAmount: v.ActualAmount, //这个就是最后实际支付的价格 RefundCoin: v.CoinAmount, TradeNo: orderInfo.TradeNo, PayMethod: orderInfo.PayMethod, ThirdPartyType: goodsInfoMap[v.GoodsID].ThirdPartyType, IsShip: v.ExpressStatus, AssType: 1, ReturnStatus: 1, ApplyTime: formatime.NewSecondNow(), ReasonImg: p.ReasonImg, ReasonContent: p.ReasonContent, RefundNo: fmt.Sprintf("%d_%vA%d", time.Now().Unix(), orderInfo.TradeNo, goodsDetail.ID), } //如果是已经发货的订单,需要在售后里面把实际支付改成功0,将瑞币改成提交过来的数字 if asGoods.IsShip == 1 { // 认为是补偿订单 asGoods.AssType = 3 if p.Coin.GreaterThan(v.ActualAmount.Add(v.CoinAmount)) { back.Fail(c, "补偿金额超过最大金额") return } if p.Coin.GreaterThan(v.ActualAmount) && p.Coin.LessThanOrEqual(v.ActualAmount.Add(v.CoinAmount)) { asGoods.RefundAmount = v.ActualAmount.Truncate(2) asGoods.RefundCoin = p.Coin.Sub(v.ActualAmount).Truncate(2) } if p.Coin.LessThan(v.ActualAmount) { asGoods.RefundAmount = p.Coin.Truncate(2) asGoods.RefundCoin = decimal.NewFromInt(0) } } tx := dbc.DB.Begin() { lastID, e := snow.GetAfsWorker().NextID() if e != nil { back.Err(c, "网络异常,请稍后重试") tx.Rollback() return } asGoods.ID = uint(lastID) if asGoods.IsShip == 1 { tx.Model(&goodsDetail).Updates(order.GoodsDetail{ AssType: 3, }) } else { tx.Model(&goodsDetail).Updates(order.GoodsDetail{ AssType: 1, }) } if err = tx.Create(&asGoods).Error; err != nil { back.Err(c, err.Error()) tx.Rollback() return } ids = append(ids, asGoods.ID) if err := hook.AfterHook.Create(&goodsDetail, &asGoods); err != nil { back.Err(c, err.Error()) tx.Rollback() return } //这里插入日志 user, _ := common.GetManageUser(c) Log := aftersales.AftersalesLog{ AsId: uint(lastID), Title: "买家申请仅退款", Content: "退款原因:" + p.ReasonContent + "|退款金额:" + (asGoods.RefundAmount).String() + "|退回瑞币:" + asGoods.RefundCoin.String(), Ctime: formatime.NewSecondNow(), User: user.Name, UserId: user.Id, } tx.Create(&Log) if (orderInfo.Kind == 1 || orderInfo.Kind == 2) && orderInfo.ApplyStatus != 11 && orderInfo.ApplyStatus != 12 && orderInfo.JCookStatus == 0 { client := jcook.GetClient() req := jcook.OrderCancelReq{ OrderID: orderInfo.JCookOrderID, CancelReasonCode: 100, } var resp jcook.OrderCancelResp if err = client.Exec(req, &resp); err != nil { tx.Rollback() back.Suc(c, "申请失败", nil) return } if resp.CancelStatus == 1 { tx.Model(orderInfo).Update("apply_status", 12) // 取消申请失败 } else { tx.Model(orderInfo).Update("apply_status", 11) // 取消申请成功 } } } tx.Commit() } c.Set("status", "AfterApply") c.Set("id", ids) back.Suc(c, "申请成功,请等待商家审核", nil) } type CannelAfterOrderPem struct { ID uint `json:"orderGoodsId"` } //撤销售后的申请 //有售后,且售后未完结,才能撤销 //refund_status=1,express_status=1,ass_type!=0才能申请撤销退款 func CannelAfterOrder(c *gin.Context) { var p CannelAfterOrderPem err := tools.ParseParams(&p, c) if err != nil { back.Fail(c, err.Error()) return } userlog, _ := common.GetManageUser(c) var orderGoodsDea order.GoodsDetail dbc.DB.First(&orderGoodsDea, "id=? and express_status=1 and ass_type!=0", p.ID) if orderGoodsDea.ID <= 0 { back.Fail(c, "该订单无法撤销售后") return } //去撤销售后 dbc.DB.Table("recook_order_goods_detail").Where("id=?", p.ID).Update(map[string]interface{}{ "ass_type": 0, }) var idlist []uint var afterOrder after.RecookAfterSalesGoodsModel dbc.DB.Order("id desc").First(&afterOrder, "order_goods_id=?", p.ID) if afterOrder.Id > 0 { dbc.DB.Model(&afterOrder).Updates(aftersales.Goods{ ReturnStatus: 6, RejectReason: "买家主动撤销", FinishTime: formatime.NewSecondNow(), IsClosed: 1, }) hook.AfterHook.Close(&afterOrder) aftersalesLog := aftersales.AftersalesLog{ AsId: afterOrder.Id, Title: "主动撤销", Content: "买家主动撤销售后", Ctime: formatime.NewSecondNow(), User: userlog.Name, UserId: userlog.Id, } dbc.DB.Create(&aftersalesLog) } idlist = append(idlist, afterOrder.Id) c.Set("status", "AfterApply") c.Set("id", idlist) back.Suc(c, "", nil) }