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.Status == model.AfsOrderStatusWait4Approve || orderStatus.Status == model.AfsOrderStatusNew { var afsOrder *model.AfsOrder if msg.Cmd == ebaiapi.CmdOrderPartRefund { 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, _ := partner.CurOrderManager.LoadAfsOrder(orderStatus.VendorOrderID, orderStatus.VendorID) if afsOrder2 == nil && msg.Cmd == ebaiapi.CmdOrderPartRefund { afsOrder := c.makeAfsOrderInfoPartRefund(msg, orderStatus) if afsOrder != nil { err = partner.CurOrderManager.OnAfsOrderNew(afsOrder, orderStatus) } } else if afsOrder2 == nil && msg.Cmd == ebaiapi.CmdOrderReversePush { afsOrder, _ := c.makeAfsOrderInfoReverseRefund(msg, orderStatus) 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为扣点 var earningPrice int64 = 0 for _, v := range goodsOrder.Skus { if goodsOrder.EarningType == model.EarningTypeQuote { earningPrice += v.ShopPrice * int64(v.Count) } else { earningPrice += v.SalePrice * int64(v.Count) } } goodsOrder.EarningPrice = earningPrice afsSkuList, _ := dao.GetOrderRefundSkuList(db, []string{goodsOrder.VendorOrderID}) 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, err := partner.CurOrderManager.LoadAfsOrder(orderStatus.VendorOrderID, 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") } if orderStatus.Status == model.AfsOrderStatusFinished { goodsOrder, _ := partner.CurOrderManager.LoadOrder(orderStatus.RefVendorOrderID, model.VendorIDEBAI) afsSkuList, _ := dao.GetOrderRefundSkuList(db, []string{goodsOrder.VendorOrderID}) var afsSku int = 0 for _, v := range afsSkuList { afsSku += v.Count } if afsSku == goodsOrder.GoodsCount && goodsOrder.GoodsCount != 0 { goodsOrder.Status = model.OrderStatusCanceled goodsOrder.VendorStatus = orderStatus.VendorStatus dao.UpdateEntity(db, goodsOrder, "Status", "VendorStatus") } } 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 }