- refactor file structure.
This commit is contained in:
175
business/partner/delivery/dada/waybill.go
Normal file
175
business/partner/delivery/dada/waybill.go
Normal file
@@ -0,0 +1,175 @@
|
||||
package dada
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dadaapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
const (
|
||||
maxCargoPrice = 63.99 // 单位为元,达达最大价格,超过这个价格配送费会增加
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCanNotFindDadaCityCode = errors.New("不能找到美团配送站点配置")
|
||||
)
|
||||
|
||||
type WaybillController struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
scheduler.CurrentScheduler.RegisterDeliveryPlatform(model.VendorIDDada, new(WaybillController), true)
|
||||
}
|
||||
|
||||
func (c *WaybillController) OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onWaybillMsg(msg)
|
||||
}, msg.OrderID)
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *WaybillController) 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.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 *WaybillController) 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 *WaybillController) CreateWaybill(order *model.GoodsOrder) (err error) {
|
||||
billParams := &dadaapi.OperateOrderRequiredParams{
|
||||
ShopNo: utils.Int2Str(order.StoreID), // 当前达达的门店号与京西是一样的
|
||||
OriginID: jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID),
|
||||
CargoPrice: jxutils.IntPrice2Standard(order.ActualPayPrice),
|
||||
IsPrepay: 0,
|
||||
ReceiverName: order.ConsigneeName,
|
||||
ReceiverAddress: order.ConsigneeAddress,
|
||||
ReceiverPhone: order.ConsigneeMobile,
|
||||
}
|
||||
if billParams.CargoPrice > maxCargoPrice {
|
||||
billParams.CargoPrice = maxCargoPrice
|
||||
}
|
||||
db := orm.NewOrm()
|
||||
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": order.BuyerComment,
|
||||
// "origin_mark": model.VendorNames[order.VendorID],
|
||||
"origin_mark_no": fmt.Sprintf("%d", order.OrderSeq),
|
||||
}
|
||||
|
||||
// 达达要求第二次创建运单,调用函数不同。所以查找两天内有无相同订单号的运单
|
||||
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)
|
||||
if err2 == nil && num > 0 {
|
||||
globals.SugarLogger.Debugf("CreateWaybill orderID:%s num=%d use ReaddOrder", order.VendorOrderID, num)
|
||||
_, err = api.DadaAPI.ReaddOrder(billParams, addParams)
|
||||
} else {
|
||||
if err2 != nil {
|
||||
globals.SugarLogger.Warnf("CreateWaybill orderID:%s error:%v", order.VendorOrderID, err2)
|
||||
}
|
||||
_, err = api.DadaAPI.AddOrder(billParams, addParams)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *WaybillController) CancelWaybill(bill *model.Waybill) (err error) {
|
||||
reasonID := dadaapi.ReasonIDOther
|
||||
reasonMsg := "send not in time"
|
||||
if bill.Status < model.WaybillStatusAccepted {
|
||||
reasonID = dadaapi.ReasonIDNobodyAccept
|
||||
reasonMsg = "ReasonIDNobodyAccept"
|
||||
} else if bill.Status < model.WaybillStatusCourierArrived {
|
||||
reasonID = dadaapi.ReasonIDNobodyPickup
|
||||
reasonMsg = "ReasonIDNobodyPickup"
|
||||
}
|
||||
_, err = api.DadaAPI.CancelOrder(bill.VendorOrderID, reasonID, reasonMsg)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *WaybillController) getDataCityCodeFromOrder(order *model.GoodsOrder, db orm.Ormer) (retVal string, err error) {
|
||||
var sql string
|
||||
if order.VendorID == model.VendorIDJD {
|
||||
sql = `
|
||||
SELECT t2.tel_code
|
||||
FROM jxstoremap t0
|
||||
JOIN jxstore t1 ON t0.jxstoreid = t1.storeid
|
||||
JOIN city t2 ON t1.area = t2.citycode
|
||||
WHERE t0.jdstoreid = ?
|
||||
`
|
||||
} else if order.VendorID == model.VendorIDELM {
|
||||
sql = `
|
||||
SELECT t2.tel_code
|
||||
FROM jx_to_elm_store_map t0
|
||||
JOIN jxstore t1 ON t0.jx_store_id = t1.storeid
|
||||
JOIN city t2 ON t1.area = t2.citycode
|
||||
WHERE t0.elm_store_id = ?
|
||||
`
|
||||
} else {
|
||||
panic(fmt.Sprintf("wrong vendorid:%d", order.VendorID))
|
||||
}
|
||||
var lists []orm.ParamsList
|
||||
num, err := db.Raw(sql, utils.Str2Int64(order.VendorStoreID)).ValuesList(&lists)
|
||||
if err == nil && num == 1 {
|
||||
retVal = lists[0][0].(string)
|
||||
} else {
|
||||
globals.SugarLogger.Errorf("GetDataCityCodeFromOrder can not find store info for vendorID:%d, store:%s, num:%d, error:%v", order.VendorID, order.VendorStoreID, num, err)
|
||||
if err == nil {
|
||||
err = ErrCanNotFindDadaCityCode
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}
|
||||
45
business/partner/delivery/dada/waybill_test.go
Normal file
45
business/partner/delivery/dada/waybill_test.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package dada
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"git.rosy.net.cn/jx-callback/globals/db"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func init() {
|
||||
beego.InitBeegoBeforeTest("/Users/xujianhua/go/src/git.rosy.net.cn/jx-callback/conf/app.conf")
|
||||
beego.BConfig.RunMode = "dev" // InitBeegoBeforeTest会将runmode设置为test
|
||||
|
||||
globals.Init()
|
||||
db.Init()
|
||||
api.Init()
|
||||
}
|
||||
|
||||
func TestCreateWaybill(t *testing.T) {
|
||||
orderID := "817540316000041"
|
||||
if order, err := orderman.CurOrderManager.LoadOrder(orderID, model.VendorIDJD); err == nil {
|
||||
// globals.SugarLogger.Debug(order)
|
||||
c := new(WaybillController)
|
||||
if err = c.CreateWaybill(order); err == nil {
|
||||
time.Sleep(1 * time.Second)
|
||||
bill := &model.Waybill{
|
||||
VendorOrderID: orderID,
|
||||
WaybillVendorID: model.VendorIDDada,
|
||||
}
|
||||
err = c.CancelWaybill(bill)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
283
business/partner/delivery/mtps/waybill.go
Normal file
283
business/partner/delivery/mtps/waybill.go
Normal file
@@ -0,0 +1,283 @@
|
||||
package mtps
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/mtpsapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"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 (
|
||||
maxAddFee = 200 // 最大增加费用,单位为分,超过不发美团了
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCanNotFindMTPSStore = errors.New("不能找到美团配送站点配置")
|
||||
ErrAddFeeExceeded = errors.New("美团配送超过基准价太多")
|
||||
ErrStoreNoPriceInfo = errors.New("找不到门店的美团配送价格信息")
|
||||
ErrStoreNoCoordinate = 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.WaybillStatusUnknown, // todo 这里要再确定一下是否只要收到订单异常消息就只简单当成一个消息
|
||||
VendorStatus: utils.Int2Str(msg.ExceptionCode),
|
||||
StatusTime: utils.Timestamp2Time(msg.Timestamp),
|
||||
}
|
||||
order.VendorOrderID, order.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID)
|
||||
retVal = mtpsapi.Err2CallbackResponse(partner.CurOrderManager.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.calculateBillDeliveryFee(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(partner.CurOrderManager.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),
|
||||
Remark: msg.CancelReason,
|
||||
}
|
||||
retVal.VendorOrderID, retVal.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID)
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *WaybillController) calculateOrderDeliveryFee(order *model.GoodsOrder, billTime time.Time, db orm.Ormer) (deliveryFee, addFee int64, err error) {
|
||||
var lists []orm.ParamsList
|
||||
if db == nil {
|
||||
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)
|
||||
|
||||
if err == nil && num == 1 {
|
||||
deliveryFee = 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, 0, ErrStoreNoPriceInfo
|
||||
}
|
||||
|
||||
lng := utils.Str2Float64(lists[0][1].(string))
|
||||
lat := utils.Str2Float64(lists[0][2].(string))
|
||||
if lng == 0 || lat == 0 {
|
||||
globals.SugarLogger.Warnf("calculateDeliveryFee can not calculate delivery fee for orderID:%s, because no coordinate info", order.VendorOrderID)
|
||||
return 0, 0, ErrStoreNoCoordinate
|
||||
}
|
||||
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 {
|
||||
addFee += jxutils.StandardPrice2Int(math.Ceil(distance - 3))
|
||||
} else {
|
||||
addFee += jxutils.StandardPrice2Int(2 + 2*math.Ceil(distance-5))
|
||||
}
|
||||
|
||||
if order.Weight < 5*1000 {
|
||||
} else if order.Weight < 10*1000 {
|
||||
addFee += jxutils.StandardPrice2Int(0.5 * float64(order.Weight/1000-5))
|
||||
} else if order.Weight < 20*1000 {
|
||||
addFee += jxutils.StandardPrice2Int(2.5 + 1*float64(order.Weight/1000-10))
|
||||
} else {
|
||||
addFee += jxutils.StandardPrice2Int(2.5 + 10 + 2*float64(order.Weight/1000-20))
|
||||
}
|
||||
|
||||
hour, min, sec := billTime.Clock()
|
||||
totalSeconds := hour*3600 + min*60 + sec
|
||||
if totalSeconds >= 11*3600+30*60 && totalSeconds <= 13*3600 { // 11:30 -- 13:00
|
||||
addFee += jxutils.StandardPrice2Int(3)
|
||||
} else if totalSeconds >= 21*3600 || totalSeconds <= 6*3600 { // 21:00 -- 06:00
|
||||
addFee += jxutils.StandardPrice2Int(3)
|
||||
}
|
||||
return deliveryFee + addFee, addFee, nil
|
||||
}
|
||||
|
||||
func (c *WaybillController) calculateBillDeliveryFee(bill *model.Waybill) (deliveryFee, addFee int64) {
|
||||
order, err := partner.CurOrderManager.LoadOrder(bill.VendorOrderID, bill.OrderVendorID)
|
||||
if err != nil {
|
||||
return 0, 0
|
||||
}
|
||||
deliveryFee, addFee, _ = c.calculateOrderDeliveryFee(order, bill.StatusTime, nil)
|
||||
return deliveryFee, addFee
|
||||
}
|
||||
|
||||
// IDeliveryPlatformHandler
|
||||
func (c *WaybillController) CreateWaybill(order *model.GoodsOrder) (err error) {
|
||||
db := orm.NewOrm()
|
||||
_, addFee, err := c.calculateOrderDeliveryFee(order, time.Now(), db)
|
||||
if err == nil {
|
||||
if addFee <= maxAddFee {
|
||||
// 忽略坐标转换错误,即使是转换出错,也只能当成转换成功来处理,底层会有错误日志输出
|
||||
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.ActualPayPrice), // 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)), "poi_seq", fmt.Sprintf("#%d", order.OrderSeq))
|
||||
_, err = api.MtpsAPI.CreateOrderByShop(billParams, addParams)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("CreateWaybill failed, orderID:%s, billParams:%v, addParams:%v, error:%v", order.VendorOrderID, billParams, addParams, err)
|
||||
|
||||
tmpLog := &legacymodel.TempLog{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
RefVendorOrderID: order.VendorOrderID,
|
||||
IntValue1: addFee,
|
||||
Msg: fmt.Sprintf("CreateWaybill failed, orderID:%s, billParams:%v, addParams:%v, error:%v", order.VendorOrderID, billParams, addParams, err),
|
||||
}
|
||||
db.Insert(tmpLog)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = ErrAddFeeExceeded
|
||||
globals.SugarLogger.Infof("CreateWaybill orderID:%s addFee exceeded too much, it's %d", order.VendorOrderID, addFee)
|
||||
|
||||
tmpLog := &legacymodel.TempLog{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
RefVendorOrderID: order.VendorOrderID,
|
||||
IntValue1: addFee,
|
||||
Msg: fmt.Sprintf("CreateWaybill orderID:%s addFee exceeded too much, it's %d", order.VendorOrderID, addFee),
|
||||
}
|
||||
db.Insert(tmpLog)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *WaybillController) CancelWaybill(bill *model.Waybill) (err error) {
|
||||
reasonID := mtpsapi.CancelReasonRidderSendNotIntime
|
||||
reasonMsg := "CancelReasonRidderSendNotIntime"
|
||||
if bill.Status < model.WaybillStatusAccepted {
|
||||
reasonID = mtpsapi.CancelReasonMerchantOther
|
||||
reasonMsg = "nobody accept order"
|
||||
} else if bill.Status < model.WaybillStatusCourierArrived {
|
||||
reasonID = mtpsapi.CancelReasonRideerGetGoodNotIntime
|
||||
reasonMsg = "CancelReasonRideerGetGoodNotIntime"
|
||||
}
|
||||
_, 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
|
||||
}
|
||||
|
||||
tmpLog := &legacymodel.TempLog{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
RefVendorOrderID: order.VendorOrderID,
|
||||
Msg: fmt.Sprintf("getMTPSShopID can not find mtps store info for orderID:%s, store:%d, num:%d, error:%v", order.VendorOrderID, JxStoreID, num, err),
|
||||
}
|
||||
db.Insert(tmpLog)
|
||||
}
|
||||
return retVal, err
|
||||
}
|
||||
42
business/partner/delivery/mtps/waybill_test.go
Normal file
42
business/partner/delivery/mtps/waybill_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package mtps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"git.rosy.net.cn/jx-callback/globals/db"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func init() {
|
||||
beego.InitBeegoBeforeTest("/Users/xujianhua/go/src/git.rosy.net.cn/jx-callback/conf/app.conf")
|
||||
beego.BConfig.RunMode = "dev" // InitBeegoBeforeTest会将runmode设置为test
|
||||
|
||||
globals.Init()
|
||||
db.Init()
|
||||
api.Init()
|
||||
}
|
||||
|
||||
func TestCreateWaybill(t *testing.T) {
|
||||
orerID := "817109342000022"
|
||||
order, _ := orderman.CurOrderManager.LoadOrder(orerID, model.VendorIDJD)
|
||||
// globals.SugarLogger.Debug(order)
|
||||
c := new(WaybillController)
|
||||
if err := c.CreateWaybill(order); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestCancelWaybill(t *testing.T) {
|
||||
bill := &model.Waybill{
|
||||
VendorWaybillID: "1532332342088966",
|
||||
VendorWaybillID2: "55",
|
||||
}
|
||||
c := new(WaybillController)
|
||||
if err := c.CancelWaybill(bill); err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
52
business/partner/partner.go
Normal file
52
business/partner/partner.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package partner
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
var (
|
||||
CurOrderManager IOrderManager
|
||||
)
|
||||
|
||||
type IOrderManager interface {
|
||||
OnOrderNew(order *model.GoodsOrder, msgVendorStatus string) (err error)
|
||||
OnOrderAdjust(order *model.GoodsOrder, msgVendorStatus string) (err error)
|
||||
OnOrderStatusChanged(orderStatus *model.OrderStatus) (err error)
|
||||
|
||||
OnWaybillStatusChanged(bill *model.Waybill) (err error)
|
||||
|
||||
LoadOrder(vendorOrderID string, vendorID int) (order *model.GoodsOrder, err error)
|
||||
UpdateWaybillVendorID(bill *model.Waybill, revertStatus bool) (err error)
|
||||
}
|
||||
|
||||
type IPurchasePlatformHandler interface {
|
||||
GetStatusFromVendorStatus(vendorStatus string) int
|
||||
GetOrder(vendorOrderID string) (order *model.GoodsOrder, err error)
|
||||
GetStatusActionTimeout(statusType, status int) time.Duration
|
||||
|
||||
AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool) (err error)
|
||||
PickupGoods(order *model.GoodsOrder) (err error)
|
||||
|
||||
// 将订单从购物平台配送转为自送
|
||||
Swtich2SelfDeliver(order *model.GoodsOrder) (err error)
|
||||
|
||||
// 将订单从购物平台配送转为自送后又送达
|
||||
Swtich2SelfDelivered(order *model.GoodsOrder) (err error)
|
||||
|
||||
// 完全自送的门店表示开始配送
|
||||
SelfDeliverDelievering(order *model.GoodsOrder) (err error)
|
||||
|
||||
// 完全自送的门店表示配送完成
|
||||
SelfDeliverDelievered(order *model.GoodsOrder) (err error)
|
||||
}
|
||||
|
||||
type IDeliveryPlatformHandler interface {
|
||||
CreateWaybill(order *model.GoodsOrder) (err error)
|
||||
CancelWaybill(bill *model.Waybill) (err error)
|
||||
}
|
||||
|
||||
func Init(curOrderManager IOrderManager) {
|
||||
CurOrderManager = curOrderManager
|
||||
}
|
||||
65
business/partner/purchase/elm/elm.go
Normal file
65
business/partner/purchase/elm/elm.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/elmapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
}
|
||||
|
||||
func (c *Controller) OnCallbackMsg(msg *elmapi.CallbackMsg) (retVal *elmapi.CallbackResponse) {
|
||||
if msg.Type == elmapi.MsgTypeOrderValid {
|
||||
innerMsg := make(map[string]interface{})
|
||||
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
|
||||
if err != nil {
|
||||
retVal = elmapi.Err2CallbackResponse(err, "")
|
||||
} else {
|
||||
innerMsg["msgType"] = msg.Type
|
||||
retVal = new(OrderController).OnOrderNewMsg(innerMsg)
|
||||
}
|
||||
} else if msg.Type > elmapi.MsgTypeOrderValid && msg.Type < elmapi.MsgTypeUserApplyCancel {
|
||||
var innerMsg elmapi.CallbackOrderStatusMsg
|
||||
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
|
||||
if err != nil {
|
||||
retVal = elmapi.Err2CallbackResponse(err, "")
|
||||
} else {
|
||||
innerMsg.MsgType = msg.Type
|
||||
retVal = new(OrderController).OnOrderStatusMsg(&innerMsg)
|
||||
}
|
||||
} else if msg.Type >= elmapi.MsgTypeUserApplyCancel && msg.Type < elmapi.MsgTypeUserUrgeOrder {
|
||||
var innerMsg elmapi.CallbackOrderCancelRefundMsg
|
||||
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
|
||||
if err != nil {
|
||||
retVal = elmapi.Err2CallbackResponse(err, "")
|
||||
} else {
|
||||
innerMsg.MsgType = msg.Type
|
||||
retVal = new(OrderController).OnOrderCancelRefundMsg(&innerMsg)
|
||||
}
|
||||
} else if msg.Type == elmapi.MsgTypeUserUrgeOrder {
|
||||
var innerMsg elmapi.CallbackOrderUrgeMsg
|
||||
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
|
||||
if err != nil {
|
||||
retVal = elmapi.Err2CallbackResponse(err, "")
|
||||
} else {
|
||||
innerMsg.MsgType = msg.Type
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = new(OrderController).onOrderUserUrgeOrder(&innerMsg)
|
||||
}, jxutils.ComposeUniversalOrderID(innerMsg.OrderID, model.VendorIDELM))
|
||||
}
|
||||
} else if msg.Type >= elmapi.MsgTypeWaybillWait4DeliveryVendor && msg.Type <= elmapi.MsgTypeRejectedSystemError {
|
||||
var innerMsg elmapi.CallbackWaybillStatusMsg
|
||||
err := utils.UnmarshalUseNumber([]byte(msg.Message), &innerMsg)
|
||||
if err != nil {
|
||||
retVal = elmapi.Err2CallbackResponse(err, "")
|
||||
} else {
|
||||
innerMsg.MsgType = msg.Type
|
||||
retVal = new(WaybillController).OnWaybillStatusMsg(&innerMsg)
|
||||
}
|
||||
} else {
|
||||
retVal = elmapi.SuccessResponse
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
313
business/partner/purchase/elm/order.go
Normal file
313
business/partner/purchase/elm/order.go
Normal file
@@ -0,0 +1,313 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/elmapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/legacy/freshfood"
|
||||
)
|
||||
|
||||
const (
|
||||
acceptOrderDelay = 270 * time.Second
|
||||
fakePickedUp = "fakefinishedpickup"
|
||||
)
|
||||
|
||||
var (
|
||||
VendorStatus2StatusMap = map[string]int{
|
||||
elmapi.OrderStatusUnprocessed: model.OrderStatusNew,
|
||||
elmapi.OrderStatusValid: model.OrderStatusAccepted,
|
||||
elmapi.OrderStatusPending: model.OrderStatusNew,
|
||||
elmapi.OrderStatusRefunding: model.OrderStatusApplyRefund,
|
||||
elmapi.OrderStatusInvalid: model.OrderStatusCanceled,
|
||||
elmapi.OrderStatusSettled: model.OrderStatusFinished,
|
||||
}
|
||||
)
|
||||
|
||||
type OrderController struct {
|
||||
scheduler.BasePurchasePlatform
|
||||
}
|
||||
|
||||
func init() {
|
||||
scheduler.CurrentScheduler.RegisterPurchasePlatform(model.VendorIDELM, new(OrderController))
|
||||
}
|
||||
|
||||
func (c *OrderController) OnOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onOrderStatusMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *OrderController) OnOrderNewMsg(msg map[string]interface{}) (retVal *elmapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onOrderNew(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg["orderId"].(string), model.VendorIDELM))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *OrderController) OnOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onOrderCancelRefundMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *OrderController) orderStatusMsg2Status(msg *elmapi.CallbackOrderStatusMsg) *model.OrderStatus {
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: msg.OrderID,
|
||||
VendorID: model.VendorIDELM,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: msg.OrderID,
|
||||
RefVendorID: model.VendorIDELM,
|
||||
VendorStatus: c.stateAndType2Str(msg.State, msg.MsgType),
|
||||
StatusTime: utils.Timestamp2Time(msg.UpdateTime),
|
||||
}
|
||||
return orderStatus
|
||||
}
|
||||
|
||||
func (c *OrderController) cancelRefundMsg2Status(msg *elmapi.CallbackOrderCancelRefundMsg) *model.OrderStatus {
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: msg.OrderID,
|
||||
VendorID: model.VendorIDELM,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: msg.OrderID,
|
||||
RefVendorID: model.VendorIDELM,
|
||||
VendorStatus: c.stateAndType2Str(msg.RefundStatus, msg.MsgType),
|
||||
StatusTime: utils.Timestamp2Time(msg.UpdateTime),
|
||||
}
|
||||
return orderStatus
|
||||
}
|
||||
|
||||
func (c *OrderController) onOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) {
|
||||
status := c.orderStatusMsg2Status(msg)
|
||||
switch msg.MsgType {
|
||||
case elmapi.MsgTypeOrderAccepted:
|
||||
status.Status = model.OrderStatusAccepted
|
||||
case elmapi.MsgTypeOrderCanceled, elmapi.MsgTypeOrderInvalid, elmapi.MsgTypeOrderForceInvalid:
|
||||
status.Status = model.OrderStatusCanceled
|
||||
case elmapi.MsgTypeOrderFinished:
|
||||
status.Status = model.OrderStatusFinished
|
||||
default:
|
||||
globals.SugarLogger.Warnf("onOrderStatusMsg elm msg:%v not handled", msg)
|
||||
return elmapi.SuccessResponse
|
||||
}
|
||||
err := partner.CurOrderManager.OnOrderStatusChanged(status)
|
||||
|
||||
// 直接跳到拣货完成
|
||||
if msg.MsgType == elmapi.MsgTypeOrderAccepted {
|
||||
status.Status = model.OrderStatusFinishedPickup
|
||||
status.VendorStatus = fakePickedUp
|
||||
err = partner.CurOrderManager.OnOrderStatusChanged(status)
|
||||
}
|
||||
// if globals.HandleLegacyJxOrder && err == nil {
|
||||
// c.legacyElmOrderStatusChanged(status)
|
||||
// }
|
||||
return elmapi.Err2CallbackResponse(err, status.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *OrderController) onOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) {
|
||||
status := c.cancelRefundMsg2Status(msg)
|
||||
switch msg.MsgType {
|
||||
case elmapi.MsgTypeUserApplyCancel:
|
||||
status.Status = model.OrderStatusApplyCancel
|
||||
case elmapi.MsgTypeUserApplyRefund:
|
||||
status.Status = model.OrderStatusApplyRefund
|
||||
default:
|
||||
status.Status = model.OrderStatusUnknown
|
||||
}
|
||||
return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged(status), status.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *OrderController) GetOrder(orderID string) (order *model.GoodsOrder, err error) {
|
||||
result, err := api.ElmAPI.GetOrder(orderID)
|
||||
if err == nil {
|
||||
phoneList := result["phoneList"].([]interface{})
|
||||
consigneeMobile := ""
|
||||
if len(phoneList) > 0 {
|
||||
consigneeMobile = utils.Interface2String(phoneList[0])
|
||||
}
|
||||
|
||||
// globals.SugarLogger.Debug(result)
|
||||
order = &model.GoodsOrder{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDELM,
|
||||
VendorStoreID: utils.Int64ToStr(utils.MustInterface2Int64(result["shopId"])),
|
||||
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(result["openId"]), 0)),
|
||||
StoreName: result["shopName"].(string),
|
||||
ConsigneeName: utils.FilterMb4(result["consignee"].(string)),
|
||||
ConsigneeMobile: consigneeMobile,
|
||||
ConsigneeAddress: utils.FilterMb4(result["address"].(string)),
|
||||
BuyerComment: utils.FilterMb4(strings.Trim(utils.Interface2String(result["description"]), "\n\r\t ")),
|
||||
ExpectedDeliveredTime: utils.Str2TimeWithDefault(utils.Interface2String(result["deliverTime"]), utils.DefaultTimeValue),
|
||||
VendorStatus: utils.Interface2String(result["status"]), // 取订单的原始status,不合并消息类型(因为当前消息类型没有意义)
|
||||
OrderSeq: int(utils.MustInterface2Int64(result["daySn"])),
|
||||
StatusTime: utils.Str2Time(result["activeAt"].(string)),
|
||||
OriginalData: utils.FilterMb4(string(utils.MustMarshal(result))),
|
||||
ActualPayPrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(result["totalPrice"])),
|
||||
Skus: []*model.OrderSku{},
|
||||
}
|
||||
order.Status = c.GetStatusFromVendorStatus(order.VendorStatus)
|
||||
if result["book"].(bool) {
|
||||
order.BusinessType = model.BusinessTypeDingshida
|
||||
} else {
|
||||
order.BusinessType = model.BusinessTypeImmediate
|
||||
}
|
||||
deliveryGeo := strings.Split(utils.Interface2String(result["deliveryGeo"]), ",")
|
||||
if len(deliveryGeo) == 2 {
|
||||
order.CoordinateType = model.CoordinateTypeMars
|
||||
order.ConsigneeLng = jxutils.StandardCoordinate2Int(utils.Str2Float64(deliveryGeo[0]))
|
||||
order.ConsigneeLat = jxutils.StandardCoordinate2Int(utils.Str2Float64(deliveryGeo[1]))
|
||||
}
|
||||
|
||||
for _, group2 := range result["groups"].([]interface{}) {
|
||||
group := group2.(map[string]interface{})
|
||||
for _, product2 := range group["items"].([]interface{}) {
|
||||
product := product2.(map[string]interface{})
|
||||
sku := &model.OrderSku{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDELM,
|
||||
Count: int(utils.MustInterface2Int64(product["quantity"])),
|
||||
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product["extendCode"]), 0)),
|
||||
VendorSkuID: utils.Int64ToStr(utils.MustInterface2Int64(product["vfoodId"])),
|
||||
SkuName: product["name"].(string),
|
||||
SalePrice: jxutils.StandardPrice2Int(utils.MustInterface2Float64(product["price"])),
|
||||
Weight: int(math.Round(utils.Interface2FloatWithDefault(product["weight"], 0.0))),
|
||||
}
|
||||
order.Skus = append(order.Skus, sku)
|
||||
order.SkuCount++
|
||||
order.GoodsCount += sku.Count
|
||||
order.SalePrice += sku.SalePrice * int64(sku.Count)
|
||||
order.Weight += sku.Weight * sku.Count
|
||||
}
|
||||
}
|
||||
setOrederDetailFee(result, order)
|
||||
}
|
||||
return order, err
|
||||
}
|
||||
|
||||
func setOrederDetailFee(result map[string]interface{}, order *model.GoodsOrder) {
|
||||
orderActivities, ok := result["orderActivities"].([]interface{})
|
||||
if ok {
|
||||
for _, value := range orderActivities {
|
||||
activity := value.(map[string]interface{})
|
||||
categoryId := utils.MustInterface2Int64(activity["categoryId"])
|
||||
restaurantPart := -jxutils.StandardPrice2Int(utils.MustInterface2Float64(activity["restaurantPart"]))
|
||||
elemePart := -jxutils.StandardPrice2Int(utils.MustInterface2Float64(activity["elemePart"]))
|
||||
if _, ok := model.ElmSkuPromotion[int(categoryId)]; ok {
|
||||
order.SkuPmFee += restaurantPart
|
||||
order.SkuPmSubsidy += elemePart
|
||||
} else {
|
||||
order.OrderPmFee += restaurantPart
|
||||
order.OrderPmSubsidy += elemePart
|
||||
}
|
||||
}
|
||||
}
|
||||
order.PlatformFeeRate = int16(utils.MustInterface2Float64(result["serviceRate"]))
|
||||
}
|
||||
|
||||
//
|
||||
func (c *OrderController) onOrderNew(msg map[string]interface{}) (response *elmapi.CallbackResponse) {
|
||||
// todo 这里应该可以直接用msg里的内容,而不用再次去查
|
||||
order, err := c.GetOrder(msg["orderId"].(string))
|
||||
if err == nil {
|
||||
order.VendorStatus = c.stateAndType2Str(order.VendorStatus, elmapi.MsgTypeOrderValid)
|
||||
err = partner.CurOrderManager.OnOrderNew(order, c.stateAndType2Str(msg["status"].(string), elmapi.MsgTypeOrderValid))
|
||||
// if globals.HandleLegacyJxOrder && err == nil {
|
||||
// c.legacyWriteElmOrder(order)
|
||||
// }
|
||||
}
|
||||
return elmapi.Err2CallbackResponse(err, "elm onOrderNew")
|
||||
}
|
||||
|
||||
func (c *OrderController) onOrderUserUrgeOrder(msg *elmapi.CallbackOrderUrgeMsg) *elmapi.CallbackResponse {
|
||||
status := &model.OrderStatus{
|
||||
VendorOrderID: msg.OrderID,
|
||||
VendorID: model.VendorIDELM,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: msg.OrderID,
|
||||
RefVendorID: model.VendorIDELM,
|
||||
Status: model.OrderStatusApplyUrgeOrder,
|
||||
VendorStatus: utils.Int2Str(msg.MsgType),
|
||||
StatusTime: utils.Timestamp2Time(msg.UpdateTime),
|
||||
}
|
||||
if globals.ReallyCallPlatformAPI {
|
||||
freshfood.FreshFoodAPI.ELMClientUrgeOrder(msg.OrderID)
|
||||
}
|
||||
return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnOrderStatusChanged(status), status.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *OrderController) stateAndType2Str(state string, msgType int) string {
|
||||
return fmt.Sprintf("%s-%d", state, msgType)
|
||||
}
|
||||
|
||||
func (c *OrderController) spliltCompositeState(compositeState string) (state string, msgType int) {
|
||||
index := strings.Index(compositeState, "-")
|
||||
if index >= 0 {
|
||||
msgType = int(utils.Str2Int64(compositeState[index+1:]))
|
||||
if msgType == 0 {
|
||||
globals.SugarLogger.Debug(compositeState)
|
||||
}
|
||||
return compositeState[:index], msgType
|
||||
}
|
||||
return compositeState, 0
|
||||
}
|
||||
|
||||
// IPurchasePlatformHandler
|
||||
func (c *OrderController) GetStatusFromVendorStatus(vendorStatus string) int {
|
||||
state, _ := c.spliltCompositeState(vendorStatus)
|
||||
if status, ok := VendorStatus2StatusMap[state]; ok {
|
||||
return status
|
||||
}
|
||||
return model.OrderStatusUnknown
|
||||
}
|
||||
|
||||
func (c *OrderController) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool) (err error) {
|
||||
if isAcceptIt {
|
||||
err = api.ElmAPI.ConfirmOrder(order.VendorOrderID)
|
||||
} else {
|
||||
err = api.ElmAPI.CancelOrder(order.VendorOrderID, elmapi.CancelOrderTypeOthers, "")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 饿了么没有拣货这个状态,直接返回成功
|
||||
// 真实流程中也不会调用这个方法,因为接收订单后状态会直接转移到已拣货
|
||||
func (c *OrderController) PickupGoods(order *model.GoodsOrder) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OrderController) Swtich2SelfDeliver(order *model.GoodsOrder) (err error) {
|
||||
err = api.ElmAPI.DeliveryBySelfLite(order.VendorOrderID)
|
||||
return err
|
||||
}
|
||||
|
||||
// 饿了么转商家自送后,没有确认送达的概念,空操作
|
||||
func (c *OrderController) Swtich2SelfDelivered(order *model.GoodsOrder) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OrderController) SelfDeliverDelievering(order *model.GoodsOrder) (err error) {
|
||||
return api.ElmAPI.StartDeliveryBySelf(order.VendorOrderID, order.ConsigneeMobile)
|
||||
}
|
||||
|
||||
func (c *OrderController) SelfDeliverDelievered(order *model.GoodsOrder) (err error) {
|
||||
return api.ElmAPI.CompleteDeliveryBySelf(order.VendorOrderID, order.ConsigneeMobile)
|
||||
}
|
||||
|
||||
func (c *OrderController) GetStatusActionTimeout(statusType, status int) time.Duration {
|
||||
if statusType == scheduler.TimerStatusTypeOrder && status == model.OrderStatusNew {
|
||||
return acceptOrderDelay // 饿了么开了专送店的订单没有拣货状态,接单后就为拣货完成,所以要延迟接单,否则门店来不及备货
|
||||
}
|
||||
return 0
|
||||
}
|
||||
44
business/partner/purchase/elm/order_legacy.go
Normal file
44
business/partner/purchase/elm/order_legacy.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
// 为了兼容之前的表,造出原来需要的数据
|
||||
func (c *OrderController) legacyWriteElmOrder(order *model.GoodsOrder) (err error) {
|
||||
db := orm.NewOrm()
|
||||
_, msgType := c.spliltCompositeState(order.VendorStatus)
|
||||
legacyOrder := &legacymodel.Elemeorder2{
|
||||
Orderid: order.VendorOrderID,
|
||||
Type: msgType,
|
||||
Consignee: order.ConsigneeName,
|
||||
Mobile: order.ConsigneeMobile,
|
||||
OrderCreatedAt: utils.Time2Str(order.StatusTime),
|
||||
}
|
||||
_, err = db.Insert(legacyOrder)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("legacyWriteElmOrder orderID:%s insert error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderController) legacyElmOrderStatusChanged(status *model.OrderStatus) (err error) {
|
||||
db := orm.NewOrm()
|
||||
legacyOrder := &legacymodel.Elemeorder2{
|
||||
Orderid: status.VendorOrderID,
|
||||
}
|
||||
if err = db.Read(legacyOrder, "Orderid"); err == nil {
|
||||
_, legacyOrder.Type = c.spliltCompositeState(status.VendorStatus)
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Update(legacyOrder, "Type")
|
||||
return err
|
||||
}, "legacyWriteElmOrder status:%v", status)
|
||||
} else {
|
||||
globals.SugarLogger.Infof("legacyElmOrderStatusChanged db.Read status:%v, error:%v", status, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
33
business/partner/purchase/elm/order_test.go
Normal file
33
business/partner/purchase/elm/order_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"git.rosy.net.cn/jx-callback/globals/db"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func init() {
|
||||
//E:/goprojects/src/git.rosy.net.cn/jx-callback/conf/app.conf
|
||||
///Users/xujianhua/go/src/git.rosy.net.cn/jx-callback/conf/app.conf
|
||||
beego.InitBeegoBeforeTest("Users/xujianhua/go/src/git.rosy.net.cn/jx-callback/conf/app.conf")
|
||||
beego.BConfig.RunMode = "dev" // InitBeegoBeforeTest会将runmode设置为test
|
||||
|
||||
globals.Init()
|
||||
db.Init()
|
||||
api.Init()
|
||||
}
|
||||
|
||||
func TestGetOrder(t *testing.T) {
|
||||
orderID := "3025427524410871880"
|
||||
order, err := new(OrderController).GetOrder(orderID)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
if order.VendorOrderID != orderID {
|
||||
panic(err.Error())
|
||||
}
|
||||
}
|
||||
70
business/partner/purchase/elm/waybill.go
Normal file
70
business/partner/purchase/elm/waybill.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package elm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/elmapi"
|
||||
"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/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
type WaybillController struct {
|
||||
}
|
||||
|
||||
func (c *WaybillController) OnWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onWaybillStatusMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDELM))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *WaybillController) onWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) {
|
||||
order := c.callbackMsg2Waybill(msg)
|
||||
if msg.MsgType == elmapi.MsgTypeWaybillWait4Courier { //MsgTypeWaybillWait4Courier事件与JD的新运单事件的时间机制更相似
|
||||
order.Status = model.WaybillStatusNew
|
||||
} else if msg.MsgType == elmapi.MsgTypeWaybillPickingUp {
|
||||
if result, err := api.ElmAPI.GetOrder(msg.OrderID); err == nil {
|
||||
order.DesiredFee = jxutils.StandardPrice2Int(utils.Interface2FloatWithDefault(result["deliverFee"], 0.0) +
|
||||
utils.Interface2FloatWithDefault(result["vipDeliveryFeeDiscount"], 0.0))
|
||||
}
|
||||
order.Status = model.WaybillStatusAccepted
|
||||
} else if msg.MsgType == elmapi.MsgTypeWaybillCourierArrived {
|
||||
order.Status = model.WaybillStatusCourierArrived
|
||||
} else if msg.MsgType == elmapi.MsgTypeWaybillDelivering {
|
||||
order.Status = model.WaybillStatusDelivering
|
||||
} else if msg.MsgType == elmapi.MsgTypeWaybillDelivered {
|
||||
order.Status = model.WaybillStatusDelivered
|
||||
} else if msg.MsgType >= elmapi.MsgTypeWaybillCanceledByMerchant && msg.MsgType <= elmapi.MsgTypeWaybillCanceledBySystem {
|
||||
order.Status = model.WaybillStatusCanceled
|
||||
} else if msg.MsgType >= elmapi.MsgTypeWaybillFailedCallLate &&
|
||||
msg.MsgType <= elmapi.MsgTypeRejectedSystemError &&
|
||||
msg.MsgType != elmapi.MsgTypeDeiverBySelf {
|
||||
order.Status = model.WaybillStatusFailed
|
||||
} else {
|
||||
// MsgTypeWaybillWait4DeliveryVendor
|
||||
// MsgTypeDeiverBySelf
|
||||
order.Status = model.WaybillStatusUnknown
|
||||
}
|
||||
return elmapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *WaybillController) callbackMsg2Waybill(msg *elmapi.CallbackWaybillStatusMsg) (retVal *model.Waybill) {
|
||||
retVal = &model.Waybill{
|
||||
VendorOrderID: msg.OrderID,
|
||||
OrderVendorID: model.VendorIDELM,
|
||||
VendorWaybillID: msg.OrderID,
|
||||
WaybillVendorID: model.VendorIDELM,
|
||||
CourierName: msg.Name,
|
||||
CourierMobile: msg.Phone,
|
||||
VendorStatus: c.composeState(msg.State, msg.SubState, msg.MsgType),
|
||||
StatusTime: utils.Timestamp2Time(msg.UpdateAt / 1000),
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *WaybillController) composeState(state, subState string, msgType int) string {
|
||||
return fmt.Sprintf("%s-%d", state, msgType)
|
||||
}
|
||||
237
business/partner/purchase/jd/order.go
Normal file
237
business/partner/purchase/jd/order.go
Normal file
@@ -0,0 +1,237 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"git.rosy.net.cn/jx-callback/legacy/freshfood"
|
||||
)
|
||||
|
||||
var (
|
||||
VendorStatus2StatusMap = map[string]int{
|
||||
jdapi.OrderStatusPurchased: model.OrderStatusNew,
|
||||
jdapi.OrderStatusNew: model.OrderStatusNew,
|
||||
jdapi.OrderStatusAdjust: model.OrderStatusNew,
|
||||
jdapi.OrderStatusWaitOutStore: model.OrderStatusAccepted,
|
||||
jdapi.OrderStatusFinishedPickup: model.OrderStatusFinishedPickup,
|
||||
jdapi.OrderStatusDelivering: model.OrderStatusDelivering,
|
||||
jdapi.OrderStatusDelivered: model.OrderStatusDelivered,
|
||||
jdapi.OrderStatusCanceled: model.OrderStatusCanceled,
|
||||
|
||||
jdapi.OrderStatusUserApplyCancel: model.OrderStatusApplyCancel,
|
||||
jdapi.OrderStatusLocked: model.OrderStatusLocked,
|
||||
jdapi.OrderStatusUnlocked: model.OrderStatusUnlocked,
|
||||
}
|
||||
)
|
||||
|
||||
type OrderController struct {
|
||||
scheduler.BasePurchasePlatform
|
||||
}
|
||||
|
||||
func init() {
|
||||
scheduler.CurrentScheduler.RegisterPurchasePlatform(model.VendorIDJD, new(OrderController))
|
||||
}
|
||||
|
||||
func (c *OrderController) OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onOrderMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.BillID, model.VendorIDJD))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *OrderController) onOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) {
|
||||
if jdapi.OrderStatusNew == msg.StatusID {
|
||||
retVal = c.onOrderNew(msg)
|
||||
} else if jdapi.OrderStatusAdjust == msg.StatusID {
|
||||
retVal = c.onOrderAdjust(msg)
|
||||
} else {
|
||||
status := c.callbackMsg2Status(msg)
|
||||
if msg.StatusID == jdapi.OrderStatusAddComment || msg.StatusID == jdapi.OrderStatusModifyComment {
|
||||
if globals.ReallyCallPlatformAPI {
|
||||
freshfood.FreshFoodAPI.JDOrderComment(msg)
|
||||
}
|
||||
}
|
||||
err := partner.CurOrderManager.OnOrderStatusChanged(status)
|
||||
// if globals.HandleLegacyJxOrder && err == nil {
|
||||
// c.legacyJdOrderStatusChanged(status)
|
||||
// }
|
||||
retVal = jdapi.Err2CallbackResponse(err, status.VendorStatus)
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *OrderController) GetOrder(orderID string) (order *model.GoodsOrder, err error) {
|
||||
result, err := api.JdAPI.QuerySingleOrder(orderID)
|
||||
// globals.SugarLogger.Info(result)
|
||||
if err == nil {
|
||||
order = &model.GoodsOrder{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDJD,
|
||||
VendorStoreID: result["produceStationNo"].(string),
|
||||
StoreID: int(utils.Str2Int64WithDefault(utils.Interface2String(result["produceStationNoIsv"]), 0)),
|
||||
StoreName: result["produceStationName"].(string),
|
||||
ConsigneeName: utils.FilterMb4(result["buyerFullName"].(string)),
|
||||
ConsigneeMobile: result["buyerMobile"].(string),
|
||||
ConsigneeAddress: utils.FilterMb4(result["buyerFullAddress"].(string)),
|
||||
CoordinateType: model.CoordinateTypeMars,
|
||||
BuyerComment: utils.FilterMb4(strings.Trim(utils.Interface2String(result["orderBuyerRemark"]), "\n\r\t ")),
|
||||
ExpectedDeliveredTime: utils.Str2TimeWithDefault(utils.Interface2String(result["orderPreEndDeliveryTime"]), utils.DefaultTimeValue),
|
||||
VendorStatus: utils.Int64ToStr(utils.MustInterface2Int64(result["orderStatus"])),
|
||||
OrderSeq: int(utils.MustInterface2Int64(result["orderNum"])),
|
||||
StatusTime: utils.Str2Time(result["orderPurchaseTime"].(string)),
|
||||
OriginalData: utils.FilterMb4(string(utils.MustMarshal(result))),
|
||||
ActualPayPrice: utils.MustInterface2Int64(result["orderBuyerPayableMoney"]),
|
||||
Skus: []*model.OrderSku{},
|
||||
}
|
||||
order.Status = c.GetStatusFromVendorStatus(order.VendorStatus)
|
||||
businessTage := utils.Interface2String(result["businessTag"])
|
||||
if strings.Index(businessTage, "dj_aging_immediately") >= 0 {
|
||||
order.BusinessType = model.BusinessTypeImmediate
|
||||
} else {
|
||||
order.BusinessType = model.BusinessTypeDingshida
|
||||
}
|
||||
coordinateType := utils.Interface2Int64WithDefault(result["buyerCoordType"], 1)
|
||||
originalLng := utils.MustInterface2Float64(result["buyerLng"])
|
||||
originalLat := utils.MustInterface2Float64(result["buyerLat"])
|
||||
if coordinateType == 1 {
|
||||
lng, lat, err2 := api.AutonaviAPI.CoordinateConvert(originalLng, originalLat, autonavi.CoordSysGPS)
|
||||
if err2 == nil {
|
||||
originalLng = lng
|
||||
originalLat = lat
|
||||
} else {
|
||||
// 如果没有转成功,保留原始数据
|
||||
order.CoordinateType = model.CoordinateTypeGPS
|
||||
}
|
||||
}
|
||||
order.ConsigneeLng = jxutils.StandardCoordinate2Int(originalLng)
|
||||
order.ConsigneeLat = jxutils.StandardCoordinate2Int(originalLat)
|
||||
// discounts := result["discount"].(map[string]interface{})
|
||||
for _, product2 := range result["product"].([]interface{}) {
|
||||
product := product2.(map[string]interface{})
|
||||
sku := &model.OrderSku{
|
||||
VendorOrderID: orderID,
|
||||
VendorID: model.VendorIDJD,
|
||||
Count: int(utils.MustInterface2Int64(product["skuCount"])),
|
||||
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product["skuIdIsv"]), 0)),
|
||||
VendorSkuID: utils.Int64ToStr(utils.MustInterface2Int64(product["skuId"])),
|
||||
SkuName: product["skuName"].(string),
|
||||
Weight: int(utils.MustInterface2Float64(product["skuWeight"]) * 1000),
|
||||
SalePrice: utils.MustInterface2Int64(product["skuJdPrice"]),
|
||||
PromotionType: int(utils.MustInterface2Int64(product["promotionType"])),
|
||||
}
|
||||
if product["isGift"].(bool) {
|
||||
sku.SkuType = 1
|
||||
}
|
||||
order.Skus = append(order.Skus, sku)
|
||||
order.SkuCount++
|
||||
order.GoodsCount += sku.Count
|
||||
order.SalePrice += sku.SalePrice * int64(sku.Count)
|
||||
order.Weight += sku.Weight * sku.Count
|
||||
}
|
||||
setOrederDetailFee(result, order)
|
||||
}
|
||||
return order, err
|
||||
}
|
||||
|
||||
func setOrederDetailFee(result map[string]interface{}, order *model.GoodsOrder) {
|
||||
order.BoxFee = utils.MustInterface2Int64(result["packagingMoney"])
|
||||
order.PlatformFeeRate = model.JdPlatformFeeRate
|
||||
order.BillStoreFreightFee = utils.MustInterface2Int64(result["merchantPaymentDistanceFreightMoney"]) + utils.MustInterface2Int64(result["tips"])
|
||||
}
|
||||
|
||||
//
|
||||
func (c *OrderController) onOrderNew(msg *jdapi.CallbackOrderMsg) (response *jdapi.CallbackResponse) {
|
||||
order, err := c.GetOrder(msg.BillID)
|
||||
if err == nil {
|
||||
err = partner.CurOrderManager.OnOrderNew(order, msg.StatusID)
|
||||
// if err == nil {
|
||||
// c.legacyWriteJdOrder(order, false)
|
||||
// }
|
||||
}
|
||||
return jdapi.Err2CallbackResponse(err, "jd onOrderNew")
|
||||
}
|
||||
|
||||
func (c *OrderController) onOrderAdjust(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse {
|
||||
order, err := c.GetOrder(msg.BillID)
|
||||
if err == nil {
|
||||
err = partner.CurOrderManager.OnOrderAdjust(order, msg.StatusID)
|
||||
// if globals.HandleLegacyJxOrder && err == nil {
|
||||
// c.legacyWriteJdOrder(order, true)
|
||||
// }
|
||||
}
|
||||
return jdapi.Err2CallbackResponse(err, "jd onOrderAdjust")
|
||||
}
|
||||
|
||||
func (c *OrderController) callbackMsg2Status(msg *jdapi.CallbackOrderMsg) *model.OrderStatus {
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: msg.BillID,
|
||||
VendorID: model.VendorIDJD,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: msg.BillID,
|
||||
RefVendorID: model.VendorIDJD,
|
||||
VendorStatus: msg.StatusID,
|
||||
Status: c.GetStatusFromVendorStatus(msg.StatusID),
|
||||
StatusTime: utils.Str2Time(msg.Timestamp),
|
||||
Remark: msg.Remark,
|
||||
}
|
||||
return orderStatus
|
||||
}
|
||||
|
||||
// IPurchasePlatformHandler
|
||||
func (c *OrderController) GetStatusFromVendorStatus(vendorStatus string) int {
|
||||
if status, ok := VendorStatus2StatusMap[vendorStatus]; ok {
|
||||
return status
|
||||
}
|
||||
return model.OrderStatusUnknown
|
||||
}
|
||||
|
||||
func (c *OrderController) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool) (err error) {
|
||||
_, err = api.JdAPI.OrderAcceptOperate(order.VendorOrderID, isAcceptIt)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderController) PickupGoods(order *model.GoodsOrder) (err error) {
|
||||
_, err = api.JdAPI.OrderJDZBDelivery(order.VendorOrderID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderController) Swtich2SelfDeliver(order *model.GoodsOrder) (err error) {
|
||||
_, err = api.JdAPI.ModifySellerDelivery(order.VendorOrderID)
|
||||
if err != nil {
|
||||
if errWithCode, ok := err.(*utils.ErrorWithCode); ok && errWithCode.Level() == 1 {
|
||||
globals.SugarLogger.Infof("Swtich2SelfDeliver failed with error:%v try get current status", err)
|
||||
if order2, err2 := c.GetOrder(order.VendorOrderID); err2 == nil {
|
||||
var mapData map[string]interface{}
|
||||
if err2 = utils.UnmarshalUseNumber([]byte(order2.OriginalData), &mapData); err2 == nil {
|
||||
if utils.Interface2String(mapData["deliveryCarrierNo"]) == "2938" { // 当前已经是自送状态了
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderController) Swtich2SelfDelivered(order *model.GoodsOrder) (err error) {
|
||||
_, err = api.JdAPI.DeliveryEndOrder(order.VendorOrderID)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderController) SelfDeliverDelievering(order *model.GoodsOrder) (err error) {
|
||||
_, err = api.JdAPI.OrderSerllerDelivery(order.VendorOrderID)
|
||||
return err
|
||||
}
|
||||
|
||||
// 京东送达接口都是一样的
|
||||
func (c *OrderController) SelfDeliverDelievered(order *model.GoodsOrder) (err error) {
|
||||
return c.Swtich2SelfDelivered(order)
|
||||
}
|
||||
49
business/partner/purchase/jd/order_legacy.go
Normal file
49
business/partner/purchase/jd/order_legacy.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
// 为了兼容之前的表,造出原来需要的数据
|
||||
func (c *OrderController) legacyWriteJdOrder(order *model.GoodsOrder, delOldFirst bool) (err error) {
|
||||
db := orm.NewOrm()
|
||||
if delOldFirst {
|
||||
db.Raw("DELETE FROM jdorder2 WHERE jdorderid = ?", utils.Str2Int64(order.VendorOrderID)).Exec()
|
||||
}
|
||||
legacyOrder := &legacymodel.Jdorder2{
|
||||
Code: "0",
|
||||
Jdorderid: utils.Str2Int64(order.VendorOrderID),
|
||||
Orderstatus: int(utils.Str2Int64(order.VendorStatus)),
|
||||
Orderstatustime: utils.Time2Str(order.StatusTime),
|
||||
Success: 1,
|
||||
Cityname: "all",
|
||||
}
|
||||
_, err = db.Insert(legacyOrder)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("legacyWriteJdOrder orderID:%s insert error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderController) legacyJdOrderStatusChanged(status *model.OrderStatus) (err error) {
|
||||
db := orm.NewOrm()
|
||||
legacyOrder := &legacymodel.Jdorder2{
|
||||
Jdorderid: utils.Str2Int64(status.VendorOrderID),
|
||||
}
|
||||
|
||||
if err = db.Read(legacyOrder, "Jdorderid"); err == nil {
|
||||
utils.CallFuncLogError(func() error {
|
||||
legacyOrder.Orderstatus = int(utils.Str2Int64(status.VendorStatus))
|
||||
legacyOrder.Orderstatustime = utils.Time2Str(status.StatusTime)
|
||||
_, err = db.Update(legacyOrder, "Orderstatus", "Orderstatustime")
|
||||
return err
|
||||
}, "legacyJdOrderStatusChanged, status:%v", status)
|
||||
} else {
|
||||
globals.SugarLogger.Infof("legacyJdOrderStatusChanged db.Read status:%v, error:%v", status, err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
42
business/partner/purchase/jd/order_test.go
Normal file
42
business/partner/purchase/jd/order_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"git.rosy.net.cn/jx-callback/globals/db"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
func init() {
|
||||
beego.InitBeegoBeforeTest("/Users/xujianhua/go/src/git.rosy.net.cn/jx-callback/conf/app.conf")
|
||||
beego.BConfig.RunMode = "dev" // InitBeegoBeforeTest会将runmode设置为test
|
||||
|
||||
globals.Init()
|
||||
db.Init()
|
||||
api.Init()
|
||||
}
|
||||
|
||||
func TestSwitch2SelfDeliver(t *testing.T) {
|
||||
orderID := "817540316000041"
|
||||
if order, err := orderman.CurOrderManager.LoadOrder(orderID, model.VendorIDJD); err == nil {
|
||||
// globals.SugarLogger.Debug(order)
|
||||
c := new(OrderController)
|
||||
if err = c.Swtich2SelfDeliver(order); err == nil {
|
||||
} else {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
} else {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetOrder(t *testing.T) {
|
||||
_, err := new(OrderController).GetOrder("815536199000222")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
65
business/partner/purchase/jd/waybill.go
Normal file
65
business/partner/purchase/jd/waybill.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package jd
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"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/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
type WaybillController struct {
|
||||
}
|
||||
|
||||
func (c *WaybillController) OnWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
retVal = c.onWaybillMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDJD))
|
||||
return retVal
|
||||
}
|
||||
|
||||
func (c *WaybillController) onWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) {
|
||||
order := c.callbackMsg2Waybill(msg)
|
||||
switch msg.DeliveryStatus {
|
||||
case jdapi.DeliveryStatusWait4Grap:
|
||||
order.Status = model.WaybillStatusNew
|
||||
case jdapi.DeliveryStatusAccepted:
|
||||
if result, err := api.JdAPI.QuerySingleOrder(msg.OrderID); err == nil {
|
||||
// 默认配送费=订单应付运费(orderReceivableFreight)
|
||||
//订单应付运费为未优惠前应付运费(满免优惠,运费优惠券,VIP免基础运费,用户小费)ps:用户小费是用户给配送员的小费
|
||||
order.DesiredFee = utils.Interface2Int64WithDefault(result["orderReceivableFreight"], 0) +
|
||||
utils.Interface2Int64WithDefault(result["merchantPaymentDistanceFreightMoney"], 0) +
|
||||
utils.Interface2Int64WithDefault(result["tips"], 0)
|
||||
}
|
||||
order.Status = model.WaybillStatusAccepted
|
||||
case jdapi.DeliveryStatusCourierCanceled:
|
||||
order.Status = model.WaybillStatusCanceled
|
||||
case jdapi.DeliveryStatusCourierArrived:
|
||||
order.Status = model.WaybillStatusCourierArrived
|
||||
case jdapi.DeliveryStatusGotGoods:
|
||||
order.Status = model.WaybillStatusDelivering
|
||||
case jdapi.DeliveryStatusFinished:
|
||||
order.Status = model.WaybillStatusDelivered
|
||||
case jdapi.DeliveryStatusFailedDelivery, jdapi.DeliveryStatusFailedGetGoods:
|
||||
order.Status = model.WaybillStatusFailed
|
||||
default:
|
||||
order.Status = model.WaybillStatusUnknown
|
||||
}
|
||||
return jdapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus)
|
||||
}
|
||||
|
||||
func (c *WaybillController) callbackMsg2Waybill(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *model.Waybill) {
|
||||
retVal = &model.Waybill{
|
||||
VendorOrderID: msg.OrderID,
|
||||
OrderVendorID: model.VendorIDJD,
|
||||
VendorWaybillID: msg.OrderID,
|
||||
WaybillVendorID: model.VendorIDJD,
|
||||
CourierName: msg.DeliveryManName,
|
||||
CourierMobile: msg.DeliveryManPhone,
|
||||
VendorStatus: msg.DeliveryStatus,
|
||||
StatusTime: utils.Str2Time(msg.DeliveryStatusTime),
|
||||
Remark: msg.Remark,
|
||||
}
|
||||
return retVal
|
||||
}
|
||||
Reference in New Issue
Block a user