Files
jx-callback/business/controller/mtps/waybill.go

234 lines
8.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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/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), true)
}
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{},
}
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.SplitSkuName(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 := utils.Params2Map("note", order.BuyerComment, "goods_detail", string(utils.MustMarshal(goods)))
_, err = api.MtpsAPI.CreateOrderByShop(billParams, addParams)
if err != nil {
globals.SugarLogger.Debugf("CreateWaybill, orderID:%s, billParams:%v, addParams:%v", order.VendorOrderID, 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
}
func (c *WaybillController) getDeliveryID(order *model.GoodsOrder, db orm.Ormer) (retVal int64, err error) {
// jxorder表当前已经有50多万条记录了加100万避免冲突
// 508505
return order.ID + 1000000, nil
}
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.Infof("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
}