package mtps import ( "errors" "math" "git.rosy.net.cn/baseapi/platformapi/mtpsapi" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/controller" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/legacyorder" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/scheduler" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" "github.com/astaxie/beego" "github.com/astaxie/beego/orm" ) var ( ErrCanNotFindMTPSStore = errors.New("不能找到美团配送站点配置") ) type WaybillController struct { } func init() { scheduler.CurrentScheduler.RegisterDeliveryPlatform(model.VendorIDMTPS, new(WaybillController)) } func (c *WaybillController) OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { jxutils.CallMsgHandler(func() { retVal = c.onWaybillMsg(msg) }, msg.OrderID) return retVal } func (c *WaybillController) OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.CallbackResponse) { jxutils.CallMsgHandler(func() { order := &model.Waybill{ VendorWaybillID: msg.MtPeisongID, VendorWaybillID2: utils.Int64ToStr(msg.DeliveryID), WaybillVendorID: model.VendorIDMTPS, CourierName: msg.CourierName, CourierMobile: msg.CourierPhone, Status: model.WaybillStatusFailed, // todo 这里要再确定一下是否只要收到订单异常消息就视为订单失败 VendorStatus: utils.Int2Str(msg.ExceptionCode), StatusTime: utils.Timestamp2Time(msg.Timestamp), } order.VendorOrderID, order.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID) retVal = mtpsapi.Err2CallbackResponse(controller.WaybillManager.OnWaybillStatusChanged(order), "mtps OnWaybillExcept") }, msg.OrderID) return retVal } func (c *WaybillController) onWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { order := c.callbackMsg2Waybill(msg) switch msg.Status { case mtpsapi.OrderStatusWaitingForSchedule: order.Status = model.WaybillStatusNew case mtpsapi.OrderStatusAccepted: order.DesiredFee = c.calculateDeliveryFee(order) order.Status = model.WaybillStatusAccepted case mtpsapi.OrderStatusPickedUp: order.Status = model.WaybillStatusDelivering case mtpsapi.OrderStatusDeliverred: order.Status = model.WaybillStatusDelivered case mtpsapi.OrderStatusCanceled: order.Status = model.WaybillStatusCanceled default: globals.SugarLogger.Warnf("onWaybillMsg unknown msg:%v", msg) return mtpsapi.SuccessResponse } return mtpsapi.Err2CallbackResponse(controller.WaybillManager.OnWaybillStatusChanged(order), order.VendorStatus) } func (c *WaybillController) callbackMsg2Waybill(msg *mtpsapi.CallbackOrderMsg) (retVal *model.Waybill) { retVal = &model.Waybill{ VendorWaybillID: msg.MtPeisongID, VendorWaybillID2: utils.Int64ToStr(msg.DeliveryID), WaybillVendorID: model.VendorIDMTPS, CourierName: msg.CourierName, CourierMobile: msg.CourierPhone, VendorStatus: utils.Int2Str(msg.Status), StatusTime: utils.Timestamp2Time(msg.Timestamp), } retVal.VendorOrderID, retVal.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID) return retVal } func (c *WaybillController) calculateDeliveryFee(bill *model.Waybill) (retVal int64) { order, err := controller.OrderManager.LoadOrder(bill.VendorOrderID, bill.OrderVendorID) if err != nil { return 0 } var lists []orm.ParamsList db := orm.NewOrm() JxStoreID := jxutils.GetJxStoreIDFromOrder(order) num, err := db.Raw(` SELECT t2.price, t1.lng, t1.lat FROM jxstore t1 JOIN mtpsdeliveryprice t2 ON t2.citycode = t1.area WHERE t1.storeid = ? `, JxStoreID).ValuesList(&lists) var delieveryFee int64 if err == nil && num == 1 { delieveryFee = utils.Str2Int64(lists[0][0].(string)) } else { globals.SugarLogger.Warnf("calculateDeliveryFee can not calculate delivery fee for orderID:%s, num:%d, error:%v", order.VendorOrderID, num, err) return 0 } lng := utils.Str2Float64(lists[0][1].(string)) lat := utils.Str2Float64(lists[0][2].(string)) lng2, lat2, _ := jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType) distance := jxutils.EarthDistance(lat, lng, lat2, lng2) * 1.4 if distance < 3 { } else if distance < 5 { delieveryFee += jxutils.StandardPrice2Int(math.Ceil(distance - 3)) } else { delieveryFee += jxutils.StandardPrice2Int(2 + 2*math.Ceil(distance-5)) } if order.Weight < 5*1000 { } else if order.Weight < 10*1000 { delieveryFee += jxutils.StandardPrice2Int(0.5 * float64(order.Weight/1000-5)) } else if order.Weight < 20*1000 { delieveryFee += jxutils.StandardPrice2Int(2.5 + 1*float64(order.Weight/1000-10)) } else { delieveryFee += jxutils.StandardPrice2Int(2.5 + 10 + 2*float64(order.Weight/1000-20)) } hour, min, sec := bill.StatusTime.Clock() totalSeconds := hour*3600 + min*60 + sec if totalSeconds >= 11*3600+30*60 && totalSeconds <= 13*3600 { // 11:30 -- 13:00 delieveryFee += jxutils.StandardPrice2Int(3) } else if totalSeconds >= 21*3600 || totalSeconds <= 6*3600 { // 21:00 -- 06:00 delieveryFee += jxutils.StandardPrice2Int(3) } return delieveryFee } // DeliveryPlatformHandler func (c *WaybillController) CreateWaybill(order *model.GoodsOrder) (err error) { db := orm.NewOrm() // 忽略坐标转换错误,即使是转换出错,也只能当成转换成功来处理,底层会有错误日志输出 lngFloat, latFloat, _ := jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType) billParams := &mtpsapi.CreateOrderByShopParam{ OrderID: jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), DeliveryServiceCode: mtpsapi.DeliveryServiceCodeRapid, ReceiverName: order.ConsigneeName, ReceiverAddress: order.ConsigneeAddress, ReceiverPhone: order.ConsigneeMobile, CoordinateType: model.CoordinateTypeMars, ReceiverLng: jxutils.StandardCoordinate2Int(lngFloat), ReceiverLat: jxutils.StandardCoordinate2Int(latFloat), GoodsValue: jxutils.IntPrice2Standard(order.SalePrice), // todo 超价处理 GoodsWeight: float64(order.Weight) / 1000, ExpectedDeliveryTime: order.ExpectedDeliveredTime.Unix(), OrderType: mtpsapi.OrderTypeASAP, } if billParams.DeliveryID, err = c.getDeliveryID(order, db); err == nil { if billParams.ShopID, err = c.getMTPSShopID(order, db); err == nil { globals.SugarLogger.Debug(billParams.ShopID) goods := &mtpsapi.GoodsDetail{ Goods: []*mtpsapi.GoodsItem{}, } for _, sku := range order.Skus { goodItem := &mtpsapi.GoodsItem{ GoodCount: sku.Count, GoodPrice: jxutils.IntPrice2Standard(sku.SalePrice), } goodItem.GoodName, goodItem.GoodUnit = jxutils.SplitSkuName(sku.SkuName) goods.Goods = append(goods.Goods, goodItem) } addParams := utils.Params2Map("note", order.BuyerComment, "goods_detail", string(utils.MustMarshal(goods))) _, err = api.MtpsAPI.CreateOrderByShop(billParams, addParams) } } return err } func (c *WaybillController) CancelWaybill(bill *model.Waybill) (err error) { reasonID := mtpsapi.CancelReasonMerchantOther reasonMsg := "other reason" if bill.Status < model.WaybillStatusAccepted { } else if bill.Status < model.WaybillStatusCourierArrived { reasonID = mtpsapi.CancelReasonRideerGetGoodNotIntime reasonMsg = "CancelReasonRideerGetGoodNotIntime" } else { reasonID = mtpsapi.CancelReasonRidderSendNotIntime reasonMsg = "CancelReasonRidderSendNotIntime" } _, err = api.MtpsAPI.CancelOrder(utils.Str2Int64(bill.VendorWaybillID2), bill.VendorWaybillID, reasonID, reasonMsg) return nil } // todo 生成mtps deliveryid,为了兼容,现在取jxorder中的id func (c *WaybillController) getDeliveryID(order *model.GoodsOrder, db orm.Ormer) (retVal int64, err error) { jxorder := &legacyorder.Jxorder2{ OrderId: utils.Str2Int64(order.VendorOrderID), } err = utils.CallFuncLogError(func() error { err2 := db.Read(jxorder, "OrderId") return err2 }, "getDeliveryID, orderID:%s", order.VendorOrderID) return int64(jxorder.Id), err } func (c *WaybillController) getMTPSShopID(order *model.GoodsOrder, db orm.Ormer) (retVal string, err error) { sql := "SELECT zs_store_id FROM jx_to_zs_store_map WHERE jx_store_id = ?" var lists []orm.ParamsList JxStoreID := jxutils.GetJxStoreIDFromOrder(order) num, err := db.Raw(sql, JxStoreID).ValuesList(&lists) if err == nil && num == 1 { retVal = lists[0][0].(string) if beego.BConfig.RunMode == "dev" { retVal = "test_0001" } } else { globals.SugarLogger.Errorf("getMTPSShopID can not find mtps store info for orderID:%s, store:%d, num:%d, error:%v", order.VendorOrderID, JxStoreID, num, err) if err == nil { err = ErrCanNotFindMTPSStore } } return retVal, err }