package delivery import ( "errors" "fmt" "math" "time" "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/partner" "git.rosy.net.cn/jx-callback/globals" ) const ( warningDistance = 10 // 公里 warningWeight = 50 * 1000 // 克 maxDiffFee2Mtps = 200 // 与美团配送最多差价 maxAddFee = 200 // 最大增加费用,单位为分,超过不发三方配送了 alarmFee = 1500 // 配送费报警阈值 ) var ( DefCreateWaybillPolicy = CreateWaybillPolicy(maxDiffFee2Mtps, maxAddFee) ) func NullCreateWaybillPolicy(refDeliveryFee, refAddFee, deliveryFee int64) (errStr string) { return "" } func CreateWaybillPolicy(maxDiffFee2Mtps2, maxAddFee2 int64) func(refDeliveryFee, refAddFee, deliveryFee int64) (errStr string) { if maxDiffFee2Mtps2 == 0 { maxDiffFee2Mtps2 = maxDiffFee2Mtps } if maxAddFee2 == 0 { maxAddFee2 = maxAddFee } return func(refDeliveryFee, refAddFee, deliveryFee int64) (errStr string) { if deliveryFee-refDeliveryFee > maxDiffFee2Mtps2 { errStr = fmt.Sprintf("超参考价太多, 费用:%d,参考价:%d, 最高超价:%d", deliveryFee, refDeliveryFee, maxDiffFee2Mtps2) } else if refAddFee > maxAddFee2 { errStr = fmt.Sprintf("超基础价太多, 当前加价:%d, 最高加价:%d", refAddFee, maxAddFee2) } return errStr } } func AddPolicy(prevPolicy, newPolicy partner.CreateWaybillPolicy) (outPolicy partner.CreateWaybillPolicy) { return func(refDeliveryFee, refAddFee, deliveryFee int64) (errStr string) { if errStr = prevPolicy(refDeliveryFee, refAddFee, deliveryFee); errStr == "" { errStr = newPolicy(refDeliveryFee, refAddFee, deliveryFee) } return errStr } } func CallCreateWaybillPolicy(policy partner.CreateWaybillPolicy, refDeliveryFee, refAddFee, deliveryFee int64, order *model.GoodsOrder, waybillVendorID int) (err error) { waybillVendorName := jxutils.GetVendorName(waybillVendorID) globals.SugarLogger.Debugf("CallCreateWaybillPolicy orderID:%s, refDeliveryFee:%d, refAddFee:%d, deliveryFee:%d, waybillVendor:%s", order.VendorOrderID, refDeliveryFee, refAddFee, deliveryFee, waybillVendorName) if policy == nil { policy = NullCreateWaybillPolicy } if errStr := policy(refDeliveryFee, refAddFee, deliveryFee); errStr != "" { errStr = fmt.Sprintf("oderID:%s创建运单出错:%s", order.VendorOrderID, errStr) globals.SugarLogger.Debugf("%s CallCreateWaybillPolicy failed with %s", waybillVendorName, errStr) return errors.New(errStr) } return nil } func CalculateOrderDeliveryFee(order *model.GoodsOrder, billTime time.Time, db *dao.DaoDB) (deliveryFee, addFee int64, err error) { globals.SugarLogger.Debugf("CalculateOrderDeliveryFee orderID:%s", order.VendorOrderID) if db == nil { db = dao.GetDB() } jxStoreID := jxutils.GetSaleStoreIDFromOrder(order) var lng, lat float64 priceInfo := &struct { Price int Lng int Lat int }{} if err = dao.GetRow(db, priceInfo, ` SELECT t2.mtps_price price, t1.lng, t1.lat FROM store t1 JOIN place t2 ON t1.city_code = t2.code WHERE t1.id = ? AND t1.deleted_at = ? `, jxStoreID, utils.DefaultTimeValue); err != nil { return 0, 0, err } lng = jxutils.IntCoordinate2Standard(priceInfo.Lng) lat = jxutils.IntCoordinate2Standard(priceInfo.Lat) deliveryFee = int64(priceInfo.Price) if deliveryFee == 0 { globals.SugarLogger.Warnf("CalculateOrderDeliveryFee 查不到美团配送价格 orderID:%s", order.VendorOrderID) deliveryFee = 650 } if lng == 0 || lat == 0 { globals.SugarLogger.Infof("[运营]计算订单配送费orderID:%s,门店:%d没有坐标信息", order.VendorOrderID, jxutils.GetSaleStoreIDFromOrder(order)) return 0, 0, fmt.Errorf("找不到门店:%d的坐标", jxutils.GetSaleStoreIDFromOrder(order)) } lng2, lat2, _ := jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType) var distanceAddFee, weightAddFee, timeAddFee int64 distance := jxutils.EarthDistance(lng, lat, lng2, lat2) * 1.4 if distance < 3 { } else if distance < 5 { distanceAddFee = jxutils.StandardPrice2Int(math.Ceil(distance - 3)) } else { distanceAddFee = jxutils.StandardPrice2Int(2 + 2*math.Ceil(distance-5)) if distance > warningDistance { globals.SugarLogger.Infof("[运营]计算订单配送费orderID:%s,距离%.3fkm太远,请检查门店坐标信息", order.VendorOrderID, distance) } } globals.SugarLogger.Debugf("CalculateOrderDeliveryFee orderID:%s", order.VendorOrderID) if order.Weight < 5*1000 { } else if order.Weight < 10*1000 { weightAddFee = jxutils.StandardPrice2Int(0.5 * float64(jxutils.IntWeight2Float(order.Weight)-5)) } else if order.Weight < 20*1000 { weightAddFee = jxutils.StandardPrice2Int(2.5 + 1*float64(jxutils.IntWeight2Float(order.Weight)-10)) } else { weightAddFee = jxutils.StandardPrice2Int(2.5 + 10 + 2*float64(jxutils.IntWeight2Float(order.Weight)-20)) if order.Weight > warningWeight { globals.SugarLogger.Infof("[运营]计算订单配送费orderID:%s,重量:%dg太重,请检查商品属性", order.VendorOrderID, order.Weight) } } hour, min, sec := billTime.Clock() totalSeconds := hour*3600 + min*60 + sec // 午高峰加价 if totalSeconds >= 11*3600 && totalSeconds <= 14*3600 { // 11:00 -- 14:00 timeAddFee = jxutils.StandardPrice2Int(3) } // 夜间加价 // else if totalSeconds >= 21*3600 || totalSeconds <= 6*3600 { // 21:00 -- 06:00 // timeAddFee = jxutils.StandardPrice2Int(3) // } addFee = distanceAddFee + weightAddFee + timeAddFee globals.SugarLogger.Debugf("CalculateOrderDeliveryFee orderID:%s, deliveryFee:%d addFee:%d, distance:%.3fkm distanceAddFee:%d, weight:%dg weightAddFee:%d, time:%s timeAddFee:%d", order.VendorOrderID, deliveryFee, addFee, distance, distanceAddFee, order.Weight, weightAddFee, utils.Time2TimeStr(billTime), timeAddFee) return deliveryFee + addFee, addFee, nil } func CalculateBillDeliveryFee(bill *model.Waybill) (deliveryFee, addFee int64) { order, err := partner.CurOrderManager.LoadOrder(bill.VendorOrderID, bill.OrderVendorID) if err != nil { return 0, 0 } deliveryFee, addFee, _ = CalculateOrderDeliveryFee(order, bill.StatusTime, nil) return deliveryFee, addFee } func OnWaybillCreated(waybill *model.Waybill) { deliveryFee := int64(math.Max(float64(waybill.DesiredFee), float64(waybill.ActualFee))) if deliveryFee > alarmFee { globals.SugarLogger.Infof("[运营]%s订单, orderID:%s, 成功创建%s运单:%s, 配送费:%s太高(大于%s),请知悉!", model.VendorChineseNames[waybill.OrderVendorID], waybill.VendorOrderID, model.VendorChineseNames[waybill.WaybillVendorID], waybill.VendorWaybillID, jxutils.IntPrice2StandardCurrencyString(deliveryFee), jxutils.IntPrice2StandardCurrencyString(alarmFee)) } }