Files
jx-callback/business/partner/delivery/dada/waybill.go

247 lines
8.5 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 dada
import (
"errors"
"fmt"
"time"
"git.rosy.net.cn/baseapi/platformapi/dadaapi"
"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/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公斤
maxDiffFee2Mtps = 100 // 与美团配送最多差价
)
var (
ErrCanNotFindDadaCityCode = errors.New("不能找到美团配送站点配置")
ErrExceedMaxDiffFee2Mtps = errors.New("与美团配送超价太多")
)
var (
CurDeliveryHandler *DeliveryHandler
)
type DeliveryHandler struct {
}
func init() {
CurDeliveryHandler = new(DeliveryHandler)
partner.RegisterDeliveryPlatform(CurDeliveryHandler, true)
}
func OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) {
return CurDeliveryHandler.OnWaybillMsg(msg)
}
func (c *DeliveryHandler) GetVendorID() int {
return model.VendorIDDada
}
func (c *DeliveryHandler) OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) {
jxutils.CallMsgHandler(func() {
retVal = c.onWaybillMsg(msg)
}, msg.OrderID)
return retVal
}
func (c *DeliveryHandler) onWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) {
order := c.callbackMsg2Waybill(msg)
switch msg.OrderStatus {
case dadaapi.OrderStatusWaitingForAccept:
order.Status = model.WaybillStatusNew
case dadaapi.OrderStatusAccepted:
if result, err := api.DadaAPI.QueryOrderInfo(msg.OrderID); err == nil {
order.ActualFee = jxutils.StandardPrice2Int(utils.Interface2FloatWithDefault(result["actualFee"], 0.0))
order.DesiredFee = jxutils.StandardPrice2Int(utils.Interface2FloatWithDefault(result["deliveryFee"], 0.0))
}
order.Status = model.WaybillStatusAccepted
case dadaapi.OrderStatusDelivering:
order.Status = model.WaybillStatusDelivering
case dadaapi.OrderStatusFinished:
order.Status = model.WaybillStatusDelivered
case dadaapi.OrderStatusCanceled:
order.Status = model.WaybillStatusCanceled
case dadaapi.OrderStatusExpired, dadaapi.OrderStatusAddOrderFailed:
order.Status = model.WaybillStatusFailed
default:
order.Status = model.WaybillStatusUnknown
}
return dadaapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), utils.Int2Str(order.Status))
}
func (c *DeliveryHandler) callbackMsg2Waybill(msg *dadaapi.CallbackMsg) (retVal *model.Waybill) {
retVal = &model.Waybill{
VendorWaybillID: msg.ClientID,
WaybillVendorID: model.VendorIDDada,
CourierName: msg.DmName,
CourierMobile: msg.DmMobile,
VendorStatus: utils.Int2Str(msg.OrderStatus),
Remark: msg.CancelReason,
// StatusTime: utils.Timestamp2Time(int64(msg.UpdateTime)),
}
// dada太扯了不同消息过来的时间格式不一样
updateTime := int64(msg.UpdateTime)
if updateTime > 2511789475 {
updateTime = updateTime / 1000
}
retVal.StatusTime = utils.Timestamp2Time(updateTime)
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 {
return nil, err
}
if policy != nil {
if err = policy(deliveryFee, addFee); err != nil {
return nil, err
}
}
billParams := &dadaapi.OperateOrderRequiredParams{
// ShopNo: utils.Int2Str(order.StoreID), // 当前达达的门店号与京西是一样的
OriginID: jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID),
CargoPrice: jxutils.IntPrice2Standard(limitOrderPrice(order.ActualPayPrice)),
IsPrepay: 0,
ReceiverName: utils.FilterMb4(order.ConsigneeName),
ReceiverAddress: utils.FilterMb4(order.ConsigneeAddress),
ReceiverPhone: order.ConsigneeMobile,
}
if billParams.ShopNo, err = c.getDadaShopID(order, db); err == nil {
if billParams.CityCode, err = c.getDataCityCodeFromOrder(order, db); err == nil {
billParams.ReceiverLng, billParams.ReceiverLat, _ = jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType)
addParams := map[string]interface{}{
"info": utils.FilterMb4(order.BuyerComment),
// "origin_mark": model.VendorChineseNames[order.VendorID],
"origin_mark_no": fmt.Sprintf("%d", order.OrderSeq),
"cargo_type": 13,
"cargo_weight": jxutils.IntWeight2Float(limitOrderWeight(order.Weight)),
"cargo_num": order.GoodsCount,
}
// 达达要求第二次创建运单,调用函数不同。所以查找两天内有无相同订单号的运单
var lists []orm.ParamsList
num, err2 := db.Raw(`
SELECT vendor_waybill_id
FROM waybill
WHERE waybill_created_at > DATE_ADD(NOW(), interval -2 day)
AND vendor_order_id = ?
AND waybill_vendor_id = ?
`, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), model.VendorIDDada).ValuesList(&lists)
var result *dadaapi.CreateOrderResponse
if err = err2; err == nil && num > 0 {
globals.SugarLogger.Debugf("CreateWaybill orderID:%s num=%d use ReaddOrder", order.VendorOrderID, num)
result, err = api.DadaAPI.ReaddOrder(billParams, addParams)
} else {
if err != nil {
globals.SugarLogger.Warnf("CreateWaybill orderID:%s error:%v", order.VendorOrderID, err)
}
if false {
result, err = api.DadaAPI.AddOrder(billParams, addParams)
} else {
if result, err = api.DadaAPI.QueryDeliverFee(billParams, addParams); err != nil {
return nil, err
}
dadaFee := jxutils.StandardPrice2Int(result.Fee)
if dadaFee-deliveryFee > maxDiffFee2Mtps {
globals.SugarLogger.Infof("CreateWaybill orderID:%s 达达与美团配送超价太多,达达:%d美团配送:%d", order.VendorOrderID, dadaFee, deliveryFee)
return nil, ErrExceedMaxDiffFee2Mtps
}
err = api.DadaAPI.AddOrderAfterQuery(result.DeliveryNo)
}
}
if err == nil && result != nil {
bill = &model.Waybill{
VendorOrderID: order.VendorOrderID,
OrderVendorID: order.VendorID,
WaybillVendorID: model.VendorIDDada,
DesiredFee: deliveryFee,
ActualFee: jxutils.StandardPrice2Int(result.Fee),
}
}
}
}
return bill, err
}
func (c *DeliveryHandler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
switch cancelReasonID {
case partner.CancelWaybillReasonNotAcceptIntime:
cancelReasonID = dadaapi.ReasonIDNobodyAccept
case partner.CancelWaybillReasonSwitch2SelfFailed:
cancelReasonID = dadaapi.ReasonIDClientDontWantItAnymore
default:
cancelReasonID = dadaapi.ReasonIDOther
}
_, err = api.DadaAPI.CancelOrder(bill.VendorOrderID, cancelReasonID, cancelReason)
return err
}
func (c *DeliveryHandler) getDataCityCodeFromOrder(order *model.GoodsOrder, db orm.Ormer) (retVal string, err error) {
jxStoreID := jxutils.GetSaleStoreIDFromOrder(order)
sql := `
SELECT t2.tel_code
FROM store t1
JOIN place t2 on t1.city_code = t2.code
WHERE t1.id = ?
`
db2 := dao.WrapDB(db)
codeInfo := &struct {
TelCode string
}{}
if err = dao.GetRow(db2, codeInfo, sql, jxStoreID); err != nil {
globals.SugarLogger.Errorf("GetDataCityCodeFromOrder can not find store info for vendorID:%d, store:%s, error:%v", order.VendorID, order.VendorStoreID, err)
if err == nil {
err = ErrCanNotFindDadaCityCode
}
return "", err
}
return codeInfo.TelCode, nil
}
func (c *DeliveryHandler) getDadaShopID(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.VendorIDDada)
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 limitOrderPrice(price int64) int64 {
if price > maxOrderPrice {
return maxOrderPrice
}
return price
}
func limitOrderWeight(weight int) int {
if weight > maxOrderWeight {
return maxOrderWeight
}
return weight
}