package mtps import ( "errors" "fmt" "time" "git.rosy.net.cn/baseapi/platformapi/mtpsapi" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxutils" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/business/model/legacymodel" "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/business/partner/delivery" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" "github.com/astaxie/beego" "github.com/astaxie/beego/orm" ) const ( // maxOrderPrice = 6399 // 单位为分,达达最大价格,超过这个价格配送费会增加 maxOrderWeight = 5000 // 5公斤 ) var ( ErrCanNotFindMTPSStore = errors.New("不能找到美团配送站点配置") ErrStoreNoPriceInfo = errors.New("找不到门店的美团配送价格信息") ) var ( curDeliveryHandler *DeliveryHandler ) type DeliveryHandler struct { } func init() { curDeliveryHandler = new(DeliveryHandler) partner.RegisterDeliveryPlatform(curDeliveryHandler, true) } func (c *DeliveryHandler) GetVendorID() int { return model.VendorIDMTPS } func OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { return curDeliveryHandler.OnWaybillMsg(msg) } func OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.CallbackResponse) { return curDeliveryHandler.OnWaybillExcept(msg) } func (c *DeliveryHandler) OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { jxutils.CallMsgHandler(func() { retVal = c.onWaybillMsg(msg) }, msg.OrderID) return retVal } func (c *DeliveryHandler) 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.WaybillStatusUnknown, // todo 这里要再确定一下是否只要收到订单异常消息就只简单当成一个消息 VendorStatus: utils.Int2Str(msg.ExceptionCode), StatusTime: utils.Timestamp2Time(msg.Timestamp), } order.VendorOrderID, order.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID) retVal = mtpsapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), "mtps OnWaybillExcept") }, msg.OrderID) return retVal } func (c *DeliveryHandler) 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, _ = delivery.CalculateBillDeliveryFee(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(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus) } func (c *DeliveryHandler) 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), Remark: msg.CancelReason, } retVal.VendorOrderID, retVal.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID) return retVal } // IDeliveryPlatformHandler func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, policy func(deliveryFee, addFee int64) error) (bill *model.Waybill, err error) { db := orm.NewOrm() deliveryFee, addFee, err := delivery.CalculateOrderDeliveryFee(order, time.Now(), db) if err == nil { if policy != nil { err = policy(deliveryFee, addFee) } if err == nil { // 忽略坐标转换错误,即使是转换出错,也只能当成转换成功来处理,底层会有错误日志输出 lngFloat, latFloat, _ := jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType) billParams := &mtpsapi.CreateOrderByShopParam{ OrderID: jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), DeliveryServiceCode: mtpsapi.DeliveryServiceCodeRapid, ReceiverName: utils.FilterMb4(order.ConsigneeName), ReceiverAddress: utils.FilterMb4(order.ConsigneeAddress), ReceiverPhone: order.ConsigneeMobile, CoordinateType: model.CoordinateTypeMars, ReceiverLng: jxutils.StandardCoordinate2Int(lngFloat), ReceiverLat: jxutils.StandardCoordinate2Int(latFloat), GoodsValue: jxutils.IntPrice2Standard(order.ActualPayPrice), // todo 超价处理 GoodsWeight: float64(jxutils.IntWeight2Float(limitOrderWeight(order.Weight))), // 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{}, } goodItemMap := map[string]*mtpsapi.GoodsItem{} for _, sku := range order.Skus { goodItem := &mtpsapi.GoodsItem{ GoodCount: sku.Count, GoodPrice: jxutils.IntPrice2Standard(sku.SalePrice), } goodItem.GoodName, goodItem.GoodUnit = jxutils.GetNameAndUnitFromSkuName(sku.SkuName) // 好像SKU名不能重复,否则会报错,尝试处理一下 if item, ok := goodItemMap[goodItem.GoodName]; !ok { goods.Goods = append(goods.Goods, goodItem) goodItemMap[goodItem.GoodName] = goodItem } else { item.GoodCount += goodItem.GoodCount } } addParams := map[string]interface{}{ "note": utils.FilterMb4(order.BuyerComment), "goods_detail": string(utils.MustMarshal(goods)), "goods_pickup_info": fmt.Sprintf("%s第%d号单", model.VendorChineseNames[order.VendorID], order.OrderSeq), "poi_seq": fmt.Sprintf("#%d", order.OrderSeq), } result, err2 := api.MtpsAPI.CreateOrderByShop(billParams, addParams) if err = err2; err != nil { globals.SugarLogger.Debugf("CreateWaybill failed, orderID:%s, billParams:%v, addParams:%v, error:%v", order.VendorOrderID, billParams, addParams, err) tmpLog := &legacymodel.TempLog{ VendorOrderID: order.VendorOrderID, RefVendorOrderID: order.VendorOrderID, IntValue1: addFee, Msg: fmt.Sprintf("CreateWaybill failed, orderID:%s, billParams:%v, addParams:%v, error:%v", order.VendorOrderID, billParams, addParams, err), } db.Insert(tmpLog) } else { bill = &model.Waybill{ VendorOrderID: order.VendorOrderID, OrderVendorID: order.VendorID, VendorWaybillID: result.MtPeisongID, VendorWaybillID2: utils.Int64ToStr(result.DeliveryID), WaybillVendorID: model.VendorIDMTPS, DesiredFee: deliveryFee, } } } } } } return bill, err } func (c *DeliveryHandler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) { // switch cancelReasonID { // case partner.CancelWaybillReasonNotAcceptIntime: // cancelReasonID = mtpsapi.CancelReasonRideerMtpsOther // case partner.CancelWaybillReasonSwitch2SelfFailed: // cancelReasonID = mtpsapi.CancelReasonMerchantOther // default: // cancelReasonID = mtpsapi.CancelReasonRideerOther // } cancelReasonID = mtpsapi.CancelReasonMerchantOther cancelReason = "" _, err = api.MtpsAPI.CancelOrder(utils.Str2Int64(bill.VendorWaybillID2), bill.VendorWaybillID, cancelReasonID, cancelReason) return nil } func (c *DeliveryHandler) getDeliveryID(order *model.GoodsOrder, db orm.Ormer) (retVal int64, err error) { // jxorder表当前已经有50多万条记录了,加100万避免冲突 // 508505 return order.ID + 1000000, nil } func (c *DeliveryHandler) getMTPSShopID(order *model.GoodsOrder, db orm.Ormer) (retVal string, err error) { saleStoreID := jxutils.GetSaleStoreIDFromOrder(order) db2 := dao.WrapDB(db) storeCourierList, err2 := dao.GetOpenedStoreCouriersByStoreID(db2, saleStoreID, model.VendorIDMTPS) if err = err2; err != nil && err != orm.ErrNoRows { return "", err } if len(storeCourierList) == 0 { return "", partner.ErrStoreHaveNoCourier } retVal = storeCourierList[0].VendorStoreID if beego.BConfig.RunMode == "dev" { retVal = "test_0001" } return retVal, nil } func limitOrderWeight(weight int) int { if weight > maxOrderWeight { return maxOrderWeight } return weight }