|
|
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)
|
|
|
|
|
|
}
|