Files
jx-callback/business/partner/purchase/jd/order.go
2019-08-28 14:25:29 +08:00

474 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 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 := getAPI("").OrderShoudSettlementService2(orderID)
if err == nil {
if orderSettlement != nil {
updateOrderBySettleMent(order, orderSettlement)
err = partner.CurOrderManager.UpdateOrderFields(order, []string{ /*"WaybillTipMoney", */ "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.WaybillTipMoney = orderSettlement.VenderPaidTips
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 = getAPI("").QuerySingleOrder(orderID)
if err == nil {
order = c.Map2Order(orderMap)
realMobile, _ = getAPI("").GetRealMobile4Order(orderID, order.VendorStoreID)
if realMobile != "" {
order.ConsigneeMobile2 = jxutils.FormalizeMobile(realMobile)
}
}
case 1:
orderSettlement, _ = getAPI("").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 = getAPI("").QuerySingleOrder(orderID); err == nil {
// globals.SugarLogger.Debugf("jd getOrder2 orderID:%s", orderID)
// order = c.Map2Order(orderMap)
// if jxutils.IsMobileFake(order.ConsigneeMobile) {
// if realMobile, err := getAPI("").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"]),
DistanceFreightMoney: utils.Interface2Int64WithDefault(result["merchantPaymentDistanceFreightMoney"], 0),
}
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 != 0 && 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 = getAPI("").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 = getAPI("").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 = getAPI("").ReceiveFailedAudit(order.VendorOrderID, isAcceptIt, ctx.GetUserName(), "")
}
return err
}
func (p *PurchaseHandler) CallCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 拣货失败后再次招唤平台配送
if globals.EnableJdStoreWrite {
err = getAPI("").UrgeDispatching(order.VendorOrderID, ctx.GetUserName())
}
return err
}
func (p *PurchaseHandler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) { // 投递失败后确认收到退货
if globals.EnableJdStoreWrite {
err = getAPI("").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 = getAPI("").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 = getAPI("").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 = getAPI("").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 = getAPI("").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 = getAPI("").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 {
err1 := c.Swtich2SelfDeliver(order, ctx.GetUserName())
if err = getAPI("").CancelAndRefund(order.VendorOrderID, ctx.GetUserName(), reason); err != nil {
if err1 != nil {
err = fmt.Errorf("取消订单失败,京东取消订单是要先转为自送再处理,转自送失败:%v", err1)
}
}
}
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 = getAPI("").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)
queryParam := &jdapi.OrderQueryParam{
OrderPurchaseTimeBegin: utils.Time2Str(fromDate),
OrderPurchaseTimeEnd: utils.Time2Str(toDate),
PageNo: jdapi.AllPage,
}
if vendorStoreID != "" {
queryParam.DeliveryStationNo = vendorStoreID
}
orderList, _, err := getAPI("").OrderQuery2(queryParam)
if err == nil {
vendorOrderIDs = make([]string, len(orderList))
for k, v := range orderList {
vendorOrderIDs[k] = utils.Int64ToStr(v.OrderID)
}
}
return vendorOrderIDs, err
}
func (c *PurchaseHandler) UpdateWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64) (err error) {
orderInfo, err := getAPI("").QuerySingleOrder2(order.VendorOrderID)
if err == nil {
tip2Add := int(tipFee) - orderInfo.Tips
if tip2Add != 0 {
if globals.EnableJdStoreWrite {
err = getAPI("").OrderAddTips(order.VendorOrderID, tip2Add, ctx.GetUserName())
}
}
}
return err
}
func (c *PurchaseHandler) GetWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder) (tipFee int64, err error) {
orderInfo, err := getAPI("").QuerySingleOrder2(order.VendorOrderID)
if err == nil {
tipFee = int64(orderInfo.Tips)
}
return tipFee, err
}
func (c *PurchaseHandler) AddWaybillTip(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee2Add int64) (err error) {
if globals.EnableJdStoreWrite {
err = getAPI("").OrderAddTips(order.VendorOrderID, int(tipFee2Add), ctx.GetUserName())
}
return err
}