Files
jx-callback/business/partner/purchase/ebai/order_afs.go
邹宗楠 8c301f67a5 1
2024-08-01 16:40:35 +08:00

449 lines
19 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 ebai
import (
"errors"
"fmt"
"git.rosy.net.cn/jx-callback/business/model/dao"
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
AfsVendorStatus2Status4PartRefundMap = map[int]int{
ebaiapi.OrderPartRefundApply: model.AfsOrderStatusWait4Approve,
ebaiapi.OrderPartRefundSuccess: model.AfsOrderStatusFinished,
ebaiapi.OrderPartRefundUserApplyArbitration: model.OrderStatusUnknown, // 是否是中间状态
ebaiapi.OrderPartRefundFailed: model.AfsOrderStatusFailed,
ebaiapi.OrderPartRefundMerchantRefused: model.AfsOrderStatusFailed, // 是否是中间状态
}
AfsVendorStatus2Status4ReverseRefundMap = map[int]int{
//ebaiapi.OrderReversePushApplyInit: model.AfsOrderStatusWait4Approve, // 初始化售后
ebaiapi.OrderReversePushApply: model.AfsOrderStatusWait4Approve, // 申请售后
ebaiapi.OrderReversePushApplyRefuse: model.AfsOrderStatusFailed, // 售后失败
ebaiapi.OrderReversePushApplyArbitration: model.AfsOrderStatusReceivedArbitration, // 仲裁
ebaiapi.OrderReversePushApplyClose: model.AfsOrderStatusFinished, // 售后结束
ebaiapi.OrderReversePushApplySuccess: model.AfsOrderStatusFinished, // 售后成功
ebaiapi.OrderReversePushApplyFail: model.AfsOrderStatusFailed, // 售后失败
}
AfsVendorStatus2Status4UserCancel = map[int]int{
ebaiapi.OrderUserCancelApply: model.AfsOrderStatusWait4Approve,
ebaiapi.OrderUserCancelCSIntervene: model.OrderStatusUnknown,
ebaiapi.OrderUserCancelCSRefused: model.AfsOrderStatusFailed,
ebaiapi.OrderUserCancelCSAgreed: model.AfsOrderStatusFinished,
ebaiapi.OrderUserCancelMerchantRefused: model.AfsOrderStatusFailed,
ebaiapi.OrderUserCancelMerchantAgreed: model.AfsOrderStatusFinished,
ebaiapi.OrderUserCancelInvalid: model.AfsOrderStatusFailed,
}
)
func (c *PurchaseHandler) isAfsMsg(msg *ebaiapi.CallbackMsg) bool {
switch msg.Cmd {
case ebaiapi.CmdOrderPartRefund:
msgType := int(utils.MustInterface2Int64(msg.Body["type"]))
return msgType == ebaiapi.OrderPartRefuncTypeCustomer || msgType == ebaiapi.OrderPartRefuncTypeCS
case ebaiapi.CmdOrderUserCancel:
// 1表示订单完成前用户全单取消申请流程 2表示订单完成后用户全单退款申请流程
cancelType := int(utils.MustInterface2Int64(msg.Body["cancel_type"]))
return cancelType == ebaiapi.OrderUserCancelTypeAfterSale || cancelType == ebaiapi.OrderUserCancelTypeBeforeSale
case ebaiapi.CmdOrderReversePush: // 订单逆向消息推送
return true
}
return false
}
func (c *PurchaseHandler) OnAfsOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
jxutils.CallMsgHandlerAsync(func() {
retVal = c.onAfsOrderMsg(msg)
}, jxutils.ComposeUniversalOrderID(GetOrderIDFromMsg(msg), model.VendorIDEBAI))
return retVal
}
func (c *PurchaseHandler) onAfsOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) {
if orderStatus := c.callbackAfsMsg2Status(msg); orderStatus != nil {
var err error
if orderStatus.RefVendorOrderID == "4032000156853892856" {
globals.SugarLogger.Debug("==msg := %s", utils.Format4Output(msg, false))
globals.SugarLogger.Debug("==orderStatus := %s", utils.Format4Output(orderStatus, false))
}
if orderStatus.Status == model.AfsOrderStatusWait4Approve || orderStatus.Status == model.AfsOrderStatusNew {
var afsOrder *model.AfsOrder
if msg.Cmd == ebaiapi.CmdOrderPartRefund {
globals.SugarLogger.Debug("====order.partrefund.push :- %s", utils.Format4Output(msg, false))
afsOrder = c.makeAfsOrderInfoPartRefund(msg, orderStatus)
} else if msg.Cmd == ebaiapi.CmdOrderReversePush {
afsOrder, err = c.makeAfsOrderInfoReverseRefund(msg, orderStatus)
if err != nil {
return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
}
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel {
if afsOrder = c.createAfsOrder(msg); afsOrder != nil {
cancelData := msg.Data.(*ebaiapi.CBUserCancelInfo)
afsOrder.AfsOrderID = orderStatus.VendorOrderID
afsOrder.RefundType = model.AfsTypeFullRefund
afsOrder.AppealType = model.AfsAppealTypeRefund
afsOrder.VendorReasonType = ""
afsOrder.ReasonType = model.AfsReasonNotOthers
afsOrder.ReasonDesc = utils.LimitUTF8StringLen(buildFullReason(cancelData.CancelReason, cancelData.AdditionReason), 1024)
afsOrder.ReasonImgList = utils.LimitUTF8StringLen(strings.Join(cancelData.Pictures, ","), 1024)
}
}
if afsOrder != nil {
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
}
} else {
afsOrder2, err := partner.CurOrderManager.LoadAfsOrder(orderStatus.VendorOrderID, orderStatus.VendorID)
if orderStatus.RefVendorOrderID == "4032000156853892856" {
globals.SugarLogger.Debug("==err := %v", err)
globals.SugarLogger.Debug("==afsOrder2 := %s", utils.Format4Output(afsOrder2, false))
}
if afsOrder2 == nil && err == nil && msg.Cmd == ebaiapi.CmdOrderPartRefund {
afsOrder := c.makeAfsOrderInfoPartRefund(msg, orderStatus)
if afsOrder != nil {
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
}
} else if afsOrder2 == nil && err == nil && msg.Cmd == ebaiapi.CmdOrderReversePush {
afsOrder, err := c.makeAfsOrderInfoReverseRefund(msg, orderStatus)
if orderStatus.RefVendorOrderID == "4032000156853892856" {
globals.SugarLogger.Debug("==err ***:= %v", err)
globals.SugarLogger.Debug("==afsOrder** := %s", utils.Format4Output(afsOrder, false))
}
if afsOrder != nil {
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
}
} else {
err = partner.CurOrderManager.OnAfsOrderStatusChanged(orderStatus)
}
}
// 只有有售后订单就更新此订单的结算信息
var db = dao.GetDB()
if (msg.Cmd == ebaiapi.CmdOrderPartRefund && utils.Str2Int(orderStatus.VendorStatus) == ebaiapi.OrderPartRefundSuccess) || (msg.Cmd == ebaiapi.CmdOrderReversePush && utils.Str2Int(orderStatus.VendorStatus) == ebaiapi.OrderReversePushApplySuccess) {
orderData, err2 := api.EbaiAPI.OrderPartRefundGet(orderStatus.RefVendorOrderID)
if err2 == nil && utils.MustInterface2Int64(orderData["merchant_income"]) != model.NO {
goodsOrder, _ := partner.CurOrderManager.LoadOrder(orderStatus.RefVendorOrderID, model.VendorIDEBAI)
goodsOrder.TotalShopMoney = utils.MustInterface2Int64(orderData["merchant_income"])
// 门店结算小于等于50为扣点
afsSkuList, _ := dao.GetOrderRefundSkuList(db, []string{goodsOrder.VendorOrderID})
var earningPrice int64 = 0
for _, v := range goodsOrder.Skus {
if goodsOrder.EarningType == model.EarningTypeQuote {
earningPrice += v.ShopPrice
} else {
earningPrice += v.SalePrice
}
}
goodsOrder.EarningPrice = earningPrice
for _, v := range goodsOrder.Skus {
for _, v2 := range afsSkuList {
if v.VendorSkuID == v2.VendorSkuID && v2.IsAfsOrder == model.YES {
switch goodsOrder.EarningType {
case model.EarningTypeQuote: // 报价
goodsOrder.EarningPrice = goodsOrder.EarningPrice - (v.ShopPrice * int64(v2.Count))
case model.EarningTypePoints:
afsOrder, _ := partner.CurOrderManager.LoadAfsOrder(v2.AfsOrderID, v2.VendorID)
goodsOrder.EarningPrice = goodsOrder.EarningPrice - afsOrder.AfsTotalShopMoney
}
}
}
}
dao.UpdateEntity(dao.GetDB(), goodsOrder, "TotalShopMoney", "EarningPrice")
}
}
afs, _ := partner.CurOrderManager.LoadAfsOrder(orderStatus.RefVendorOrderID, model.VendorIDEBAI)
if msg.Cmd == ebaiapi.CmdOrderPartRefund {
switch utils.Str2Int(orderStatus.VendorStatus) {
case ebaiapi.OrderUserCancelMerchantAgreed, ebaiapi.OrderUserCancelCSAgreed:
afs.Status = orderStatus.Status
afs.VendorStatus = orderStatus.VendorStatus
afs.Flag = model.YES
case ebaiapi.OrderUserCancelCSRefused, ebaiapi.OrderUserCancelMerchantRefused, ebaiapi.OrderUserCancelInvalid:
afs.Status = orderStatus.Status
afs.VendorStatus = orderStatus.VendorStatus
afs.Flag = 3
}
} else if msg.Cmd == ebaiapi.CmdOrderReversePush {
switch utils.Str2Int(orderStatus.VendorStatus) {
case ebaiapi.OrderReversePushApplySuccess:
afs.Status = orderStatus.Status
afs.VendorStatus = orderStatus.VendorStatus
afs.Flag = model.YES
case ebaiapi.OrderReversePushApplyRefuse, ebaiapi.OrderReversePushApplyFail:
afs.Status = orderStatus.Status
afs.VendorStatus = orderStatus.VendorStatus
afs.Flag = 3
}
}
if afs != nil {
dao.UpdateEntity(db, afs, "Status", "VendorStatus", "Flag")
}
retVal = api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil)
}
return retVal
}
func (p *PurchaseHandler) createAfsOrder(msg *ebaiapi.CallbackMsg) (afsOrder *model.AfsOrder) {
cancelData := msg.Data.(*ebaiapi.CBUserCancelInfo)
afsOrder, err := partner.CurOrderManager.CreateAfsOrderFromOrder(utils.Int64ToStr(cancelData.OrderID), model.VendorIDEBAI)
if err == nil {
afsOrder.AfsOrderID = afsOrder.VendorOrderID
afsOrder.AfsCreatedAt = utils.Timestamp2Time(msg.Timestamp)
} else {
afsOrder = nil
}
return afsOrder
}
func (c *PurchaseHandler) convertAfsReasonType(vendorReasonType string) int8 {
return model.AfsReasonNotOthers
}
func (c *PurchaseHandler) GetAfsStatusFromVendorStatus4PartRefund(vendorStatus int) int {
return AfsVendorStatus2Status4PartRefundMap[vendorStatus]
}
func (c *PurchaseHandler) GetAfsStatusFromVendorStatus4ReverseRefund(vendorStatus int) int {
return AfsVendorStatus2Status4ReverseRefundMap[vendorStatus]
}
func (c *PurchaseHandler) GetAfsStatusFromVendorStatus4UserCancel(vendorStatus int) int {
return AfsVendorStatus2Status4UserCancel[vendorStatus]
}
func (c *PurchaseHandler) callbackAfsMsg2Status(msg *ebaiapi.CallbackMsg) (orderStatus *model.OrderStatus) {
if msg.Cmd == ebaiapi.CmdOrderPartRefund {
partRefundData := msg.Data.(*ebaiapi.CBPartRefundInfo)
orderStatus = &model.OrderStatus{
VendorOrderID: partRefundData.RefundID, // 是售后单ID不是订单ID订单ID在RefVendorOrderID中
VendorID: model.VendorIDEBAI,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: utils.Int64ToStr(partRefundData.OrderID),
RefVendorID: model.VendorIDEBAI,
VendorStatus: utils.Int2Str(partRefundData.Status),
Status: c.GetAfsStatusFromVendorStatus4PartRefund(partRefundData.Status),
StatusTime: utils.Timestamp2Time(msg.Timestamp),
Remark: buildFullReason(partRefundData.Reason, partRefundData.AdditionReason),
}
if orderStatus.Status == model.AfsOrderStatusWait4Approve && partRefundData.Type != ebaiapi.OrderPartRefuncTypeCustomer {
orderStatus.Status = model.AfsOrderStatusNew
}
} else if msg.Cmd == ebaiapi.CmdOrderReversePush {
partRefundData := msg.Data.(*ebaiapi.CBOrderReversePush)
orderStatus = &model.OrderStatus{
VendorOrderID: utils.Int64ToStr(partRefundData.RefundOrderId), // 是售后单ID不是订单ID订单ID在RefVendorOrderID中
VendorID: model.VendorIDEBAI,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: partRefundData.OrderId,
RefVendorID: model.VendorIDEBAI,
VendorStatus: utils.Int2Str(partRefundData.CurReverseEvent.RefundStatus),
Status: c.GetAfsStatusFromVendorStatus4ReverseRefund(partRefundData.CurReverseEvent.RefundStatus),
StatusTime: utils.Timestamp2Time(msg.Timestamp),
Remark: partRefundData.CurReverseEvent.RefundReasonDesc,
}
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel {
cancelData := msg.Data.(*ebaiapi.CBUserCancelInfo)
orderStatus = &model.OrderStatus{
VendorOrderID: utils.Int64ToStr(cancelData.OrderID), // 是售后单ID不是订单ID订单ID在RefVendorOrderID中
VendorID: model.VendorIDEBAI,
OrderType: model.OrderTypeAfsOrder,
RefVendorOrderID: utils.Int64ToStr(cancelData.OrderID),
RefVendorID: model.VendorIDEBAI,
VendorStatus: utils.Int2Str(cancelData.Type),
Status: c.GetAfsStatusFromVendorStatus4UserCancel(cancelData.Type),
StatusTime: utils.Timestamp2Time(msg.Timestamp),
Remark: buildFullReason(cancelData.CancelReason, cancelData.AdditionReason),
}
}
return orderStatus
}
// 审核售后单申请 退货退款
func (c *PurchaseHandler) AgreeOrRefuseRefund(ctx *jxcontext.Context, order *model.AfsOrder, approveType int, reason string) (err error) {
if globals.EnableEbaiStoreWrite {
param := &ebaiapi.RefundOrderExamine{
ReverseOrderId: order.AfsOrderID,
OrderId: order.VendorOrderID,
IdempotentId: utils.Int64ToStr(time.Now().UnixNano()),
ActionType: ebaiapi.RefundTypeRefuse,
ReasonCode: "7001",
ReasonRemarks: reason,
}
refundProductList := make([]*ebaiapi.RefundProductList, 0, 0)
date, _, _ := api.EbaiAPI.GetReverseOrder(order.VendorOrderID)
for _, v := range date {
v2 := v.(map[string]interface{})
refundProduct := &ebaiapi.RefundProductList{
SubBizOrderId: v2["sub_biz_order_id"].(string),
PlatformSkuId: utils.Int64ToStr(utils.Interface2Int64WithDefault(v2["platform_sku_id"], 0)),
}
if order.AfsOrderID == order.VendorOrderID {
param.ReverseOrderId = utils.Int64ToStr(utils.MustInterface2Int64(v2["refund_order_id"]))
}
switch utils.MustInterface2Int64(v2["fund_calculate_type"]) {
case 0:
refundProduct.Number = utils.Int64ToStr(utils.MustInterface2Int64(v2["refund_quantity"]))
case 1:
refundProduct.RefundAmount = utils.Int64ToStr(utils.MustInterface2Int64(v2["refund_user_amount"]))
}
refundProductList = append(refundProductList, refundProduct)
}
if approveType == partner.AfsApproveTypeRefused {
if reason == "" {
return fmt.Errorf("拒绝退单时请填写原因")
}
param.RefundProductList = refundProductList
err = api.EbaiAPI.OrderDisagreeReturnGoods(param)
} else if approveType == partner.AfsApproveTypeRefusedToRefundMoney {
return errors.New("此平台暂时不支持,退货转退款")
} else {
param.ActionType = ebaiapi.RefundTypeAgree
param.ReasonRemarks = reason
err = api.EbaiAPI.OrderAgreeReturnGoods(param)
}
}
return err
}
// 确认收到退货
func (c *PurchaseHandler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, order *model.AfsOrder) (err error) {
err = fmt.Errorf("内部错误,饿百平台不支持确认收到退货操作")
return err
}
// 发起全款退款
func (c *PurchaseHandler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
//售后退单 部分/全部
return c.PartRefundOrder(ctx, order, order.Skus, reason)
}
// 发起部分退款 售后/售中
func (c *PurchaseHandler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
if order.Status < model.OrderStatusEndBegin {
return fmt.Errorf("订单处于未结束状态,请稍后重试")
}
eabiApi := api.EbaiAPI
date, removerAll, err := api.EbaiAPI.GetReverseOrder(order.VendorOrderID)
if err != nil {
return err
}
//售后部分多次退款
if removerAll {
param := &ebaiapi.RefundOrderExamine{
ReverseOrderId: "",
OrderId: order.VendorOrderID,
IdempotentId: utils.Int64ToStr(time.Now().UnixNano()),
ActionType: ebaiapi.RefundTypeAgree,
ReasonCode: "",
ReasonRemarks: reason,
}
refundProductList := make([]*ebaiapi.RefundProductList, 0, 0)
if date != nil && len(date) != model.NO {
for _, v := range date {
v2 := v.(map[string]interface{})
refundProduct := &ebaiapi.RefundProductList{
SubBizOrderId: v2["sub_biz_order_id"].(string),
PlatformSkuId: utils.Int64ToStr(utils.Interface2Int64WithDefault(v2["platform_sku_id"], 0)),
}
param.ReverseOrderId = utils.Int64ToStr(utils.MustInterface2Int64(v2["refund_order_id"]))
switch utils.MustInterface2Int64(v2["fund_calculate_type"]) {
case 0:
refundProduct.Number = utils.Int64ToStr(utils.MustInterface2Int64(v2["refund_quantity"]))
case 1:
refundProduct.RefundAmount = utils.Int64ToStr(utils.MustInterface2Int64(v2["refund_user_amount"]))
}
refundProductList = append(refundProductList, refundProduct)
}
param.RefundProductList = refundProductList
}
err = eabiApi.OrderAgreePartRefund(param)
} else {
orderDetail, err := eabiApi.OrderGet2(order.VendorOrderID)
if err != nil {
return err
}
skuList2 := make([]*ebaiapi.RefundProductListParam, 0, 0)
for _, r := range refundSkuList {
for _, v := range orderDetail.Products[0] {
if utils.Int2Str(jxutils.GetSkuIDFromOrderSku(r)) == v.CustomSkuID || r.VendorSkuID == v.BaiduProductID {
skuList2 = append(skuList2, &ebaiapi.RefundProductListParam{
SubBizOrderId: v.SubBizOrderID,
PlatformSkuId: v.BaiduProductID,
Number: utils.Int2Str(r.Count),
RefundAmount: "",
FundCalculateType: "0",
})
}
}
}
// 部分退款
err = eabiApi.OrderReverseApply(&ebaiapi.OrderReverseApplyParam{
OrderId: order.VendorOrderID,
IdempotentId: utils.Int64ToStr(time.Now().Unix()),
RefundType: ebaiapi.MerchantOrderReverseApplyPartCancel,
ReasonCode: "7015",
ReasonRemarks: reason,
NeedIvrUser: 1,
RefundProductList: skuList2,
})
//if reason == "" {
// return fmt.Errorf("拒绝退单时,请填写拒单原因")
//}
//if err := api.EbaiAPI.OrderPartRefund(order.VendorOrderID, orderSkus2AfsSkus(refundSkuList)); err != nil {
// return err
//}
}
return err
}
func orderSkus2AfsSkus(refundSkuList []*model.OrderSku) (removeSkuList []*ebaiapi.RefundSku) {
for _, v := range refundSkuList {
refundSku := &ebaiapi.RefundSku{
CustomeSkuID: utils.Int2Str(v.SkuID),
Number: utils.Int2Str(v.Count),
}
removeSkuList = append(removeSkuList, refundSku)
}
return removeSkuList
}
func (c *PurchaseHandler) GetOrderAfsInfo(ctx *jxcontext.Context, vendorOrderID, afsOrderID string) (orderAfsInfo *partner.OrderAfsInfo, err error) {
orderAfsInfo = &partner.OrderAfsInfo{}
result, _, err := api.EbaiAPI.GetReverseOrder(vendorOrderID)
if err == nil {
orderAfsInfo.VendorOrderID = vendorOrderID
var afsTotalShopMoney int64 = 0
for _, v := range result {
v2 := v.(map[string]interface{})
afsTotalShopMoney += utils.MustInterface2Int64(v2["refund_user_amount"])
}
orderAfsInfo.AfsTotalShopMoney = afsTotalShopMoney
}
return orderAfsInfo, err
//orderAfsInfo = &partner.OrderAfsInfo{}
//if result, err := api.EbaiAPI.OrderPartRefundGet(vendorOrderID) ;err == nil {
// orderAfsInfo.VendorOrderID = vendorOrderID
// orderAfsInfo.AfsTotalShopMoney = utils.MustInterface2Int64(result["shop_fee"])
//}
//return orderAfsInfo, err
}