273 lines
12 KiB
Go
273 lines
12 KiB
Go
package ebai
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
|
||
"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, // 是否是中间状态
|
||
}
|
||
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 {
|
||
if msg.Cmd == ebaiapi.CmdOrderPartRefund {
|
||
msgType := int(utils.MustInterface2Int64(msg.Body["type"]))
|
||
return msgType == ebaiapi.OrderPartRefuncTypeCustomer || msgType == ebaiapi.OrderPartRefuncTypeCS
|
||
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel {
|
||
cancelType := int(utils.MustInterface2Int64(msg.Body["cancel_type"]))
|
||
return cancelType == ebaiapi.OrderUserCancelTypeAfterSale
|
||
}
|
||
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.Status == model.AfsOrderStatusWait4Approve || orderStatus.Status == model.AfsOrderStatusNew {
|
||
var afsOrder *model.AfsOrder
|
||
if msg.Cmd == ebaiapi.CmdOrderPartRefund {
|
||
partRefundData := msg.Data.(*ebaiapi.CBPartRefundInfo)
|
||
afsOrder = &model.AfsOrder{
|
||
VendorID: model.VendorIDEBAI,
|
||
AfsOrderID: orderStatus.VendorOrderID,
|
||
VendorOrderID: orderStatus.RefVendorOrderID,
|
||
VendorStoreID: "",
|
||
StoreID: 0,
|
||
AfsCreatedAt: utils.Timestamp2Time(msg.Timestamp),
|
||
VendorAppealType: "",
|
||
AppealType: model.AfsAppealTypeRefund,
|
||
VendorReasonType: partRefundData.ReasonType,
|
||
ReasonType: c.convertAfsReasonType(partRefundData.ReasonType),
|
||
ReasonDesc: utils.LimitUTF8StringLen(buildFullReason(partRefundData.Reason, partRefundData.AdditionReason), 1024),
|
||
ReasonImgList: utils.LimitUTF8StringLen(strings.Join(partRefundData.Photos, ","), 1024),
|
||
RefundType: model.AfsTypePartRefund,
|
||
|
||
VendorOrgCode: msg.Source,
|
||
// FreightUserMoney: afsInfo.OrderFreightMoney,
|
||
// AfsFreightMoney: afsInfo.AfsFreight,
|
||
// BoxMoney: afsInfo.PackagingMoney,
|
||
// TongchengFreightMoney: afsInfo.TongchengFreightMoney,
|
||
// SkuBoxMoney: afsInfo.MealBoxMoney,
|
||
}
|
||
for _, sku := range partRefundData.RefundProducts {
|
||
orderSku := &model.OrderSkuFinancial{
|
||
// VendorID: model.VendorIDEBAI,
|
||
// AfsOrderID: afsOrder.AfsOrderID,
|
||
// VendorOrderID: afsOrder.VendorOrderID,
|
||
// VendorStoreID: afsOrder.VendorStoreID,
|
||
// StoreID: afsOrder.StoreID,
|
||
// IsAfsOrder: 1,
|
||
|
||
Count: sku.Number,
|
||
// ConfirmTime: afsOrder.AfsCreateAt,
|
||
VendorSkuID: sku.SkuID,
|
||
SkuID: int(utils.Str2Int64WithDefault(sku.CustomSkuID, 0)),
|
||
Name: sku.Name,
|
||
UserMoney: sku.TotalRefund,
|
||
PmSkuSubsidyMoney: sku.ShopEleRefund,
|
||
}
|
||
afsOrder.SkuUserMoney += orderSku.UserMoney
|
||
afsOrder.PmSubsidyMoney += orderSku.PmSubsidyMoney
|
||
afsOrder.Skus = append(afsOrder.Skus, orderSku)
|
||
}
|
||
} else if msg.Cmd == ebaiapi.CmdOrderUserCancel {
|
||
if afsOrder = c.createAfsOrder(msg); afsOrder != nil {
|
||
// if orderFinancial, err2 := partner.CurOrderManager.LoadOrderFinancial(orderStatus.RefVendorOrderID, model.VendorIDEBAI); err2 == nil {
|
||
// afsOrder = c.OrderFinancialDetail2Refund(orderFinancial, msg)
|
||
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 {
|
||
if afsOrder2, err := partner.CurOrderManager.LoadAfsOrder(orderStatus.VendorOrderID, orderStatus.VendorID); afsOrder2 == nil && err == nil {
|
||
partRefundData := msg.Data.(*ebaiapi.CBPartRefundInfo)
|
||
afsOrder := &model.AfsOrder{
|
||
VendorID: model.VendorIDEBAI,
|
||
AfsOrderID: orderStatus.VendorOrderID,
|
||
VendorOrderID: orderStatus.RefVendorOrderID,
|
||
VendorStoreID: "",
|
||
StoreID: 0,
|
||
AfsCreatedAt: utils.Timestamp2Time(msg.Timestamp),
|
||
VendorAppealType: "",
|
||
AppealType: model.AfsAppealTypeRefund,
|
||
VendorReasonType: partRefundData.ReasonType,
|
||
ReasonType: c.convertAfsReasonType(partRefundData.ReasonType),
|
||
ReasonDesc: utils.LimitUTF8StringLen(buildFullReason(partRefundData.Reason, partRefundData.AdditionReason), 1024),
|
||
ReasonImgList: utils.LimitUTF8StringLen(strings.Join(partRefundData.Photos, ","), 1024),
|
||
RefundType: model.AfsTypePartRefund,
|
||
VendorOrgCode: msg.Source,
|
||
}
|
||
for _, sku := range partRefundData.RefundProducts {
|
||
orderSku := &model.OrderSkuFinancial{
|
||
Count: sku.Number,
|
||
VendorSkuID: sku.SkuID,
|
||
SkuID: int(utils.Str2Int64WithDefault(sku.CustomSkuID, 0)),
|
||
Name: sku.Name,
|
||
UserMoney: sku.TotalRefund,
|
||
PmSkuSubsidyMoney: sku.ShopEleRefund,
|
||
}
|
||
afsOrder.SkuUserMoney += orderSku.UserMoney
|
||
afsOrder.PmSubsidyMoney += orderSku.PmSubsidyMoney
|
||
afsOrder.Skus = append(afsOrder.Skus, orderSku)
|
||
}
|
||
if afsOrder != nil {
|
||
err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus)
|
||
}
|
||
} else {
|
||
err = partner.CurOrderManager.OnAfsOrderStatusChanged(orderStatus)
|
||
}
|
||
}
|
||
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) 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.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 {
|
||
if approveType == partner.AfsApproveTypeRefused {
|
||
err = api.EbaiAPI.OrderDisagreeRefund(order.VendorOrderID, reason)
|
||
} else {
|
||
err = api.EbaiAPI.OrderAgreeRefund(order.VendorOrderID)
|
||
}
|
||
}
|
||
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 globals.EnableEbaiStoreWrite {
|
||
err = api.EbaiAPI.OrderPartRefund(order.VendorOrderID, orderSkus2AfsSkus(refundSkuList))
|
||
}
|
||
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{}
|
||
if result, err := api.EbaiAPI.OrderPartRefundGet(vendorOrderID); err == nil {
|
||
orderAfsInfo.VendorOrderID = vendorOrderID
|
||
orderAfsInfo.AfsTotalShopMoney = utils.MustInterface2Int64(result["shop_fee"])
|
||
}
|
||
return orderAfsInfo, err
|
||
}
|