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/freshfood" "git.rosy.net.cn/jx-callback/business/jd/models" "git.rosy.net.cn/jx-callback/compat/corm" "github.com/astaxie/beego/orm" _ "github.com/go-sql-driver/mysql" // import your used driver ) const ( MsgNotHandledCode = "9527" ) var ( errChecker corm.DBErrorChecker orderMsgChan chan *jdapi.JDOrderMsg // freshFoodServerURL = "http://portal.jingxicaishi.com" freshFoodServerURL = "http://test.jxc4.com" freshFoodAPI *freshfood.FreshFoodAPI ) type OrderControler struct { } func initOrder() { errChecker = new(corm.MysqlErrorChecker) freshFoodAPI = freshfood.NewFreshFoodAPI(freshFoodServerURL, sugarLogger.Desugar()) orderMsgChan = make(chan *jdapi.JDOrderMsg, 128) go orderMsgHandlerRoutinue() // 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 { 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 orderMsgHandlerRoutinue() { for { msg := <-orderMsgChan sugarLogger.Debugf("OrderMsgHandlerRoutinue:%v", msg) go handleOrderMsg(msg) } } func addOrderMsg(orderMsg *jdapi.JDOrderMsg) { sugarLogger.Debugf("addOrderMsg:%v", orderMsg) orderMsgChan <- orderMsg } func handleOrderMsg(orderMsg *jdapi.JDOrderMsg) { sugarLogger.Debugf("handleOrderMsg:%v", orderMsg) switch orderMsg.StatusId { case jdapi.JdOrderStatusNew: newOrder(orderMsg) case jdapi.JdOrderStatusAdjust: adjustOrder(orderMsg) default: normalOrderStatus(orderMsg) } } // -------------- func (c *OrderControler) OrderStatus(order *jdapi.JDOrderMsg) *jdapi.JDOrderMsgResponse { if order.StatusId != jdapi.JdOrderStatusNew && order.StatusId != jdapi.JdOrderStatusAdjust { err := normalOrderStatus(order) if err != nil { sugarLogger.Warnf("error in OrderStatus, error:%v", err) return &jdapi.JDOrderMsgResponse{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 { isStatusSame := order.StatusId == jdapi.JdOrderStatusNew if !isStatusSame { order.StatusId = jdapi.JdOrderStatusNew sugarLogger.Warnf("order:%s get %s before create", order.BillId, order.StatusId) } addOrderMsg(order) if !isStatusSame { order.StatusId = utils.Int2Str(status) } } if rec.OrderStatus != status { rec.OrderStatus = status rec.OrderStatusTime = order.Timestamp rec.Code = MsgNotHandledCode db.Update(rec, "OrderStatus", "OrderStatusTime", "Code") addOrderMsg(order) } else { sugarLogger.Warnf("duplicated jd orderid:%s", order.BillId) sugarLogger.Debug(rec) } } else { sugarLogger.Errorf("error when calling ReadOrCreate:%v", err) return &jdapi.JDOrderMsgResponse{jdapi.JDerrorCodeAccessFailed, err.Error(), ""} } } return jdSuccessResponse } func (c *OrderControler) OrderDeliveryStatus(jdOrderDeliveryStatusMsg *jdapi.JDDeliveryStatusMsg) *jdapi.JDOrderMsgResponse { err := freshFoodAPI.JDOrderDeliveryStatus(jdOrderDeliveryStatusMsg, "0") if err != nil { sugarLogger.Errorf("Error when calling JDOrderDeliveryStatus, error:%v", err) return &jdapi.JDOrderMsgResponse{jdapi.JDerrorCodeAccessFailed, err.Error(), ""} } return jdSuccessResponse } //----------- func acceptOrder(order *jdapi.JDOrderMsg) { gJdapi.OrderAcceptOperate(order.BillId, true) } func newOrder(order *jdapi.JDOrderMsg) error { sugarLogger.Debug("NewOrder2") result, err := gJdapi.LegacyQuerySingleOrder(order.BillId) acceptOrder(order) if err != nil { sugarLogger.Warnf("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, _ := json.Marshal(data) rec.Data = string(resultByteArr) err = freshFoodAPI.NewJDOrder(rec) if err == nil { db := orm.NewOrm() _, err = db.Update(rec, "Data", "Code", "Msg", "Success", "CityName", "OrderStatus", "OrderStatusTime") if err != nil { sugarLogger.Errorf("update order error:%v", err) } } else { sugarLogger.Errorf("Error when calling NewJDOrder error:%v", err) } } else { 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 { sugarLogger.Warnf("error when accessing db:%v", err) return err } if rec.OrderStatus == utils.Str2Int(order.StatusId) { sugarLogger.Infof("Duplicate message order:%v", order) return nil } rec.OrderStatus = utils.Str2Int(order.StatusId) rec.OrderStatusTime = order.Timestamp err = freshFoodAPI.JDOrderStatus(rec, "0") if err != nil { // todo 这里应该要加一个重试机制 sugarLogger.Warnf("access freshfood failed, error:%v", err) return err } rec.Code = "0" _, err = db.Update(rec, "OrderStatus", "OrderStatusTime", "Code") if err != nil { sugarLogger.Warnf("error when accessing db:%v", err) } return err }