package jd import ( "fmt" "strings" "time" "git.rosy.net.cn/jx-callback/business/jxutils/tasksch" "git.rosy.net.cn/baseapi/platformapi/autonavi" "git.rosy.net.cn/baseapi/platformapi/jdapi" "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 ( VendorStatus2StatusMap = map[string]int{ jdapi.OrderStatusPurchased: model.OrderStatusNew, jdapi.OrderStatusWaitOutStore: model.OrderStatusAccepted, jdapi.StatusIDWaitOutStore: model.OrderStatusAccepted, jdapi.OrderStatusFinishedPickup: model.OrderStatusFinishedPickup, jdapi.OrderStatusDelivering: model.OrderStatusDelivering, jdapi.OrderStatusDelivered: model.OrderStatusFinished, // jdapi.OrderStatusFinished: model.OrderStatusFinished, // todo 这个状态不是真正都完成的意思 jdapi.OrderStatusCanceled: model.OrderStatusCanceled, jdapi.OrderStatusAdjust: model.OrderStatusAdjust, jdapi.OrderStatusUserApplyCancel: model.OrderStatusApplyCancel, jdapi.OrderStatusLocked: model.OrderStatusLocked, jdapi.OrderStatusUnlocked: model.OrderStatusUnlocked, } ) func (c *PurchaseHandler) OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { jxutils.CallMsgHandler(func() { retVal = c.onOrderMsg(msg) }, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD)) return retVal } func (c *PurchaseHandler) updateOrderFinancialInfo(orderID string) (err error) { order := &model.GoodsOrder{ VendorOrderID: orderID, VendorID: model.VendorIDJD, } orderSettlement, err := api.JdAPI.OrderShoudSettlementService2(orderID) if err == nil { if orderSettlement != nil { updateOrderBySettleMent(order, orderSettlement) err = partner.CurOrderManager.UpdateOrderFields(order, []string{"TotalShopMoney", "PmSubsidyMoney"}) } } return err } func (c *PurchaseHandler) onOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { status := c.callbackMsg2Status(msg) if jdapi.StatusIDNewOrder == msg.StatusID { status.Status = model.OrderStatusNew // 因为京东将事件32000与状态32000混用,事件32000可能是新订单,也可能是已接单,统一当成新订单处理 } if partner.CurOrderManager.GetStatusDuplicatedCount(status) > 0 { return nil } if msg.MsgURL == jdapi.CallbackMsgOrderAccounting { retVal = c.OnFinancialMsg(msg) retVal = jdapi.Err2CallbackResponse(c.updateOrderFinancialInfo(msg.BillID), status.VendorStatus) } else if msg.MsgURL == jdapi.CallbackMsgAfterSaleBillStatus { retVal = c.OnAfsOrderMsg(msg) } else { // 新订单事件,与订单状态有点冲突 if jdapi.StatusIDNewOrder == msg.StatusID { retVal = c.onOrderNew(msg, status) } else if jdapi.OrderStatusAdjust == msg.StatusID { retVal = c.onOrderAdjust(msg, status) } else { if msg.StatusID == jdapi.OrderStatusAddComment || msg.StatusID == jdapi.OrderStatusModifyComment { utils.CallFuncAsync(func() { c.onOrderComment2(msg) }) } err := partner.CurOrderManager.OnOrderStatusChanged(status) // if globals.HandleLegacyJxOrder && err == nil { // c.legacyJdOrderStatusChanged(status) // } retVal = jdapi.Err2CallbackResponse(err, status.VendorStatus) } } return retVal } func updateOrderBySettleMent(order *model.GoodsOrder, orderSettlement *jdapi.OrderSettlementInfo) { if orderSettlement != nil { order.TotalShopMoney = orderSettlement.SettlementAmount order.PmSubsidyMoney = orderSettlement.PlatOrderGoodsDiscountMoney + orderSettlement.PlatSkuGoodsDiscountMoney } } func (c *PurchaseHandler) getOrder(orderID string) (order *model.GoodsOrder, orderMap map[string]interface{}, err error) { globals.SugarLogger.Debugf("jd getOrder orderID:%s", orderID) var ( realMobile string orderSettlement *jdapi.OrderSettlementInfo ) task := tasksch.NewParallelTask("jd getOrder", tasksch.NewParallelConfig().SetIsContinueWhenError(true), jxcontext.AdminCtx, func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) { taskIndex := batchItemList[0].(int) switch taskIndex { case 0: orderMap, err = api.JdAPI.QuerySingleOrder(orderID) if err == nil { order = c.Map2Order(orderMap) realMobile, _ = api.JdAPI.GetRealMobile4Order(orderID, order.VendorStoreID) if realMobile != "" { order.ConsigneeMobile2 = jxutils.FormalizeMobile(realMobile) } } case 1: orderSettlement, _ = api.JdAPI.OrderShoudSettlementService2(orderID) } return nil, err }, []int{0, 1}) task.Run() _, err = task.GetResult(0) if order != nil && orderSettlement != nil { updateOrderBySettleMent(order, orderSettlement) } // if orderMap, err = api.JdAPI.QuerySingleOrder(orderID); err == nil { // globals.SugarLogger.Debugf("jd getOrder2 orderID:%s", orderID) // order = c.Map2Order(orderMap) // if jxutils.IsMobileFake(order.ConsigneeMobile) { // if realMobile, err := api.JdAPI.GetRealMobile4Order(orderID, order.VendorStoreID); err == nil { // 故意强制忽略取不到真实手机号错误 // globals.SugarLogger.Debugf("jd getOrder3 orderID:%s", orderID) // order.ConsigneeMobile2 = jxutils.FormalizeMobile(realMobile) // } else { // // globals.SugarLogger.Warnf("jd GetOrder orderID:%s, GetRealMobile4Order failed with error:%v", orderID, err2) // } // } // } return order, orderMap, err } func (c *PurchaseHandler) GetOrder(orderID string) (order *model.GoodsOrder, err error) { order, _, err = c.getOrder(orderID) return order, err } func (c *PurchaseHandler) Map2Order(orderData map[string]interface{}) (order *model.GoodsOrder) { result := orderData orderID := utils.Int64ToStr(utils.MustInterface2Int64(result["orderId"])) globals.SugarLogger.Debugf("jd Map2Order orderID:%s", orderID) const defaultStatusTimeField = "orderPurchaseTime" statusTimeField := defaultStatusTimeField if result[statusTimeField] == nil { // 814560888003021 orderPurchaseTime为空 statusTimeField = "orderStartTime" } order = &model.GoodsOrder{ VendorOrderID: orderID, VendorID: model.VendorIDJD, VendorStoreID: utils.Interface2String(result["produceStationNo"]), StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(result["produceStationNoIsv"]), 0)), StoreName: utils.Interface2String(result["produceStationName"]), ConsigneeName: utils.Interface2String(result["buyerFullName"]), ConsigneeMobile: jxutils.FormalizeMobile(utils.Interface2String(result["buyerMobile"])), ConsigneeAddress: utils.Interface2String(result["buyerFullAddress"]), CoordinateType: model.CoordinateTypeMars, BuyerComment: utils.TrimBlankChar(utils.Interface2String(result["orderBuyerRemark"])), ExpectedDeliveredTime: utils.Str2TimeWithDefault(utils.Interface2String(result["orderPreEndDeliveryTime"]), utils.DefaultTimeValue), PickDeadline: utils.Str2TimeWithDefault(utils.Interface2String(result["pickDeadline"]), utils.DefaultTimeValue), // 813951615000022 pickDeadline为空 VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(result["orderStatus"])), OrderSeq: int(utils.MustInterface2Int64(result["orderNum"])), StatusTime: utils.Str2Time(result[statusTimeField].(string)), OrderCreatedAt: utils.Str2Time(result[statusTimeField].(string)), OriginalData: string(utils.MustMarshal(result)), ActualPayPrice: utils.MustInterface2Int64(result["orderBuyerPayableMoney"]), } order.Status = c.GetStatusFromVendorStatus(order.VendorStatus) businessTage := utils.Interface2String(result["businessTag"]) if strings.Index(businessTage, "dj_aging_immediately") >= 0 { order.BusinessType = model.BusinessTypeImmediate } else { order.BusinessType = model.BusinessTypeDingshida } coordinateType := utils.Interface2Int64WithDefault(result["buyerCoordType"], 1) originalLng := utils.MustInterface2Float64(result["buyerLng"]) originalLat := utils.MustInterface2Float64(result["buyerLat"]) if coordinateType == 1 { lng, lat, err2 := api.AutonaviAPI.CoordinateConvert(originalLng, originalLat, autonavi.CoordSysGPS) if err2 == nil { originalLng = lng originalLat = lat } else { // 如果没有转成功,保留原始数据 order.CoordinateType = model.CoordinateTypeGPS } } order.ConsigneeLng = jxutils.StandardCoordinate2Int(originalLng) order.ConsigneeLat = jxutils.StandardCoordinate2Int(originalLat) // discounts := result["discount"].(map[string]interface{}) for _, product2 := range result["product"].([]interface{}) { product := product2.(map[string]interface{}) sku := &model.OrderSku{ VendorOrderID: orderID, VendorID: model.VendorIDJD, Count: int(utils.MustInterface2Int64(product["skuCount"])), SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product["skuIdIsv"]), 0)), VendorSkuID: utils.Int64ToStr(utils.MustInterface2Int64(product["skuId"])), SkuName: product["skuName"].(string), Weight: jxutils.FloatWeight2Int(float32(utils.MustInterface2Float64(product["skuWeight"]))), VendorPrice: utils.MustInterface2Int64(product["skuStorePrice"]), SalePrice: utils.MustInterface2Int64(product["skuJdPrice"]), } if jdPromotionType := int(utils.MustInterface2Int64(product["promotionType"])); jdPromotionType != jdapi.PromotionTypeNormal { sku.StoreSubName = utils.Int2Str(jdPromotionType) } if skuCostumeProperty, ok := product["skuCostumeProperty"]; ok { sku.SkuName += skuCostumeProperty.(string) } if isGift, ok := product["isGift"].(bool); ok && isGift { sku.SkuType = 1 } order.Skus = append(order.Skus, sku) } jxutils.RefreshOrderSkuRelated(order) return order } // func (c *PurchaseHandler) onOrderNew(msg *jdapi.CallbackOrderMsg, orderStatus *model.OrderStatus) (response *jdapi.CallbackResponse) { globals.SugarLogger.Debugf("onOrderNew orderID:%s", msg.BillID) order, orderMap, err := c.getOrder(msg.BillID) if err == nil { globals.SugarLogger.Debugf("onOrderNew2 orderID:%s", msg.BillID) if err = partner.CurOrderManager.OnOrderNew(order, orderStatus); err == nil { utils.CallFuncAsync(func() { c.OnOrderDetail(orderMap, partner.CreatedPeration) }) } } return jdapi.Err2CallbackResponse(err, "jd onOrderNew") } func (c *PurchaseHandler) onOrderAdjust(msg *jdapi.CallbackOrderMsg, orderStatus *model.OrderStatus) *jdapi.CallbackResponse { order, orderMap, err := c.getOrder(msg.BillID) if err == nil { err = partner.CurOrderManager.OnOrderAdjust(order, orderStatus) if err == nil { utils.CallFuncAsync(func() { c.OnOrderDetail(orderMap, partner.UpdatedPeration) }) } } return jdapi.Err2CallbackResponse(err, "jd onOrderAdjust") } func (c *PurchaseHandler) callbackMsg2Status(msg *jdapi.CallbackOrderMsg) *model.OrderStatus { orderStatus := &model.OrderStatus{ VendorOrderID: msg.BillID, VendorID: model.VendorIDJD, OrderType: model.OrderTypeOrder, RefVendorOrderID: msg.BillID, RefVendorID: model.VendorIDJD, VendorStatus: msg.StatusID, Status: c.GetStatusFromVendorStatus(msg.StatusID), StatusTime: utils.Str2Time(msg.Timestamp), Remark: msg.Remark, } return orderStatus } func (c *PurchaseHandler) postFakeMsg(vendorOrderID, vendorStatus string) { msg := &jdapi.CallbackOrderMsg{ BillID: vendorOrderID, StatusID: vendorStatus, Timestamp: utils.Time2Str(time.Now()), } utils.CallFuncAsync(func() { OnOrderMsg(msg) }) } // IPurchasePlatformHandler func (c *PurchaseHandler) GetStatusFromVendorStatus(vendorStatus string) int { if status, ok := VendorStatus2StatusMap[vendorStatus]; ok { return status } return model.OrderStatusUnknown } func (c *PurchaseHandler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) { globals.SugarLogger.Debugf("jd AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt) if globals.EnableStoreWrite { err = api.JdAPI.OrderAcceptOperate(order.VendorOrderID, isAcceptIt, userName) } else { c.postFakeMsg(order.VendorOrderID, jdapi.StatusIDWaitOutStore) } return err } func (c *PurchaseHandler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) { globals.SugarLogger.Debugf("jd PickupGoods orderID:%s, isSelfDelivery:%t", order.VendorOrderID, isSelfDelivery) if !isSelfDelivery && globals.EnableJdStoreWrite { _, err = api.JdAPI.OrderJDZBDelivery(order.VendorOrderID, userName) } else { c.postFakeMsg(order.VendorOrderID, jdapi.OrderStatusFinishedPickup) } return err } func (p *PurchaseHandler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool) (err error) { if globals.EnableJdStoreWrite { err = api.JdAPI.ReceiveFailedAudit(order.VendorOrderID, isAcceptIt, ctx.GetUserName(), "") } return err } func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送 if globals.EnableJdStoreWrite { err = api.JdAPI.UrgeDispatching(order.VendorOrderID, ctx.GetUserName()) } return err } func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货 if globals.EnableJdStoreWrite { err = api.JdAPI.ConfirmReceiveGoods(order.VendorOrderID) } return err } func (c *PurchaseHandler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Debugf("jd Swtich2SelfDeliver orderID:%s", order.VendorOrderID) if globals.EnableJdStoreWrite { _, err = api.JdAPI.ModifySellerDelivery(order.VendorOrderID, userName) if err != nil { if errWithCode, ok := err.(*utils.ErrorWithCode); ok && errWithCode.Level() == 1 { globals.SugarLogger.Infof("Swtich2SelfDeliver failed with error:%v try get current status", err) if order2, err2 := c.GetOrder(order.VendorOrderID); err2 == nil { var mapData map[string]interface{} if err2 = utils.UnmarshalUseNumber([]byte(order2.OriginalData), &mapData); err2 == nil { if utils.Interface2String(mapData["deliveryCarrierNo"]) == "2938" { // 当前已经是自送状态了 err = nil } } } } } } return err } func (c *PurchaseHandler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Debugf("jd Swtich2SelfDelivered orderID:%s", order.VendorOrderID) if globals.EnableJdStoreWrite { _, err = api.JdAPI.DeliveryEndOrder(order.VendorOrderID, userName) } return err } func (c *PurchaseHandler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Debugf("jd SelfDeliverDelivering orderID:%s", order.VendorOrderID) if globals.EnableJdStoreWrite { _, err = api.JdAPI.OrderSerllerDelivery(order.VendorOrderID, userName) } return err } // 京东送达接口都是一样的 func (c *PurchaseHandler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) { globals.SugarLogger.Debugf("jd SelfDeliverDelivered orderID:%s", order.VendorOrderID) if globals.EnableJdStoreWrite { err = c.Swtich2SelfDelivered(order, userName) } return err } func (c *PurchaseHandler) GetOrderRealMobile(ctx *jxcontext.Context, order *model.GoodsOrder) (mobile string, err error) { mobile, err = api.JdAPI.GetRealMobile4Order(order.VendorOrderID, order.VendorStoreID) return mobile, err } func (c *PurchaseHandler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAgree bool, reason string) (err error) { if globals.EnableJdStoreWrite { err = api.JdAPI.OrderCancelOperate(order.VendorOrderID, isAgree, ctx.GetUserName(), reason) } return err } func (c *PurchaseHandler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) { if globals.EnableJdStoreWrite { api.JdAPI.DeliveryEndOrder(order.VendorOrderID, ctx.GetUserName()) err = api.JdAPI.CancelAndRefund(order.VendorOrderID, ctx.GetUserName(), reason) } return err } func (c *PurchaseHandler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) { order = jxutils.RemoveSkuFromOrder(order, removedSkuList) var oaosAdjustDTOList []*jdapi.OAOSAdjustDTO for _, sku := range order.Skus { oaosAdjustDTOList = append(oaosAdjustDTOList, &jdapi.OAOSAdjustDTO{ OutSkuID: utils.Int2Str(jxutils.GetSkuIDFromOrderSku(sku)), SkuCount: sku.Count, }) } if globals.EnableJdStoreWrite { err = api.JdAPI.AdjustOrder(order.VendorOrderID, ctx.GetUserName(), reason, oaosAdjustDTOList) } return err } func (c *PurchaseHandler) ListOrders(ctx *jxcontext.Context, 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) params := map[string]interface{}{ "orderPurchaseTime_begin": utils.Time2Str(fromDate), "orderPurchaseTime_end": utils.Time2Str(toDate), jdapi.KeyPageNo: jdapi.AllPage, } if vendorStoreID != "" { params["deliveryStationNo"] = vendorStoreID } orderList, _, err := api.JdAPI.OrderQuery2(params) if err == nil { vendorOrderIDs = make([]string, len(orderList)) for k, v := range orderList { vendorOrderIDs[k] = utils.Int64ToStr(v.OrderID) } } return vendorOrderIDs, err }