package defsch import ( "fmt" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/jxstore/cms" "math" "math/rand" "time" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/business/jxcallback/scheduler" "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" ) func (s *DefScheduler) loadSavedOrderByID(vendorOrderID string, vendorID int, isForceLoad bool) *WatchOrderInfo { return s.loadSavedOrderFromMap(&model.OrderStatus{ RefVendorOrderID: vendorOrderID, RefVendorID: vendorID, }, isForceLoad) } func (s *DefScheduler) SelfDeliveringAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName, courierName, courierMobile string) (err error) { var order *model.GoodsOrder jxutils.CallMsgHandler(func() { err = func() (err error) { savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true) if savedOrderInfo != nil { order = savedOrderInfo.order if err = s.isPossibleSwitch2SelfDelivery(order); err == nil { // 是否能转自送 err = s.cancelOtherWaybillsCheckOrderDeliveryFlag(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive) if err == nil { if model.IsOrderDeliveryByStore(order) { if order.Status < model.OrderStatusDelivering { storeDetail, err2 := dao.GetStoreDetail(dao.GetDB(), order.StoreID, order.VendorID, "") phone := userName if err = err2; err == nil { phone = storeDetail.Tel1 } err = s.SelfDeliverDelivering(order, phone) // 取消平台自配送 s.CancelAll3rdWaybills(ctx, vendorOrderID, vendorID, true) // 取消三方平台配送以及调度 } } else { if order.Status < model.OrderStatusDelivering { err = s.Swtich2SelfDeliver(order, userName) } else if order.VendorID == order.WaybillVendorID { // 状态为配送中,且是购物平台运单,不能转自送了 err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation } } } } if err == nil { order.Status = model.OrderStatusDelivering order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled | model.OrderDeliveryFlagMaskPurcahseDisabled if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil { s.stopTimer(savedOrderInfo) //return err } } } else { order = &model.GoodsOrder{ VendorOrderID: vendorOrderID, VendorID: vendorID, } err = scheduler.ErrCanNotFindOrder } vendorStatus := fmt.Sprintf("%s转商户自送成功", ctx.GetUserName()) remark := "" if err != nil { vendorStatus = fmt.Sprintf("%s转商户自送失败", ctx.GetUserName()) remark = err.Error() partner.CurOrderManager.OnOrderMsg(order, vendorStatus, remark) return err } else { partner.CurOrderManager.OnOrderMsg(order, vendorStatus, remark) } // 上面是真的转自送,支持美团,饿百,京东,如果时抖店,抖店暂时全部是自送的!但是有骑手信息时,就是一个白嫖单子! if courierName != "" && courierMobile != "" && err == nil { timeNow := time.Now() rand.Seed(timeNow.UnixNano()) randNumber := rand.Int63n(640) if randNumber < 60 { randNumber += 60 } randTime := time.Duration(randNumber) * time.Second bill := &model.Waybill{ VendorWaybillID: order.VendorOrderID, VendorWaybillID2: "", WaybillVendorID: model.VendorJXFakeWL, VendorOrderID: order.VendorOrderID, OrderVendorID: order.VendorID, CourierName: courierName, CourierMobile: courierMobile, Status: model.OrderStatusNew, VendorStatus: utils.Int2Str(model.OrderStatusNew), ActualFee: 0, DesiredFee: 0, TipFee: 0, DuplicatedCount: 0, DeliveryFlag: 0, WaybillCreatedAt: timeNow, WaybillFinishedAt: utils.DefaultTimeValue, StatusTime: timeNow.Add(randTime), // 下一状态时间 OriginalData: "", Remark: "自定义物流单(全平台刷单)", VendorOrgCode: order.VendorOrgCode, } err = dao.CreateEntity(dao.GetDB(), bill) //if order.VendorID == model.VendorIDTaoVegetable { // order.VendorWaybillID = order.VendorOrderID // order.WaybillVendorID = model.VendorJXFakeWL // dao.UpdateEntity(dao.GetDB(), order, "VendorWaybillID", "WaybillVendorID") //} } return err }() }, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID)) return err } func (s *DefScheduler) canOrderCreateWaybillNormally(order *model.GoodsOrder, savedOrderInfo *WatchOrderInfo) (err error) { if !(order.LockStatus != model.OrderStatusLocked && order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) { err = fmt.Errorf("当前订单%s没有处于拣货完成且没有结束没有锁定的订单才能进行召唤配送操作", order.VendorOrderID) } else if model.IsOrderHaveWaybill(order) { err = fmt.Errorf("当前订单%s已经有了有效的承运人%s了", order.VendorOrderID, jxutils.GetVendorName(order.WaybillVendorID)) } return err } func (s *DefScheduler) isPossibleSwitch2SelfDelivery(order *model.GoodsOrder) (err error) { //TODO 刷单用,之后不刷单了删除 //if order.VendorID == model.VendorIDDD { // return nil //} if model.IsOrderDeliveryByPlatform(order) { if order.Status < model.OrderStatusFinishedPickup { err = fmt.Errorf("拣货完成后才能转自配送") } else if order.Status == model.OrderStatusFinishedPickup { if time.Now().Sub(order.StatusTime) < minMinute2Schedule3rdCarrier*time.Minute { err = fmt.Errorf("非自配送门店转3方配送至少要求拣货完成后%d分钟才能操作", minMinute2Schedule3rdCarrier) } } else if order.Status >= model.OrderStatusDelivering && order.Status < model.OrderStatusEndBegin { if model.IsOrderHaveOwnWaybill(order) { err = fmt.Errorf("%s物流已在配送中,不能转自配送", jxutils.GetVendorName(order.VendorID)) } } else if order.Status >= model.OrderStatusEndBegin { err = fmt.Errorf("订单%s已经结束,请刷新状态", order.VendorOrderID) } } return err } // 创建订单 func (s *DefScheduler) CreateWaybillOnProviders4SavedOrder(ctx *jxcontext.Context, savedOrderInfo *WatchOrderInfo, courierVendorIDs, excludeCourierVendorIDs []int, forceCreate bool, maxDeliveryFee int64) (bills []*model.Waybill, err error) { order := savedOrderInfo.order // 查看订单状态是否处于可配送状态 if !forceCreate { err = s.canOrderCreateWaybillNormally(order, nil) } // 检查订单是否在配送状态 waybills, err := dao.GetWaybills(dao.GetDB(), order.VendorOrderID, nil) for _, v := range waybills { if v.Status >= model.OrderStatusDelivering && v.Status != model.OrderStatusCanceled && v.Status != model.OrderStatusFinished { err = fmt.Errorf("订单已经在配送中,无法创建运单,有疑问请联系管理员") break } } if err == nil { if forceCreate { maxDeliveryFee = math.MaxInt64 } // 生成美团订单(三方订单) if bills, err = s.CreateWaybillOnProviders(ctx, order, courierVendorIDs, excludeCourierVendorIDs, maxDeliveryFee, forceCreate); err == nil { if forceCreate { order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order) } if err == nil { if forceCreate { s.stopTimer(savedOrderInfo) } // 获取门店品牌余额 storeAcct, err := cms.GetStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order)) // 获取门店余额 // 门店详细信息 storeList, err := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), savedOrderInfo.order.VendorID, order.VendorOrgCode) if err != nil { return nil, err } deliveryFeeMap, _ := s.QueryOrderWaybillFeeInfoEx(ctx, order.VendorOrderID, order.VendorID) // 不管是门店发单还是品牌发单都要扣钱,门店发单扣门店,品牌发单扣品牌 if order.CreateDeliveryType == model.YES { // 获取平台配送费 isEqual, isZero, _ := partner.CurStoreAcctManager.CheckStoreAcctExpendExist(order.VendorOrderID) // 当前订单的支出记录 expend, lastFee, _ := partner.CurStoreAcctManager.GetStoreAcctExpendLastCreateWayBillFee(order.VendorOrderID) // 最后一个运单支出记录 // 收最贵的一个订单配送费(配送费发送变化,收取最贵的价格) if !isZero && !isEqual { // 满足此条件是,门店发单已经存在此订单的发单记录,且支出记录大于退还记录 var newPrice int64 if len(courierVendorIDs) == 1 { courierVendorID := courierVendorIDs[0] if _, ok := deliveryFeeMap[courierVendorID]; ok { newPrice = deliveryFeeMap[courierVendorID].DeliveryFee } } else if len(courierVendorIDs) == 0 { var maxFee int64 for _, v := range deliveryFeeMap { if v.DeliveryFee > maxFee { maxFee = v.DeliveryFee } } newPrice = maxFee } // 门店支出运费,门店发单 if order.CreateDeliveryType == model.YES { if storeAcct.AccountBalance > int(newPrice) { if int(newPrice) > lastFee { // 门店支出费用 partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(newPrice)-lastFee, partner.StoreAcctTypeExpendCreateWaybill2ndMore, order.VendorOrderID, "", expend.ID) //int(newPrice)-lastFee } } } } else { // 新订单的发单记录,门店发单扣门店,品牌发单扣品牌 if len(courierVendorIDs) == 1 { courierVendorID := courierVendorIDs[0] if _, ok := deliveryFeeMap[courierVendorID]; ok { if order.CreateDeliveryType == model.YES { err = partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(deliveryFeeMap[courierVendorID].DeliveryFee), partner.StoreAcctTypeExpendCreateWaybillEx, order.VendorOrderID, "", 0) //int(newPrice)-lastFee } } } else if len(courierVendorIDs) == 0 { var maxFee int64 for _, v := range deliveryFeeMap { if v.DeliveryFee > maxFee { maxFee = v.DeliveryFee } } err = partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(maxFee), partner.StoreAcctTypeExpendCreateWaybillEx, order.VendorOrderID, "", 0) //int(maxFee) } } } else { // 看看此订单有无发单记录,小费记录 // 品牌发单 if len(courierVendorIDs) == 1 { courierVendorID := courierVendorIDs[0] if _, ok := deliveryFeeMap[courierVendorID]; ok { err = partner.CurStoreAcctManager.InsertBrandBill(jxcontext.AdminCtx, storeList.BrandID, int(deliveryFeeMap[courierVendorID].DeliveryFee), model.BrandBillTypeExpend, model.BrandBillFeeTypeDelivery, order.VendorOrderID, order.VendorWaybillID) } } else if len(courierVendorIDs) == 0 { var maxFee int64 for _, v := range deliveryFeeMap { if v.DeliveryFee > maxFee { maxFee = v.DeliveryFee } } err = partner.CurStoreAcctManager.InsertBrandBill(jxcontext.AdminCtx, storeList.BrandID, int(maxFee), model.BrandBillTypeExpend, model.BrandBillFeeTypeDelivery, order.VendorOrderID, order.VendorWaybillID) } } } return bills, err } } if err != nil { globals.SugarLogger.Debugf("CreateWaybillOnProviders4SavedOrder orderID:%s failed with error:%v", order.VendorOrderID, err) } return nil, err } // 创建三方运单 func (s *DefScheduler) CreateWaybillOnProvidersEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int, courierVendorIDs []int, forceCreate bool, maxDeliveryFee int64) (bills []*model.Waybill, errCode string, err error) { savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true) if savedOrderInfo != nil { order := savedOrderInfo.order //1表示为门店发单,需要验证门店账户余额情况 if errCode, err = s.CheckStoreBalance(ctx, order, courierVendorIDs); err != nil { return nil, errCode, err } } billFunc := func() { bills, err = func() (bills []*model.Waybill, err error) { if vendorID == model.VendorIDELM { return nil, fmt.Errorf("不要直接使用饿了么订单号,请使用相应的饿百订单号") } // 创建可调度对象,并且存储 savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true) if savedOrderInfo != nil { savedOrderInfo.order.SendOrderType = 1 // 设置为手动创建订单 order := savedOrderInfo.order if order.DeliveryType == model.OrderDeliveryTypeSelfTake { return nil, fmt.Errorf("订单:%s是自提单", vendorOrderID) } if !forceCreate { err = s.isPossibleSwitch2SelfDelivery(order) } if err == nil { if savedOrderInfo.order.VendorID == model.VendorIDEBAI { courierVendorIDs = []int{model.VendorIDMTPS, model.VendorIDDada} } order := savedOrderInfo.order order.DeliveryFlag = 0 err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order) // 创建订单 if bills, err = s.CreateWaybillOnProviders4SavedOrder(ctx, savedOrderInfo, courierVendorIDs, nil, forceCreate, maxDeliveryFee); err == nil && len(bills) > 0 { partner.CurOrderManager.OnOrderMsg(order, "手动创建运单成功", fmt.Sprintf("%s创建%s平台运单,强发:%t,最高限价:%d", ctx.GetUserName(), model.VendorChineseNames[bills[0].WaybillVendorID], forceCreate, maxDeliveryFee)) } } } else { err = scheduler.ErrCanNotFindOrder } return bills, err }() } jxutils.CallMsgHandler(billFunc, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID)) return bills, errCode, err } func (s *DefScheduler) CheckStoreBalance(ctx *jxcontext.Context, order *model.GoodsOrder, courierVendorIDs []int) (errCode string, err error) { var ( db = dao.GetDB() ) deliveryFeeMap, _ := s.QueryOrderWaybillFeeInfoEx(ctx, order.VendorOrderID, order.VendorID) if err != nil { return errCode, fmt.Errorf("获取订单配送费错误[%v]!", err) } switch order.CreateDeliveryType { case model.NO: // 品牌发单 storeDetail, err := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "") if err != nil { return "", err } brandAcct, err := dao.GetBrandBalance(db, storeDetail.BrandID) if err != nil { return "", err } if len(courierVendorIDs) == 1 { courierVendorID := courierVendorIDs[0] if _, ok := deliveryFeeMap[courierVendorID]; ok { if deliveryFeeMap[courierVendorID].DeliveryFee > int64(brandAcct) { return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("品牌账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(deliveryFeeMap[courierVendorID].DeliveryFee)) } } } else if len(courierVendorIDs) == 0 { var maxFee int64 for _, v := range deliveryFeeMap { if v.DeliveryFee > maxFee { v.DeliveryFee = maxFee } } if maxFee > int64(brandAcct) { return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("品牌账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(maxFee)) } } case model.YES: // 门店发单 //暂时这么认为,len courierVendorIDs 为1表示是老板或者运营从小程序上点的立即发单,因为小程序上是点哪个发哪个 //京西后台则是点一下发3个,len courierVendorIDs 是0 //如果是小程序上点哪个扣哪个平台的钱 //如果是后台,则选最高的那个扣 storeAcct, err := cms.GetStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order)) // 获取门店余额 if err != nil { return "", err } //1、先判断是不是第一次发:查询库里是否有这个订单的运费支出记录,再查询是否有相同金额并且类型为回退的收入记录(取消运单退回) //前者有,后者无, 表示已经发过了,暂未取消,若这这次的发单金额小于上次的金额则不进行判断也不多扣钱,若大于则扣除‘这次金额-上次金额’的钱,余额不足问题也根据这个判断 //前者有,后者有,表示发过并且取消过了,是多次发,直接扣 //前者无,表示就是第一次发,直接扣 //2、小程序里这次金额用发单平台的金额,后台里这次金额用所有平台最高费用 isEqual, isZero, err := partner.CurStoreAcctManager.CheckStoreAcctExpendExist(order.VendorOrderID) //表示前者有,后者无 if !isZero && !isEqual { // 当前订单支出费用大于,退还费用 var newPrice int64 if len(courierVendorIDs) == 1 { courierVendorID := courierVendorIDs[0] if _, ok := deliveryFeeMap[courierVendorID]; ok { newPrice = deliveryFeeMap[courierVendorID].DeliveryFee } } else if len(courierVendorIDs) == 0 { var maxFee int64 for _, v := range deliveryFeeMap { if v.DeliveryFee > maxFee { v.DeliveryFee = maxFee } } newPrice = maxFee } _, lastFee, _ := partner.CurStoreAcctManager.GetStoreAcctExpendLastCreateWayBillFee(order.VendorOrderID) // 如果门店属于京西菜市,京西果园则只能扣门店的金额 if int(newPrice) > lastFee { if storeAcct.AccountBalance < int(newPrice)-lastFee /*&& result < int(newPrice)-lastFee*/ { return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(newPrice-int64(lastFee))) } } } else { if len(courierVendorIDs) == 1 { courierVendorID := courierVendorIDs[0] if _, ok := deliveryFeeMap[courierVendorID]; ok { if deliveryFeeMap[courierVendorID].DeliveryFee > int64(storeAcct.AccountBalance) { return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(deliveryFeeMap[courierVendorID].DeliveryFee)) } } } else if len(courierVendorIDs) == 0 { var maxFee int64 for _, v := range deliveryFeeMap { if v.DeliveryFee > maxFee { v.DeliveryFee = maxFee } } if maxFee > int64(storeAcct.AccountBalance) { return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(maxFee)) } } } default: return "", fmt.Errorf("不存在的订单发单类型,检查配置") } return errCode, err } // todo 这个函数可以和SelfDeliveringAndUpdateStatus合并 func (s *DefScheduler) CancelAll3rdWaybills(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isStopSchedule bool) (err error) { jxutils.CallMsgHandler(func() { err = func() (err error) { // 取消三方运单,取消各平台单号信息,间隔一段时间后定时任务重新调度 savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true) if savedOrderInfo != nil { err = s.cancelOtherWaybills(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive) } else { err = scheduler.ErrCanNotFindOrder } // 停止调度,同事停止订单调度,不在通知第三方 if err == nil && isStopSchedule { order := savedOrderInfo.order order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil { s.stopTimer(savedOrderInfo) } } return err }() }, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID)) return err } // 查询三方运单费用 func (s *DefScheduler) QueryOrderWaybillFeeInfoEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int) (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) { jxutils.CallMsgHandler(func() { deliveryFeeMap, err = func() (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) { db := dao.GetDB() order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID) if err != nil { return nil, err } if order.DeliveryType == model.OrderDeliveryTypeSelfTake { return nil, fmt.Errorf("订单:%s是自提单", vendorOrderID) } // 获取用户送货地址 storeCourierList, err := dao.GetStoreCourierList(db, []int{jxutils.GetSaleStoreIDFromOrder(order)}, nil, model.StoreStatusAll, model.StoreAuditStatusOnline) if err != nil { return nil, err } // 美团配送订单兑现 waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(ctx, vendorOrderID, vendorID, true, false) if err != nil { return nil, err } waybillMap := make(map[int]*model.Waybill) for _, bill := range waybillList { waybillMap[bill.WaybillVendorID] = &bill.Waybill } deliveryFeeMap = make(map[int]*partner.WaybillFeeInfo) var timeoutSecond int if savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, false); savedOrderInfo != nil { timeoutSecond = savedOrderInfo.GetCreateWaybillTimeout() } store, _ := dao.GetStoreDetail(db, order.JxStoreID, order.VendorID, order.VendorOrgCode) for _, storeCourier := range storeCourierList { var feeInfo *partner.WaybillFeeInfo if waybillMap[storeCourier.VendorID] != nil { feeInfo = &partner.WaybillFeeInfo{ Waybill: waybillMap[storeCourier.VendorID], } } else { if storeCourier.Status != model.StoreStatusOpened { feeInfo = &partner.WaybillFeeInfo{ ErrCode: partner.WaybillFeeErrCodeCourierNotOpen, ErrStr: fmt.Sprintf("暂未开通,联系运营"), } } else { if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil { if handler.Use4CreateWaybill { // 获取订单配送费用 feeInfo, err = handler.Handler.GetWaybillFee(order) if err != nil { feeInfo = &partner.WaybillFeeInfo{ ErrCode: partner.WaybillFeeErrCodeCourierOthers, ErrStr: err.Error(), } } else { feeInfo.DeliveryFee += model.WayBillDeliveryMarkUp // 加收两毛 if storeCourier.VendorID == model.VendorIDFengNiao { feeInfo.DeliveryFee += model.WayBillDeliveryMarkUp // 蜂鸟加 } feeInfo.DeliveryFee += int64(store.FreightMarkup) feeInfo.TimeoutSecond = timeoutSecond } } else { feeInfo = &partner.WaybillFeeInfo{ ErrCode: partner.WaybillFeeErrCodeCourierForbidden, ErrStr: fmt.Sprintf("内部错误,%d不能用于创建运单", storeCourier.VendorID), } } } else { feeInfo = &partner.WaybillFeeInfo{ ErrCode: partner.WaybillFeeErrCodeCourierNotSupported, ErrStr: fmt.Sprintf("内部错误,%d不被支持", storeCourier.VendorID), } } } } deliveryFeeMap[storeCourier.VendorID] = feeInfo } err = nil return deliveryFeeMap, err }() }, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID)) return deliveryFeeMap, err }