package uupt import ( "fmt" "strings" "time" "git.rosy.net.cn/baseapi/platformapi/baidunavi" "git.rosy.net.cn/baseapi/platformapi/mtpsapi" "git.rosy.net.cn/baseapi/platformapi/uuptapi" "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/model/dao" "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" ) const ( //errCode 错误码说明 ErrorParameter1 = -101 //参数格式校验错误 ErrorParameter2 = -199 //参数格式校验错误 ErrorTimestamp = -102 //timestamp错误 ErrorAppID = -103 //appid无效 ErrorSignatureCheck = -104 //签名校验失败 ErrorOpenIDInvalid = -105 //openid无效 ErrorUnableParseOrigin = -1001 //无法解析起始地 ErrorUnableParseDestination = -1002 //无法解析目的地 ErrorCantGetCityInformation = -1003 //无法获取订单城市相关信息 ErrorOrderCategory = -1004 //订单小类出现错误 ErrorNoUserInformation = -1005 //没有用户信息 ErrorCouponID = -1006 //优惠券ID错误 ErrorPriceToken1 = -2001 //price_token无效 ErrorPriceToken2 = -2002 //price_token无效 ErrorPushType = -2003 //push_type错误 ErrorSpecialType = -2004 //special_type错误 ErrorCallMeWithTake = -2005 //callMe_withTake错误 ErrorOrderPrice = -2006 //order_price错误 ErrorBalancePayMoney = -2007 //balance_payMoney错误 ErrorOrderTotalMoney = -2008 //订单总金额错误 ErrorPayMoney = -2009 //支付金额错误 ErrorUserNotMatch = -2010 //用户不一致 ErrorWrongPhone = -2011 //手机号错误 ErrorNotExistBind = -2012 //不存在绑定关系 ErrorCancelReasonCantEmpty = -4001 //取消原因不能为空 ErrorOrderNumber1 = -4002 //订单编号无效 ErrorOrderNumber2 = -5001 //订单编号无效 ErrorOrderNumber3 = -5002 //订单编号无效 ErrorOrderNumber4 = -5003 //订单编号无效 ErrorFrequencyTooFast = -10001 //发送频率过快,请稍候重试 ErrorNeedCommitVerificationCode = -106 //接口返回base64图片需要提交对应图片验证码 ) var ErrCode = map[int]string{ ErrorParameter1: "参数格式校验错误", ErrorParameter2: "参数格式校验错误", ErrorTimestamp: "timestamp错误", ErrorAppID: "appid无效", ErrorSignatureCheck: "签名校验失败", ErrorOpenIDInvalid: "openid无效", ErrorUnableParseOrigin: "无法解析起始地", ErrorUnableParseDestination: "无法解析目的地", ErrorCantGetCityInformation: "无法获取订单城市相关信息", ErrorOrderCategory: "订单小类出现错误", ErrorNoUserInformation: "没有用户信息", ErrorCouponID: "优惠券ID错误", ErrorPriceToken1: "price_token无效", ErrorPriceToken2: "price_token无效", ErrorPushType: "push_type错误", ErrorSpecialType: "special_type错误", ErrorCallMeWithTake: "callMe_withTake错误", ErrorOrderPrice: "order_price错误", ErrorBalancePayMoney: "balance_payMoney错误", ErrorOrderTotalMoney: "订单总金额错误", ErrorPayMoney: "支付金额错误", ErrorUserNotMatch: "用户不一致", ErrorWrongPhone: "手机号错误", ErrorNotExistBind: "不存在绑定关系", ErrorCancelReasonCantEmpty: "取消原因不能为空", ErrorOrderNumber1: "订单编号无效", ErrorOrderNumber2: "订单编号无效", ErrorOrderNumber3: "订单编号无效", ErrorOrderNumber4: "订单编号无效", ErrorFrequencyTooFast: "发送频率过快,请稍候重试", ErrorNeedCommitVerificationCode: "接口返回base64图片需要提交对应图片验证码", } var ( curDeliveryHandler *DeliveryHandler ) type DeliveryHandler struct { } func init() { if api.UuAPI != nil { curDeliveryHandler = new(DeliveryHandler) partner.RegisterDeliveryPlatform(curDeliveryHandler, true) } } func (d DeliveryHandler) GetVendorID() int { return model.VendorIDUUPT } func (d DeliveryHandler) CreateStore(ctx *jxcontext.Context, storeDetail *dao.StoreDetail2) (vendorStoreID string, status int, err error) { return "", 0, fmt.Errorf("uu跑腿暂不支持此操作") } func (d DeliveryHandler) GetStore(ctx *jxcontext.Context, storeID int, vendorStoreID string) (storeDetail *dao.StoreDetail2, err error) { //uu跑腿无门店概念 store, err := dao.GetStoreDetail(dao.GetDB(), utils.Str2Int(vendorStoreID), model.VendorIDUUPT, "") if err == nil { storeDetail = &dao.StoreDetail2{ Store: model.Store{ Name: store.Name, Tel1: store.Tel1, Address: store.Address, Lat: store.Lat, Lng: store.Lng, }, VendorID: model.VendorIDUUPT, VendorStoreID: utils.Int2Str(storeID), CourierStatus: model.StoreStatusOpened, } } return storeDetail, err } func (d DeliveryHandler) IsErrStoreNotExist(err error) bool { return false } func (d DeliveryHandler) IsErrStoreExist(err error) bool { return false } func (d DeliveryHandler) CreateWaybill(order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) { //获取门店老板详情 storeOwner, err := dao.GetStoreDetail(dao.GetDB(), getReallyStoreID(order.StoreID, order.JxStoreID), 0, "") if err != nil { return nil, err } //获取金额令牌,实际需要支付金额 price, err := getOrderPrice(order) if err != nil { return nil, err } param := map[string]interface{}{ "price_token": price.PriceToken, "order_price": price.TotalMoney, "balance_paymoney": price.NeedPayMoney, "receiver": order.ConsigneeName, "receiver_phone": order.ConsigneeMobile, "note": fmt.Sprintf("%s#%s号单,", model.VendorChineseNames[order.VendorID], utils.Int2Str(order.OrderSeq)) + utils.FilterMb4("客户电话:"+order.ConsigneeMobile+",配送遇到问题,可联系18048531223取消配送单,禁止未配送直接完成订单"), "callback_url": uuptapi.WaybillCallbackURL, "push_type": uuptapi.PushTypeOpen, "pubusermobile": storeOwner.Tel1, //老板电话 "special_type": uuptapi.SpecialTypeNo, "callme_withtake": uuptapi.CallMeWithTakeYes, } if orderCode, originID, err := api.UuAPI.AddOrder(param); err != nil { return nil, err } else { bill = &model.Waybill{ VendorOrderID: order.VendorOrderID, OrderVendorID: order.VendorID, VendorWaybillID: orderCode, VendorWaybillID2: originID, WaybillVendorID: model.VendorIDUUPT, DesiredFee: jxutils.StandardPrice2Int(utils.Str2Float64(price.TotalMoney)), } } delivery.OnWaybillCreated(bill) return bill, err } func (d DeliveryHandler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) { if err = api.UuAPI.CancelOrder(bill.VendorWaybillID, uuptapi.CancelReasonNormal); err != nil { return err } bill.Status = model.WaybillStatusCanceled bill.Remark = cancelReason partner.CurOrderManager.OnWaybillStatusChanged(bill) return nil } func (d DeliveryHandler) GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *partner.WaybillFeeInfo, err error) { if orderPrice, err := getOrderPrice(order); err != nil { return nil, err } else { deliveryFeeInfo = &partner.WaybillFeeInfo{} // deliveryFeeInfo.DeliveryFee = jxutils.StandardPrice2Int(utils.Str2Float64(orderPrice.NeedPayMoney)) 优惠后金额 deliveryFeeInfo.DeliveryFee = jxutils.StandardPrice2Int(utils.Str2Float64(orderPrice.TotalMoney)) // 原始金额 } return deliveryFeeInfo, err } func (c *DeliveryHandler) GetWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (tipFee int64, err error) { // uu跑腿没有获取小费的接口,直接返回系统支付的金额 //order, err := api.UuAPI.GetOrderDetail(vendorOrderID) //if err == nil { // tipFee = jxutils.StandardPrice2Int(order.Tips) //} //return tipFee, err return 0, nil } func (c *DeliveryHandler) UpdateWaybillTip(ctx *jxcontext.Context, vendorOrgCode, vendorStoreID, vendorOrderID, vendorWaybillID, vendorWaybillID2, cityCode string, tipFee int64) (err error) { return api.UuAPI.AddTip(vendorOrderID, vendorWaybillID, int(tipFee)) } func (d DeliveryHandler) ComplaintRider(bill *model.Waybill, resonID int, resonContent string) (err error) { return fmt.Errorf("UU跑腿暂不支持此操作") } func (d DeliveryHandler) GetRiderInfo(orderId string, deliveryId int64, mtPeisongId string) (rider *mtpsapi.RiderInfo, err error) { waybill, err := api.UuAPI.GetOrderDetail(orderId) if err != nil { return nil, err } temp := strings.Split(waybill.DriverLastloc, ",") //格式:113.71776,34.767501 param := &mtpsapi.RiderInfo{ OrderId: orderId, ThirdCarrierOrderId: waybill.OrderCode, CourierName: waybill.DriverName, CourierPhone: waybill.DriverMobile, LogisticsProviderCode: mtpsapi.UUPTCode, LogisticsStatus: utils.Str2Int(waybill.State), Longitude: temp[0], Latitude: temp[1], } switch waybill.State { case uuptapi.StateConfirmSuccess: param.LogisticsStatus = model.WaybillStatusNew param.LogisticsContext = model.RiderWaitRider case uuptapi.StateRMGrabsOrder: param.LogisticsStatus = model.WaybillStatusCourierAssigned param.LogisticsContext = model.RiderGetOrder case uuptapi.StateArrivedStore: param.LogisticsStatus = model.WaybillStatusCourierArrived param.LogisticsContext = model.RiderToStore case uuptapi.StatePickUp, uuptapi.StateArrivedDestination: param.LogisticsStatus = model.WaybillStatusDelivering param.LogisticsContext = model.RiderGetOrderDelivering case uuptapi.StateReceiverGetGoods: param.LogisticsStatus = model.WaybillStatusDelivered param.LogisticsContext = model.RiderGetOrderDelivered case uuptapi.StateOrderCancel: param.LogisticsStatus = model.WaybillStatusCanceled param.LogisticsContext = model.RiderGetOrderCanceled } return param, nil } func (c *DeliveryHandler) GetDeliverLiquidatedDamages(orderId string, deliverId string) (money int64, err error) { return api.UuAPI.GetOrderLiquidatedDamages(deliverId, orderId) } func (c *DeliveryHandler) GetRidderPosition(ctx *jxcontext.Context, vendorOrgCode, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (lng, lat float64, err error) { if rider, err := api.UuAPI.GetOrderDetail(vendorWaybillID); err == nil && len(rider.DriverLastloc) > 0 { te := strings.Split(rider.DriverLastloc, ",") if len(te) > 0 { lng = utils.Str2Float64(te[0]) lat = utils.Str2Float64(te[1]) } return lng, lat, nil } return 0, 0, err } //辅助函数 func getOrderPrice(order *model.GoodsOrder) (orderPrice *uuptapi.GetOrderPriceResp, err error) { store, err := dao.GetStoreDetail(dao.GetDB(), getReallyStoreID(order.StoreID, order.JxStoreID), 0, "") if err != nil { return nil, err } //转换百度坐标系 var coords []*baidunavi.Coordinate coords = append(coords, &baidunavi.Coordinate{ Lng: jxutils.IntCoordinate2Standard(store.Lng), Lat: jxutils.IntCoordinate2Standard(store.Lat), }, &baidunavi.Coordinate{ Lat: jxutils.IntCoordinate2Standard(order.ConsigneeLat), Lng: jxutils.IntCoordinate2Standard(order.ConsigneeLng), }) coords, err = api.BaiDuNaviAPI.BatchCoordinateConvert(coords, baidunavi.CoordSysGCJ02, baidunavi.CoordSysBaiDu) weight := 4 tempWeight := 0 if order.Weight/1000 >= weight { tempWeight = weight } else if order.Weight/1000 < 1 { tempWeight = 1 } else { tempWeight = int(order.Weight / 1000) } param := map[string]interface{}{ "origin_id": order.VendorOrderID, "from_address": store.Address, "from_usernote": "京西菜市(" + store.Store.Name + ")", "to_address": order.ConsigneeAddress, "city_name": store.CityName, "send_type": uuptapi.SendTypeHelpMeDeliver, "from_lat": coords[0].Lat, "from_lng": coords[0].Lng, "to_lat": coords[1].Lat, "to_lng": coords[1].Lng, "goods_weight": tempWeight, } if orderPrice, err = api.UuAPI.GetOrderPrice(param); err != nil { return nil, err } else { return orderPrice, nil } } func OnWaybillMsg(req *uuptapi.WaybillCallbackParam) (resp *uuptapi.CallbackResponse) { param := &model.Waybill{ VendorOrderID: req.OriginID, VendorWaybillID: req.OrderCode, WaybillVendorID: model.VendorIDUUPT, CourierName: req.DriverName, CourierMobile: req.DriverMobile, VendorStatus: req.State, StatusTime: time.Now(), Remark: req.StateText, } var good *model.GoodsOrder var reallyPrice int64 sql := `SELECT * FROM goods_order WHERE vendor_order_id = ? ORDER BY order_created_at DESC LIMIT 1 OFFSET 0` sqlParams := []interface{}{req.OriginID} dao.GetRow(dao.GetDB(), &good, sql, sqlParams) param.OrderVendorID = good.VendorID //查询运单价格 uuPrice, err := api.UuAPI.GetOrderDetail(req.OrderCode) if err != nil { reallyPrice = 0 } else { reallyPrice = int64(utils.Str2Float64(uuPrice.OrderPrice) * 100) } store, _ := dao.GetStoreDetail(dao.GetDB(), good.JxStoreID, good.VendorID, good.VendorOrgCode) reallyPrice += int64(store.FreightMarkup) actualFee := int64((utils.Str2Float64(uuPrice.OrderPrice)-utils.Str2Float64(uuPrice.PriceOff))*100) - int64(utils.WayBillDeliveryMarkUp) switch req.State { case uuptapi.StateConfirmSuccess: param.Status = model.WaybillStatusNew //5 待调度 param.DesiredFee = reallyPrice param.ActualFee = actualFee case uuptapi.StateRMGrabsOrder: param.Status = model.WaybillStatusCourierAssigned param.Remark = req.DriverName + "," + req.DriverMobile param.DesiredFee = reallyPrice param.ActualFee = actualFee case uuptapi.StateArrivedStore: param.Status = model.WaybillStatusCourierArrived param.DesiredFee = reallyPrice param.ActualFee = actualFee case uuptapi.StatePickUp: param.Status = model.WaybillStatusUuPickUp param.DesiredFee = reallyPrice param.ActualFee = actualFee case uuptapi.StateArrivedDestination: param.Status = model.WaybillStatusUuArrivedDestination param.DesiredFee = reallyPrice param.ActualFee = actualFee case uuptapi.StateReceiverGetGoods: param.Status = model.WaybillStatusDelivered param.DesiredFee = reallyPrice param.ActualFee = actualFee case uuptapi.StateOrderCancel: param.Status = model.WaybillStatusCanceled default: globals.SugarLogger.Warnf("onWaybillMsg unknown State:%v", req.State) } if err := partner.CurOrderManager.OnWaybillStatusChanged(param); err != nil { return uuptapi.Err2CallbackResponse(err) } //推送抖音 switch param.OrderVendorID { case model.VendorIDDD: tiktokStatusPush(param, req.State) case model.VendorIDMTWM, model.VendorIDTaoVegetable: delivery.GetOrderRiderInfoToPlatform(param.VendorOrderID, param.Status) // 骑手位置更新 } return uuptapi.Err2CallbackResponse(nil) } func tiktokStatusPush(param *model.Waybill, orderStatus string) { result := &mtpsapi.RiderInfo{ OrderId: param.VendorOrderID, ThirdCarrierOrderId: param.VendorOrderID, CourierName: param.CourierName, CourierPhone: param.CourierMobile, LogisticsProviderCode: "10002", LogisticsStatus: param.Status, OpCode: "", } switch orderStatus { case uuptapi.StateConfirmSuccess: //下单成功 result.LogisticsStatus = model.WaybillStatusNew result.LogisticsContext = model.RiderWaitRider case uuptapi.StateRMGrabsOrder: //骑手已接单 result.LogisticsStatus = model.WaybillStatusCourierAssigned // 分配骑手 result.LogisticsContext = model.RiderWaitGetGoods case uuptapi.StateArrivedStore: //骑手到店 result.LogisticsStatus = model.WaybillStatusCourierArrived result.LogisticsContext = model.RiderToStore case uuptapi.StatePickUp: //已取件 result.LogisticsStatus = model.WaybillStatusUuPickUp result.LogisticsContext = model.RiderPickUp case uuptapi.StateArrivedDestination: //到达取件人地址处 result.LogisticsStatus = model.WaybillStatusUuArrivedDestination result.LogisticsContext = model.RiderArrivedDestination case uuptapi.StateReceiverGetGoods: //取件人收货 result.LogisticsStatus = model.WaybillStatusDelivered result.LogisticsContext = model.RiderGetOrderDelivered case uuptapi.StateOrderCancel: //运单取消 result.LogisticsStatus = model.WaybillStatusCanceled result.LogisticsContext = model.RiderGetOrderCanceled default: result.LogisticsStatus = 0 result.LogisticsContext = model.RiderGetOrderDeliverOther } delivery.PullTiktokRiderInfo(result) } //辅助函数 func getReallyStoreID(storeID, jxStoreID int) int { if storeID == 0 && jxStoreID == 0 { return 0 } if storeID == 0 { return jxStoreID } else { return storeID } } func (c *DeliveryHandler) UpdateStoreName(storeId, name string) (err error) { return err }