Files
jx-callback/business/jd/controller/order.go
2018-06-20 15:06:09 +08:00

239 lines
6.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 controller
import (
"encoding/json"
"git.rosy.net.cn/baseapi/platform/jdapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jd/models"
"git.rosy.net.cn/jx-callback/compat/corm"
"git.rosy.net.cn/jx-callback/globals"
"github.com/astaxie/beego/orm"
)
const (
MsgNotHandledCode = "9527"
)
var (
errChecker corm.DBErrorChecker
orderMsgChan chan jdapi.JDOrderMsg
)
type OrderController struct {
}
func InitOrder() {
errChecker = new(corm.MysqlErrorChecker)
orderMsgChan = make(chan jdapi.JDOrderMsg, 128)
go orderMsgHandlerRoutine()
// todo 这样操作在有多个进程时,会有问题
// 另外当前这个模式可能会出现同一个定单的消息虽然远程推送过来顺序是对的但经过处理后推送到freshfood时乱序因为每个消息的处理时间是不确定的
handlePendingOrderMsg()
}
func handlePendingOrderMsg() {
var ordersInfo []models.Jdorder
db := orm.NewOrm()
_, err := db.Raw("SELECT * FROM jdorder WHERE code = ?", MsgNotHandledCode).QueryRows(&ordersInfo)
if err != nil {
globals.SugarLogger.Errorf("can not get jdorder from db, error:%v", err)
} else {
for _, jdOrderInfo := range ordersInfo {
orderMsg := &jdapi.JDOrderMsg{
Id: jdOrderInfo.Id,
BillId: utils.Int64ToStr(jdOrderInfo.JdOrderId),
StatusId: utils.Int2Str(jdOrderInfo.OrderStatus),
Timestamp: jdOrderInfo.OrderStatusTime,
}
addOrderMsg(orderMsg)
}
}
}
func orderMsgHandlerRoutine() {
for {
msg := <-orderMsgChan
globals.SugarLogger.Debugf("orderMsgHandlerRoutine:%v", msg)
go handleOrderMsg(&msg)
}
}
func addOrderMsg(orderMsg *jdapi.JDOrderMsg) {
globals.SugarLogger.Debugf("addOrderMsg:%v", orderMsg)
orderMsgChan <- *orderMsg
}
func handleOrderMsg(orderMsg *jdapi.JDOrderMsg) {
globals.SugarLogger.Debugf("handleOrderMsg:%v", orderMsg)
switch orderMsg.StatusId {
case jdapi.JdOrderStatusNew:
newOrder(orderMsg)
case jdapi.JdOrderStatusAdjust:
adjustOrder(orderMsg)
default:
normalOrderStatus(orderMsg)
}
}
// --------------
func (c *OrderController) OrderStatus(order *jdapi.JDOrderMsg) *jdapi.JDCallbackResponse {
if order.StatusId != jdapi.JdOrderStatusNew && order.StatusId != jdapi.JdOrderStatusAdjust {
err := normalOrderStatus(order)
if err != nil {
return &jdapi.JDCallbackResponse{jdapi.JDerrorCodeAccessFailed, err.Error(), ""}
}
} else {
db := orm.NewOrm()
jdorderid := utils.Str2Int64(order.BillId)
status := utils.Str2Int(order.StatusId)
rec := &models.Jdorder{
Code: MsgNotHandledCode,
JdOrderId: jdorderid,
OrderStatus: status,
OrderStatusTime: order.Timestamp,
}
if created, _, err := db.ReadOrCreate(rec, "Jdorderid"); err == nil {
order.Id = rec.Id
if created {
if order.StatusId != jdapi.JdOrderStatusNew && order.StatusId != jdapi.JdOrderStatusAdjust {
globals.SugarLogger.Warnf("order:%v get before create", order)
oldStatusId := order.StatusId
order.StatusId = jdapi.JdOrderStatusNew
addOrderMsg(order)
order.StatusId = oldStatusId
}
addOrderMsg(order)
} else {
if rec.OrderStatus != status {
if order.StatusId == jdapi.JdOrderStatusNew {
globals.SugarLogger.Warnf("order:%v get after some other message:%d", order, rec.OrderStatus)
} else {
rec.OrderStatus = status
rec.OrderStatusTime = order.Timestamp
rec.Code = MsgNotHandledCode
utils.CallFuncLogError(func() error {
_, err := db.Update(rec, "OrderStatus", "OrderStatusTime", "Code")
return err
}, globals.ErrStrAccessDB)
addOrderMsg(order)
}
} else {
globals.SugarLogger.Warnf("duplicated jd order msg %v", order)
}
}
} else {
globals.SugarLogger.Errorf("error when calling ReadOrCreate:%v", err)
return &jdapi.JDCallbackResponse{jdapi.JDerrorCodeAccessFailed, err.Error(), ""}
}
}
return jdapi.SuccessResponse
}
func (c *OrderController) OrderDeliveryStatus(jdOrderDeliveryStatusMsg *jdapi.JDDeliveryStatusMsg) *jdapi.JDCallbackResponse {
err := globals.FreshFoodAPI.JDOrderDeliveryStatus(jdOrderDeliveryStatusMsg)
if err != nil {
globals.SugarLogger.Errorf("Error when calling JDOrderDeliveryStatus, error:%v", err)
return &jdapi.JDCallbackResponse{jdapi.JDerrorCodeAccessFailed, err.Error(), ""}
}
return jdapi.SuccessResponse
}
//-----------
func acceptOrder(order *jdapi.JDOrderMsg) {
globals.Jdapi.OrderAcceptOperate(order.BillId, true)
}
func newOrder(order *jdapi.JDOrderMsg) error {
result, err := globals.Jdapi.LegacyQuerySingleOrder(order.BillId)
acceptOrder(order)
if err != nil {
globals.SugarLogger.Errorf("error when query jd order:%s, error:%v", order.BillId, err)
} else {
rec := &models.Jdorder{
Id: order.Id,
}
rec.Code, _ = result["code"].(string)
rec.Msg, _ = result["msg"].(string)
success, _ := result["success"].(bool)
if success {
rec.Success = 1
} else {
rec.Success = 0
}
// todo
rec.CityName = "all"
data := result["data"].(map[string]interface{})
dataResult := data["result"].(map[string]interface{})
resultList, ok := dataResult["resultList"].([]interface{})
if ok && len(resultList) == 1 {
resultList0 := resultList[0].(map[string]interface{})
orderStatus, _ := resultList0["orderStatus"].(json.Number).Int64()
rec.OrderStatus = int(orderStatus)
rec.OrderStatusTime = resultList0["orderStatusTime"].(string)
resultByteArr := utils.MustMarshal(data)
rec.Data = string(resultByteArr)
err = globals.FreshFoodAPI.NewJDOrder(rec)
if err == nil {
db := orm.NewOrm()
utils.CallFuncLogError(func() error {
_, err := db.Update(rec, "Data", "Code", "Msg", "Success", "CityName", "OrderStatus", "OrderStatusTime")
return err
}, globals.ErrStrAccessDB)
} else {
globals.SugarLogger.Errorf("Error when calling NewJDOrder error:%v", err)
}
} else {
globals.SugarLogger.Warnf("can not get jdorder info:%v", order.BillId)
}
}
return err
}
func adjustOrder(order *jdapi.JDOrderMsg) error {
return newOrder(order)
}
func normalOrderStatus(order *jdapi.JDOrderMsg) error {
db := orm.NewOrm()
rec := &models.Jdorder{
JdOrderId: utils.Str2Int64(order.BillId),
}
err := db.Read(rec, "JdOrderId")
if err != nil {
globals.SugarLogger.Warnf("error when accessing db:%v", err)
return err
}
if rec.OrderStatus == utils.Str2Int(order.StatusId) {
globals.SugarLogger.Infof("Duplicate message order:%v", order)
return nil
}
rec.OrderStatus = utils.Str2Int(order.StatusId)
rec.OrderStatusTime = order.Timestamp
err = globals.FreshFoodAPI.JDOrderStatus(rec)
if err != nil {
globals.SugarLogger.Warnf("access freshfood failed, error:%v", err)
return err
}
rec.Code = "0"
utils.CallFuncLogError(func() error {
_, err := db.Update(rec, "OrderStatus", "OrderStatusTime", "Code")
return err
}, globals.ErrStrAccessDB)
return err
}