package ebai import ( "fmt" "math" "strings" "time" beego "github.com/astaxie/beego/server/web" "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" "git.rosy.net.cn/baseapi/platformapi/ebaiapi" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" "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/model/dao" "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" ) const ( // acceptOrderDelay = 180 * time.Second // pickupOrderDelay = 260 * time.Second pickupOrderDelay = 1 * time.Minute callDeliveryDelay = 10 * time.Minute callDeliveryDelayGap = 30 fakeAcceptOrder = "fake_accept_order" fakeOrderAdjustFinished = "fake_order_adjust_finished" fakeOrderCanceled = "fake_order_canceled" ) // 饿百的接单会直接召唤配送,为了统一将饿百的接单影射成拣货完成,然后模拟一个接单消息 var ( VendorStatus2StatusMap = map[string]int{ ebaiapi.CmdOrderCreate: model.OrderStatusWaitAccepted, ebaiapi.OrderStatusNew: model.OrderStatusWaitAccepted, fakeAcceptOrder: model.OrderStatusAccepted, ebaiapi.OrderStatusAccepted: model.OrderStatusFinishedPickup, ebaiapi.OrderStatusCourierAccepted: model.OrderStatusDelivering, ebaiapi.OrderStatusCourierPickedup: model.OrderStatusDelivering, ebaiapi.OrderStatusFinished: model.OrderStatusFinished, ebaiapi.OrderStatusCanceled: model.OrderStatusCanceled, fakeOrderAdjustFinished: model.OrderStatusAdjust, fakeOrderCanceled: model.OrderStatusCanceled, } skuActTypeMap = map[string]int{ ebaiapi.OrderSkuDiscountTypeZhe: 1, ebaiapi.OrderSkuDiscountTypeReduce: 1, ebaiapi.OrderSkuDiscountTypeTe: 1, } deliveryTypeMap = map[int]string{ ebaiapi.DeliveryPartyFengElmSelf: model.OrderDeliveryTypeStoreSelf, } ) func mapDeliveryType(ebaiDeliveryParty int, businessType int) (deliveryType string) { if businessType == ebaiapi.DeliveryBusinessTypeZT { return model.OrderDeliveryTypeSelfTake } else { deliveryType = deliveryTypeMap[ebaiDeliveryParty] if deliveryType == "" { deliveryType = model.OrderDeliveryTypePlatform } } return deliveryType } func (p *PurchaseHandler) getStatusFromVendorStatus(vendorStatus string) int { if status, ok := VendorStatus2StatusMap[vendorStatus]; ok { return status } return model.OrderStatusUnknown } func (p *PurchaseHandler) GetOrder(vendorOrgCode, vendorOrderID, vendorStoreID string) (order *model.GoodsOrder, err error) { order, _, err = p.getOrder(vendorOrderID) return order, err } func (p *PurchaseHandler) GetOrderStatus(vendorOrgCode, vendorOrderID string) (status int, err error) { status, err = api.EbaiAPI.OrderStatusGet(vendorOrderID) if err == nil { status = p.getStatusFromVendorStatus(utils.Int2Str(status)) } return status, err } func (p *PurchaseHandler) getOrder(vendorOrderID string) (order *model.GoodsOrder, orderMap map[string]interface{}, err error) { for i := 0; i < 2; i++ { orderMap, err = api.EbaiAPI.OrderGet(vendorOrderID) if err == nil { order = p.Map2Order(orderMap) // 饿百订单有时会出现取不到baidu_shop_id的情况,重试 if order.VendorStoreID != "" { break } } time.Sleep(100 * time.Millisecond) } return order, orderMap, err } func (p *PurchaseHandler) GetOrder4PartRefund(vendorOrderID string) (order *model.GoodsOrder, err error) { taskIDs := []int{1, 2} var ( err1, err2 error result1, result2 map[string]interface{} ) task := tasksch.NewParallelTask("GetOrder4PartRefund", nil, jxcontext.AdminCtx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { taskID := batchItemList[0].(int) if taskID == 1 { result1, err1 = api.EbaiAPI.OrderGet(vendorOrderID) } else if taskID == 2 { result2, err2 = api.EbaiAPI.OrderPartRefundGet(vendorOrderID) } return nil, nil }, taskIDs) task.Run() task.GetResult(0) if err1 == nil { order = p.Map2Order(result1) if err2 == nil { order.Skus = p.partRefund2OrderDetailSkuList(utils.Interface2String(result2["order_id"]), result2["order_detail"]) giftSkus, discountMoney := getZengSkus(vendorOrderID, result1) order.DiscountMoney = discountMoney order.Skus = append(order.Skus, giftSkus...) order.ActualPayPrice = utils.MustInterface2Int64(result2["user_fee"]) order.TotalShopMoney = utils.MustInterface2Int64(result2["shop_fee"]) jxutils.RefreshOrderSkuRelated(order) } else if err2Ext, ok := err2.(*utils.ErrorWithCode); !ok || err2Ext.IntCode() != ebaiapi.ErrOrderIsNotPartRefund { err = err2 } } else { err = err1 } return order, err } func getZengSkus(orderID string, orderMan map[string]interface{}) (skus []*model.OrderSku, discountMoney int64) { discounts, _ := orderMan["discount"].([]interface{}) for _, v := range discounts { discount := v.(map[string]interface{}) discountType := utils.Interface2String(discount["type"]) if discountType == ebaiapi.OrderSkuDiscountTypeZeng { sku := &model.OrderSku{ VendorOrderID: orderID, VendorID: model.VendorIDEBAI, Count: 1, SkuID: 0, VendorSkuID: "", SkuName: utils.Interface2String(discount["desc"]), VendorPrice: 0, } skus = append(skus, sku) } discountMoney += utils.Interface2Int64WithDefault(discount["fee"], 0) } return skus, discountMoney } func (p *PurchaseHandler) partRefund2OrderDetailSkuList(orderID string, orderDetail2 interface{}) (skuList []*model.OrderSku) { orderDetail := orderDetail2.([]interface{}) for _, product2 := range orderDetail { product := product2.(map[string]interface{}) skuName := product["name"].(string) _, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(skuName) number := int(utils.MustInterface2Int64(product["number"])) sku := &model.OrderSku{ VendorOrderID: orderID, VendorID: model.VendorIDEBAI, Count: number, SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product[ebaiapi.KeyCustomSkuID]), 0)), VendorSkuID: utils.Interface2String(product[ebaiapi.KeySkuID]), SkuName: skuName, // Weight: int(utils.Interface2Int64WithDefault(product["total_weight"], 0)) / number, // 退单这里的total_weight有BUG,这里的total_weight还是没有退单时的值 VendorPrice: utils.MustInterface2Int64(product["product_price"]), } sku.SalePrice, _, sku.StoreSubName = getSkuSalePrice(product) if sku.Weight == 0 { sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit) // 订单信息里没有重量,只有名字里尝试找 } skuList = append(skuList, sku) } return skuList } func getExpectedDeliveredTime(orderMap map[string]interface{}) (expectedTime time.Time) { expectedTime = getTimeFromInterface(orderMap["latest_send_time"]) if utils.IsTimeZero(expectedTime) { expectedTime = getTimeFromInterface(orderMap["send_time"]) } return expectedTime } func (p *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) { result := orderData shopMap := result["shop"].(map[string]interface{}) orderMap := result["order"].(map[string]interface{}) userMap := result["user"].(map[string]interface{}) vendorOrderID := orderMap["order_id"].(string) order = &model.GoodsOrder{ VendorOrderID: vendorOrderID, VendorOrderID2: utils.Interface2String(orderMap["eleme_order_id"]), VendorID: model.VendorIDEBAI, VendorStoreID: utils.Interface2String(shopMap["baidu_shop_id"]), StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(shopMap["id"]), 0)), StoreName: utils.Interface2String(shopMap["name"]), VendorUserID: utils.Interface2String(userMap["user_id"]), ConsigneeName: utils.Interface2String(userMap["name"]), ConsigneeMobile: jxutils.FormalizeMobile(utils.Interface2String(userMap["phone"])), ConsigneeAddress: utils.Interface2String(userMap["address"]), CoordinateType: model.CoordinateTypeMars, BuyerComment: utils.TrimBlankChar(utils.Interface2String(orderMap["remark"])), ExpectedDeliveredTime: getExpectedDeliveredTime(orderMap), PickDeadline: utils.DefaultTimeValue, VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(orderMap["status"])), OrderSeq: int(utils.ForceInterface2Int64(orderMap["order_index"])), StatusTime: getTimeFromInterface(orderMap["create_time"]), OrderCreatedAt: getTimeFromInterface(orderMap["create_time"]), // OrderFinishedAt: getTimeFromInterface(orderMap["finished_time"]), OriginalData: string(utils.MustMarshal(result)), ActualPayPrice: utils.ForceInterface2Int64(orderMap["user_fee"]), BaseFreightMoney: utils.ForceInterface2Int64(orderMap["send_fee"]), TotalShopMoney: utils.ForceInterface2Int64(orderMap["shop_fee"]), DeliveryType: mapDeliveryType(int(utils.ForceInterface2Int64(orderMap["delivery_party"])), int(utils.ForceInterface2Int64(orderMap["business_type"]))), InvoiceTitle: utils.Interface2String(orderMap["invoice_title"]), InvoiceTaxerID: utils.Interface2String(orderMap["taxer_id"]), InvoiceEmail: jxutils.GetOneEmailFromStr(utils.Interface2String(orderMap["remark"])), VendorOrgCode: utils.Interface2String(result["source"]), } finishTime := getTimeFromInterface(orderMap["finished_time"]) if finishTime == utils.ZeroTimeValue { order.OrderFinishedAt = utils.DefaultTimeValue } else { order.OrderFinishedAt = finishTime } if utils.IsTimeZero(order.PickDeadline) && !utils.IsTimeZero(order.StatusTime) { order.PickDeadline = order.StatusTime.Add(pickupOrderDelay) // 饿百要求在5分钟内拣货,不然订单会被取消 } if order.ConsigneeMobile == "" { if mobileInfo, err := api.EbaiAPI.OrderPrivateInfo(vendorOrderID); err == nil { order.ConsigneeMobile = jxutils.FormalizeMobile(mobileInfo.ShortNumber) } } if order.StoreID > math.MaxInt32 { order.StoreID = 0 } order.Status = p.getStatusFromVendorStatus(order.VendorStatus) if utils.MustInterface2Int64(orderMap["send_immediately"]) == 1 { order.BusinessType = model.BusinessTypeImmediate } else { order.BusinessType = model.BusinessTypeDingshida if utils.IsTimeZero(order.ExpectedDeliveredTime) { order.ExpectedDeliveredTime = getTimeFromInterface(orderMap["latest_send_time"]) } } deliveryGeo := userMap["coord_amap"].(map[string]interface{}) originalLng := utils.Interface2Float64WithDefault(deliveryGeo["longitude"], 0.0) // 饿百的订单在过一段时间后,经纬度信息会变成字符串"**" originalLat := utils.Interface2Float64WithDefault(deliveryGeo["latitude"], 0.0) // lng, lat, err2 := api.AutonaviAPI.CoordinateConvert(originalLng, originalLat, autonavi.CoordSysBaidu) // if err2 == nil { // originalLng = lng // originalLat = lat // order.CoordinateType = model.CoordinateTypeMars // } order.ConsigneeLng = jxutils.StandardCoordinate2Int(originalLng) order.ConsigneeLat = jxutils.StandardCoordinate2Int(originalLat) products := result["products"].([]interface{})[0].([]interface{}) for _, product2 := range products { product := product2.(map[string]interface{}) skuName := product["product_name"].(string) _, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(skuName) productAmount := int(utils.MustInterface2Int64(product["product_amount"])) sku := &model.OrderSku{ VendorOrderID: order.VendorOrderID, VendorID: model.VendorIDEBAI, Count: productAmount, SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product[ebaiapi.KeyCustomSkuID]), 0)), VendorSkuID: utils.Interface2String(product["baidu_product_id"]), SkuName: skuName, Weight: int(utils.Interface2Int64WithDefault(product["total_weight"], 0)) / productAmount, VendorPrice: utils.MustInterface2Int64(product["product_price"]), } var baiduRate int64 sku.SalePrice, baiduRate, sku.StoreSubName = getSkuSalePrice(product) order.PmSubsidyMoney += baiduRate if sku.Weight == 0 { sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit) // 订单信息里没有重量,只有名字里尝试找 } // if product["isGift"].(bool) { // sku.SkuType = 1 // } order.Skus = append(order.Skus, sku) } giftSkus, discountMoney := getZengSkus(vendorOrderID, orderData) order.DiscountMoney = discountMoney order.Skus = append(order.Skus, giftSkus...) jxutils.RefreshOrderSkuRelated(order) return order } func getSkuSalePrice(product map[string]interface{}) (salePrice, baiduRate int64, vendorActType string) { var product2 *ebaiapi.OrderProductInfo if err := utils.Map2StructByJson(product, &product2, true); err != nil { return utils.MustInterface2Int64(product["product_price"]), 0, "" } return getSkuSalePrice2(product2) } func getSkuSalePrice2(product *ebaiapi.OrderProductInfo) (salePrice, baiduRate int64, vendorActType string) { salePrice = int64(product.ProductPrice) if product.ProductSubsidy != nil { for _, v := range product.ProductSubsidy.DiscountDetail { if skuActTypeMap[v.Type] == 1 { skuCount := product.ProductAmount if skuCount == 0 { skuCount = product.Number } salePrice -= int64(math.Round(float64(v.BaiduRate+v.ShopRate) / float64(skuCount))) // 饿百同一SKU的优惠与非优惠没有拆开,平均摊销处理 vendorActType = v.Type } baiduRate += int64(v.BaiduRate) } } return salePrice, baiduRate, vendorActType } func (p *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) { globals.SugarLogger.Debugf("ebai AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt) if isAcceptIt { if globals.EnableEbaiStoreWrite { err = api.EbaiAPI.OrderConfirm(order.VendorOrderID) if beego.BConfig.RunMode == "jxgy" { utils.AfterFuncWithRecover(time.Minute*10, func() { err = api.EbaiAPI.OrderPickComplete(order.VendorOrderID) }) } else { utils.AfterFuncWithRecover(time.Minute, func() { err = api.EbaiAPI.OrderPickComplete(order.VendorOrderID) }) } } p.postFakeMsg(order.VendorOrderID, fakeAcceptOrder) } else { if globals.EnableEbaiStoreWrite { err = api.EbaiAPI.OrderCancel(order.VendorOrderID, ebaiapi.CancelTypeCustom, "bu") } } return err } func (p *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) { globals.SugarLogger.Debugf("ebai PickupGoods orderID:%s, isSelfDelivery:%t", order.VendorOrderID, isSelfDelivery) if globals.EnableEbaiStoreWrite { // err = api.EbaiAPI.OrderPickComplete(order.VendorOrderID) } if err == nil { p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusAccepted) } return err } func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) { return err } func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送 return err } func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货 return err } // 将订单从购物平台配送转为自送 func (p *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Debugf("ebai Swtich2SelfDeliver orderID:%s", order.VendorOrderID) if globals.EnableEbaiStoreWrite { if err = api.EbaiAPI.OrderSwitchselfdelivery(order.VendorOrderID); err != nil { if utils.IsErrMatch(err, "301251", nil) { if deliveryStatus, err2 := api.EbaiAPI.OrderDeliveryGet(order.VendorOrderID); err2 == nil { deliveryStatus := utils.Int64ToStr(utils.MustInterface2Int64(deliveryStatus["status"])) if deliveryStatus == ebaiapi.WaybillStatusSelfDelivery { err = nil } else if deliveryStatus == ebaiapi.WaybillStatusDeliveryCancled { p.trySyncCancelStatus(order.VendorOrderID) } } } } } if err == nil { // 饿百不会发送配送中,模拟发送 p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusCourierAccepted) } return err } func (p *PurchaseHandler) trySyncCancelStatus(vendorOrderID string) (err error) { orderInfo, err := api.EbaiAPI.OrderGet2(vendorOrderID) if err == nil { if utils.Int2Str(orderInfo.Order.Status) == ebaiapi.OrderStatusCanceled { p.postFakeMsg(vendorOrderID, fakeOrderCanceled) } } return err } // 将订单从购物平台配送转为自送后又送达 func (p *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Debugf("ebai Swtich2SelfDelivered orderID:%s", order.VendorOrderID) // todo 饿百转商家自送后,没有确认送达的概念,空操作 return err } // 完全自送的门店表示开始配送 func (p *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Debugf("ebai SelfDeliverDelivering orderID:%s", order.VendorOrderID) if globals.EnableEbaiStoreWrite { err = api.EbaiAPI.OrderSendOut(order.VendorOrderID, userName) } if err == nil { // 饿百不会发送配送中,模拟发送 p.postFakeMsg(order.VendorOrderID, ebaiapi.OrderStatusCourierAccepted) } return err } // 完全自送的门店表示配送完成 func (p *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Debugf("ebai SelfDeliverDelivered orderID:%s", order.VendorOrderID) if globals.EnableEbaiStoreWrite { err = api.EbaiAPI.OrderComplete(order.VendorOrderID, userName) } return err } // func (c *PurchaseHandler) onOrderMsg(msg *ebaiapi.CallbackMsg) (retVal *ebaiapi.CallbackResponse) { if c.isAfsMsg(msg) { retVal = c.onAfsOrderMsg(msg) } else { status := c.callbackMsg2Status(msg) if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 0 { return nil } if ebaiapi.CmdOrderCreate == msg.Cmd { retVal = c.onOrderNew(msg, status) } else { var err error if status != nil { if status.Status == model.OrderStatusAdjust { var order *model.GoodsOrder if order, err = c.GetOrder4PartRefund(GetOrderIDFromMsg(msg)); err == nil { err = partner.CurOrderManager.OnOrderAdjust(order, status) } } else { // 处理饿百降级订单的情况 // 是否降级;1:是,0:否;极少数订单因网络或信息交互异常,导致订单部分字段(如订单金额)生成延迟,此时订单会被标记为“已降级”状态,需开发者重新调用查看订单详情接口获取完整订单数据。 // toto sku是否也需要处理? if status.Status == model.OrderStatusDelivering || status.Status == model.OrderStatusFinished { if order, err2 := partner.CurOrderManager.LoadOrder(status.VendorOrderID, status.VendorID); err2 == nil { if order.TotalShopMoney == 0 { if order2, err2 := c.GetOrder(msg.Source, status.VendorOrderID, ""); err2 == nil { order.TotalShopMoney = order2.TotalShopMoney order.PmSubsidyMoney = order2.PmSubsidyMoney partner.CurOrderManager.UpdateOrderFields(order, []string{"TotalShopMoney", "PmSubsidyMoney"}) } } } } err = partner.CurOrderManager.OnOrderStatusChanged(msg.Source, status) } } retVal = api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, nil) } } return retVal } func (c *PurchaseHandler) onOrderNew(msg *ebaiapi.CallbackMsg, orderStatus *model.OrderStatus) (response *ebaiapi.CallbackResponse) { vendorOrderID := GetOrderIDFromMsg(msg) order, orderMap, err := c.getOrder(vendorOrderID) if err == nil { // 饿百订单有时会出现取不到baidu_shop_id的情况,返回错误让服务器重试 if order.VendorStoreID == "" { return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, fmt.Errorf("订单%s的baidu_shop_id为空", order.VendorOrderID), "") } if err = partner.CurOrderManager.OnOrderNew(order, orderStatus); err == nil { utils.CallFuncAsync(func() { c.OnOrderDetail(orderMap, partner.CreatedPeration) }) } } return api.EbaiAPI.Err2CallbackResponse(msg.Cmd, err, map[string]interface{}{ "source_order_id": vendorOrderID, }) } func (c *PurchaseHandler) callbackMsg2Status(msg *ebaiapi.CallbackMsg) (orderStatus *model.OrderStatus) { orderID := GetOrderIDFromMsg(msg) orderStatus = &model.OrderStatus{ VendorOrderID: orderID, VendorID: model.VendorIDEBAI, OrderType: model.OrderTypeOrder, RefVendorOrderID: orderID, RefVendorID: model.VendorIDEBAI, StatusTime: utils.Timestamp2Time(msg.Timestamp), VendorStatus: msg.Cmd, } if msg.Cmd == ebaiapi.CmdOrderUserCancel { msgType := int(utils.MustInterface2Int64(msg.Body["type"])) cancelType := int(utils.MustInterface2Int64(msg.Body["cancel_type"])) orderStatus.Remark = buildFullReason(utils.Interface2String(msg.Body["cancel_reason"]), utils.Interface2String(msg.Body["addition_reason"])) orderStatus.VendorStatus = msg.Cmd + "-" + utils.Int2Str(msgType) if cancelType == ebaiapi.OrderUserCancelTypeBeforeSale { if msgType == ebaiapi.OrderUserCancelApply /* || msgType == ebaiapi.OrderUserCancelCSIntervene */ { orderStatus.Status = model.OrderStatusApplyCancel } else if msgType == ebaiapi.OrderUserCancelCSRefused || msgType == ebaiapi.OrderUserCancelMerchantRefused { orderStatus.Status = model.OrderStatusVendorRejectCancel } else if msgType == ebaiapi.OrderUserCancelInvalid { orderStatus.Status = model.OrderStatusUndoApplyCancel } else if msgType == ebaiapi.OrderUserCancelCSAgreed || msgType == ebaiapi.OrderUserCancelMerchantAgreed { orderStatus.Status = model.OrderStatusVendorAgreeCancel } } } else if msg.Cmd == ebaiapi.CmdOrderPartRefund { msgType := int(utils.MustInterface2Int64(msg.Body["type"])) status := int(utils.MustInterface2Int64(msg.Body["status"])) orderStatus.Remark = buildFullReason(utils.Interface2String(msg.Body["reason"]), utils.Interface2String(msg.Body["addition_reason"])) if msgType == ebaiapi.OrderPartRefuncTypeMerchant && status == ebaiapi.OrderPartRefundSuccess { orderStatus.VendorStatus = fakeOrderAdjustFinished } } else if status, ok := msg.Body["status"]; ok { if vendorStatus, ok := status.(string); ok { orderStatus.VendorStatus = vendorStatus } else { orderStatus.VendorStatus = utils.Int64ToStr(utils.MustInterface2Int64(status)) } orderStatus.Remark = utils.Interface2String(msg.Body["reason"]) } if orderStatus.Status == 0 { orderStatus.Status = c.getStatusFromVendorStatus(orderStatus.VendorStatus) } return orderStatus } func buildFullReason(reason, addReason string) (fullReason string) { fullReason = reason if addReason != "" { fullReason += ",额外原因:" + addReason } return fullReason } func (c *PurchaseHandler) GetStatusActionTimeout(order *model.GoodsOrder, statusType, status int) (params *partner.StatusActionParams) { if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusAccepted { params = &partner.StatusActionParams{ // PickDeadline没有设置时才有效,饿百要求在5分钟内拣货,不然订单会被取消 Timeout: pickupOrderDelay, } } else if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusFinishedPickup { params = &partner.StatusActionParams{ // 立即达订单有效,自配送延时召唤配送 Timeout: callDeliveryDelay, TimeoutGap: callDeliveryDelayGap, } } return params } func (c *PurchaseHandler) getOrderStoreDeliveryType(order *model.GoodsOrder) (deliveryType int) { sql := ` SELECT * FROM store_map t1 WHERE t1.vendor_store_id = ? AND t1.vendor_id = ? AND t1.deleted_at = ? ` db := dao.GetDB() var storeMap *model.StoreMap if err := dao.GetRow(db, &storeMap, sql, order.VendorStoreID, model.VendorIDEBAI, utils.DefaultTimeValue); err == nil { return int(storeMap.DeliveryType) } else if !dao.IsNoRowsError(err) { globals.SugarLogger.Warnf("getOrderStoreDeliveryType orderID:%s failed with error:%v", order.VendorOrderID, err) } return scheduler.StoreDeliveryTypeByPlatform } func (c *PurchaseHandler) postFakeMsg(vendorOrderID, vendorStatus string) { msg := &ebaiapi.CallbackMsg{ Cmd: ebaiapi.CmdOrderStatus, Timestamp: time.Now().Unix(), Body: map[string]interface{}{ "status": vendorStatus, "order_id": vendorOrderID, }, } utils.CallFuncAsync(func() { OnCallbackMsg(msg) }) } func getTimeFromInterface(timeValue interface{}) time.Time { var timeStamp int64 if timeStr, ok := timeValue.(string); ok { timeStamp = utils.Str2Int64WithDefault(timeStr, 0) } else { timeStamp = utils.Interface2Int64WithDefault(timeValue, 0) } if timeStamp < 1538103149 { // 立即达订单给的是1(而不是空,0),1538103149不是特殊值,只是一个任意之前的时间,这样写可以处理 return utils.DefaultTimeValue } return utils.Timestamp2Time(timeStamp) } func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) { mobile, err = api.EbaiAPI.GetRealMobile4Order(order.VendorOrderID) return mobile, err } func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) { if globals.EnableEbaiStoreWrite { if isAgree { err = api.EbaiAPI.OrderAgreeRefund(order.VendorOrderID) } else { err = api.EbaiAPI.OrderDisagreeRefund(order.VendorOrderID, reason) } } return err } func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) { if globals.EnableEbaiStoreWrite { err = api.EbaiAPI.OrderCancel(order.VendorOrderID, ebaiapi.CancelTypeCustom, reason) } return err } func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) { // 饿百必须要确认订单后才能调整单 if order.Status < model.OrderStatusFinishedPickup { err = c.PickupGoods(order, false, ctx.GetUserName()) } if err == nil { var skuList []*ebaiapi.RefundSku for _, sku := range removedSkuList { skuList = append(skuList, &ebaiapi.RefundSku{ CustomeSkuID: utils.Int2Str(jxutils.GetSkuIDFromOrderSku(sku)), Number: utils.Int2Str(sku.Count), }) } if globals.EnableEbaiStoreWrite { err = api.EbaiAPI.OrderPartRefund(order.VendorOrderID, skuList) } } return err } func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, queryDate time.Time, vendorStoreID string) (vendorOrderIDs []string, err error) { if utils.IsTimeZero(queryDate) { return nil, fmt.Errorf("queryDate必须指定") } fromDate := utils.Time2Date(queryDate) toDate := fromDate.Add(24*time.Hour - 1) var vendorStoreIDs []string if vendorStoreID == "" { vendorStoreIDs, err = c.GetAllStoresVendorID(ctx, "") if err != nil { return nil, err } } else { vendorStoreIDs = []string{vendorStoreID} } task := tasksch.NewParallelTask("ebai ListOrders", nil, ctx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { vendorStoreID := batchItemList[0].(string) orderList, err := api.EbaiAPI.OrderListAll("", utils.Str2Int64(vendorStoreID), fromDate.Unix(), toDate.Unix(), 0) if err == nil { retVal = orderList } return retVal, err }, vendorStoreIDs) tasksch.HandleTask(task, parentTask, true).Run() orderList, err := task.GetResult(0) if err == nil && len(orderList) > 0 { vendorOrderIDs = make([]string, len(orderList)) for k, v := range orderList { orderInfo := v.(*ebaiapi.ListOrderItemInfo) vendorOrderIDs[k] = orderInfo.OrderID } } return vendorOrderIDs, err } func (c *PurchaseHandler) GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) { orderInfo, err := api.EbaiAPI.GetStoreOrderInfo(vendorOrderID) if err == nil { if orderBasic, _ := orderInfo["order_basic"].(map[string]interface{}); orderBasic != nil { tipFee = jxutils.StandardPrice2Int(utils.Interface2Float64WithDefault(orderBasic["delivery_tip_amount"], 0)) } } return tipFee, err } func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) { if globals.EnableEbaiStoreWrite { err = api.EbaiAPI.ModifyTip4OrderWaybill(vendorOrderID, "", jxutils.IntPrice2Standard(tipFee), 0) if err != nil { if strings.Contains(err.Error(), "HTTP code is not 200") { return fmt.Errorf("饿百此订单暂不支持加小费!") } } } return err } func (c *PurchaseHandler) GetSelfTakeCode(ctx *jxcontext.Context, order *model.GoodsOrder) (selfTakeCode string, err error) { // orderTrackList, err := api.EbaiAPI.OrderQueryAcceptancecode(order.VendorOrderID) // if err == nil { // for _, v := range orderTrackList { // if v.TagCode == 180 { // searchResult := selfTakeCodeReg.FindStringSubmatch(v.MsgContent) // if searchResult != nil && len(searchResult[1]) > 0 { // selfTakeCode = searchResult[1] // } // break // } // } // } return selfTakeCode, err } func (c *PurchaseHandler) ConfirmSelfTake(ctx *jxcontext.Context, order *model.GoodsOrder, selfTakeCode string) (err error) { if globals.EnableEbaiStoreWrite { err = api.EbaiAPI.OrderCheckout(order.VendorOrderID, selfTakeCode) } return err }