From a76213e8f0f528eb8aa34b4d753e041c228a7bc2 Mon Sep 17 00:00:00 2001 From: gazebo Date: Tue, 10 Jul 2018 13:37:35 +0800 Subject: [PATCH] - first compilable version of order handler. --- business/controller/controller.go | 74 +++++++++ business/controller/dada/waybill.go | 87 ++++++++++ business/controller/elm/elm.go | 64 +++++++ business/controller/elm/order.go | 211 +++++++++++++++++++++++ business/controller/elm/waybill.go | 92 ++++++++++ business/controller/jd/order.go | 144 ++++++++++++++++ business/controller/jd/waybill.go | 87 ++++++++++ business/controller/mtps/waybill.go | 80 +++++++++ business/controller/order.go | 249 ++++++++++++++++++++++++++++ business/controller/waybill.go | 111 +++++++++++++ business/model/order.go | 108 ++++++++++++ globals/globals.go | 3 + legacy/elm/controller/order.go | 4 +- legacy/freshfood/freshfood.go | 6 +- main.go | 4 + 15 files changed, 1319 insertions(+), 5 deletions(-) create mode 100644 business/controller/controller.go create mode 100644 business/controller/dada/waybill.go create mode 100644 business/controller/elm/elm.go create mode 100644 business/controller/elm/order.go create mode 100644 business/controller/elm/waybill.go create mode 100644 business/controller/jd/order.go create mode 100644 business/controller/jd/waybill.go create mode 100644 business/controller/mtps/waybill.go create mode 100644 business/controller/order.go create mode 100644 business/controller/waybill.go create mode 100644 business/model/order.go diff --git a/business/controller/controller.go b/business/controller/controller.go new file mode 100644 index 000000000..1d26c2127 --- /dev/null +++ b/business/controller/controller.go @@ -0,0 +1,74 @@ +package controller + +import ( + "fmt" + "strings" + "sync" + "time" + + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/baseapi/utils/routinepool" + "git.rosy.net.cn/jx-callback/globals" +) + +const ( + VenderIDUnknown = -1 + VendorIDJD = 0 + VendorIDMTWM = 1 + VendorIDELM = 2 + + VendorIDDada = 101 + VendorIDMTPS = 102 +) + +const ( + OrderTypeOrder = 1 + OrderTypeWaybill = 2 +) + +const ( + DefaultOrderCacheTimeout = 24 * time.Hour +) + +var ( + RoutinePool *routinepool.Pool +) + +type SyncMapWithTimeout struct { + sync.Map +} + +func (m *SyncMapWithTimeout) StoreWithTimeout(key, value interface{}, timeout time.Duration) { + m.Map.Store(key, value) + time.AfterFunc(timeout, func() { + m.Delete(key) + }) +} + +func (m *SyncMapWithTimeout) Store(key, value interface{}) { + m.StoreWithTimeout(key, value, DefaultOrderCacheTimeout) +} + +func GetVendorIDFromUniversalOrderID(orderID string) (vendorID int) { + index := strings.Index(orderID, "|") + if index != -1 { + vendorID = int(utils.Str2Int64(orderID[index:])) + } else { + // 800402581000221 jd order + // 3022716176275221584 elm order + orderIDLen := len(orderID) + if orderIDLen == len("800402581000221") { + vendorID = VendorIDJD + } else if orderIDLen == len("3022716176275221584") { + vendorID = VendorIDELM + } else { + globals.SugarLogger.Errorf("unkown order type:%v", orderID) + vendorID = VenderIDUnknown + } + } + return vendorID +} + +func ComposeUniversalOrderID(orderID string, vendorID int) string { + return fmt.Sprintf("%s|%d", orderID, vendorID) +} diff --git a/business/controller/dada/waybill.go b/business/controller/dada/waybill.go new file mode 100644 index 000000000..e3b110c70 --- /dev/null +++ b/business/controller/dada/waybill.go @@ -0,0 +1,87 @@ +package dada + +import ( + "git.rosy.net.cn/baseapi/platformapi/dadaapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/controller" + "git.rosy.net.cn/jx-callback/business/model" +) + +type WaybillController struct { + controller.WaybillController +} + +func (c *WaybillController) OnWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { + controller.RoutinePool.CallFun(func() { + retVal = c.onWaybillMsg(msg) + }, msg.OrderID) + return retVal +} + +func (c *WaybillController) callbackMsg2Status(msg *dadaapi.CallbackMsg) *model.OrderStatus { + orderStatus := &model.OrderStatus{ + VendorOrderID: msg.ClientID, + VendorID: controller.VendorIDDada, + OrderType: controller.OrderTypeWaybill, + VendorStatus: utils.Int2Str(msg.OrderStatus), + StatusTime: utils.Timestamp2Time(int64(msg.UpdateTime)), + } + return orderStatus +} + +func (c *WaybillController) onWaybillMsg(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { + switch msg.OrderStatus { + case dadaapi.OrderStatusWaitingForAccept: + retVal = c.onWaybillNew(msg) + case dadaapi.OrderStatusAccepted: + retVal = c.onWaybillAccepted(msg) + case dadaapi.OrderStatusDeliverying: + retVal = c.onWaybillDelivering(msg) + case dadaapi.OrderStatusFinished: + retVal = c.onWaybillDelivered(msg) + case dadaapi.OrderStatusCanceled: + retVal = c.onWaybillCanceled(msg) + case dadaapi.OrderStatusExpired, dadaapi.OrderStatusAddOrderFailed: + retVal = c.onWaybillFailed(msg) + default: + retVal = c.onWaybillOtherStatus(msg) + } + return retVal +} + +func (c *WaybillController) onWaybillNew(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { + order := &model.Waybill{ + VendorOrderID: msg.OrderID, + VendorID: controller.GetVendorIDFromUniversalOrderID(msg.OrderID), + VendorWaybillID: msg.ClientID, + WaybillVendorID: controller.VendorIDDada, + CourierName: msg.DmName, + CourierMobile: msg.DmMobile, + WaybillCreatedAt: utils.Timestamp2Time(int64(msg.UpdateTime)), + } + return dadaapi.Err2CallbackResponse(c.OnWaybillNew(order), "dada onWaybillNew") +} + +func (c *WaybillController) onWaybillAccepted(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { + return dadaapi.Err2CallbackResponse(c.OnWaybillAccepted(c.callbackMsg2Status(msg)), "dada onWaybillAccepted") +} + +func (c *WaybillController) onWaybillDelivering(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { + return dadaapi.Err2CallbackResponse(c.OnWaybillDelivering(c.callbackMsg2Status(msg)), "dada onWaybillDelivering") +} + +func (c *WaybillController) onWaybillDelivered(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { + return dadaapi.Err2CallbackResponse(c.OnWaybillDelivered(c.callbackMsg2Status(msg)), "dada onWaybillDelivered") +} + +func (c *WaybillController) onWaybillCanceled(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { + return dadaapi.Err2CallbackResponse(c.OnWaybillCanceled(c.callbackMsg2Status(msg)), "dada onWaybillCanceled") +} + +func (c *WaybillController) onWaybillFailed(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { + return dadaapi.Err2CallbackResponse(c.OnWaybillFailed(c.callbackMsg2Status(msg)), "dada onWaybillFailed") +} + +func (c *WaybillController) onWaybillOtherStatus(msg *dadaapi.CallbackMsg) (retVal *dadaapi.CallbackResponse) { + return dadaapi.Err2CallbackResponse(c.OnWaybillOtherStatus(c.callbackMsg2Status(msg)), "dada onWaybillOtherStatus") +} diff --git a/business/controller/elm/elm.go b/business/controller/elm/elm.go new file mode 100644 index 000000000..9ef840e40 --- /dev/null +++ b/business/controller/elm/elm.go @@ -0,0 +1,64 @@ +package elm + +import ( + "git.rosy.net.cn/baseapi/platformapi/elmapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/controller" +) + +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 + controller.RoutinePool.CallFun(func() { + retVal = new(OrderController).onOrderUserUrgeOrder(&innerMsg) + }, innerMsg.OrderID) + } + } 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 +} diff --git a/business/controller/elm/order.go b/business/controller/elm/order.go new file mode 100644 index 000000000..f17cb8ede --- /dev/null +++ b/business/controller/elm/order.go @@ -0,0 +1,211 @@ +package elm + +import ( + "fmt" + + "git.rosy.net.cn/jx-callback/globals" + + "git.rosy.net.cn/baseapi/platformapi/elmapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/controller" + "git.rosy.net.cn/jx-callback/business/model" +) + +type OrderController struct { + controller.OrderController +} + +var ( + api *elmapi.API +) + +func (c *OrderController) OnOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) { + controller.RoutinePool.CallFun(func() { + retVal = c.onOrderStatusMsg(msg) + }, msg.OrderID) + return retVal +} + +func (c *OrderController) OnOrderNewMsg(msg map[string]interface{}) (retVal *elmapi.CallbackResponse) { + controller.RoutinePool.CallFun(func() { + retVal = c.onOrderNew(msg) + }, msg["orderId"].(string)) + return retVal +} + +func (c *OrderController) OnOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) { + controller.RoutinePool.CallFun(func() { + retVal = c.onOrderCancelRefundMsg(msg) + }, msg.OrderID) + return retVal +} + +func (c *OrderController) orderStatusMsg2Status(msg *elmapi.CallbackOrderStatusMsg) *model.OrderStatus { + orderStatus := &model.OrderStatus{ + VendorOrderID: msg.OrderID, + VendorID: controller.VendorIDELM, + OrderType: controller.OrderTypeOrder, + VendorStatus: fmt.Sprintf("%s-%d", 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: controller.VendorIDELM, + OrderType: controller.OrderTypeOrder, + Status: controller.OrderStatusEvent, + VendorStatus: utils.Int2Str(msg.MsgType), + StatusTime: utils.Timestamp2Time(msg.UpdateTime), + } + return orderStatus +} + +func (c *OrderController) onOrderStatusMsg(msg *elmapi.CallbackOrderStatusMsg) (retVal *elmapi.CallbackResponse) { + switch msg.MsgType { + case elmapi.MsgTypeOrderAccepted: + retVal = c.onOrderAccepted(msg) + case elmapi.MsgTypeOrderCanceled: + retVal = c.onOrderCanceled(msg) + case elmapi.MsgTypeOrderInvalid: + retVal = c.onOrderInvalid(msg) + case elmapi.MsgTypeOrderForceInvalid: + retVal = c.onOrderForceInvalid(msg) + case elmapi.MsgTypeOrderFinished: + retVal = c.onOrderFinished(msg) + default: + globals.SugarLogger.Warnf("elm msg:%d not handled", msg.MsgType) + retVal = elmapi.SuccessResponse + } + return retVal +} + +func (c *OrderController) onOrderCancelRefundMsg(msg *elmapi.CallbackOrderCancelRefundMsg) (retVal *elmapi.CallbackResponse) { + switch msg.MsgType { + case elmapi.MsgTypeUserApplyCancel: + retVal = c.onOrderUserApplyCancel(msg) + case elmapi.MsgTypeUserApplyRefund: + retVal = c.onOrderUserApplyRefund(msg) + default: + retVal = c.onOrderOtherCancelRefundStatus(msg) + } + return retVal +} + +func (c *OrderController) getOrderInfo(msg *elmapi.CallbackOrderStatusMsg) (order *model.Order, orderSkus []*model.OrderSku, err error) { + result, err := api.GetOrder(msg.OrderID) + if err == nil { + phoneList := result["phoneList"].([]interface{}) + consigneeMobile := "" + if len(phoneList) > 0 { + consigneeMobile = phoneList[0].(string) + } + order = &model.Order{ + VendorOrderID: msg.OrderID, + VendorID: controller.VendorIDELM, + VendorStoreID: result["shopId"].(string), + StoreID: int(utils.Str2Int64(result["openId"].(string))), + StoreName: result["shopName"].(string), + ConsigneeName: result["consignee"].(string), + ConsigneeMobile: consigneeMobile, + VendorStatus: msg.State, + OrderCreatedAt: utils.Str2Time(result["createdAt"].(string)), + } + + orderSkus = []*model.OrderSku{} + for _, group := range result["groups"].([]map[string]interface{}) { + for _, product := range group["items"].([]map[string]interface{}) { + sku := &model.OrderSku{ + VendorOrderID: msg.OrderID, + VendorID: controller.VendorIDJD, + Count: int(utils.MustInterface2Int64(product["quantity"])), + SkuID: int(utils.Str2Int64(product["extendCode"].(string))), + VendorSkuID: product["skuId"].(string), + SkuName: product["name"].(string), + SalePrice: utils.MustInterface2Int64(product["userPrice"]), + OrderCreatedAt: order.OrderCreatedAt, + } + orderSkus = append(orderSkus, sku) + order.SkuCount++ + order.SalePrice += sku.SalePrice + } + } + } + + return order, orderSkus, err +} + +// +func (c *OrderController) onOrderNew(msg map[string]interface{}) (response *elmapi.CallbackResponse) { + // todo 这里应该可以直接用msg里的内容,而不用再次去查 + fakeOrderMsg := &elmapi.CallbackOrderStatusMsg{ + OrderID: msg["orderId"].(string), + State: elmapi.OrderStatusFake, + } + order, orderSkus, err := c.getOrderInfo(fakeOrderMsg) + if err == nil { + err = c.OnOrderNew(c, order, orderSkus) + } + return elmapi.Err2CallbackResponse(err, "elm onOrderNew") +} + +func (c *OrderController) onOrderAccepted(msg *elmapi.CallbackOrderStatusMsg) *elmapi.CallbackResponse { + status := c.orderStatusMsg2Status(msg) + err := c.OnOrderAccepted(c, status) + if err == nil { + status.VendorStatus = "fakeautopickup" + err = c.OnOrderFinishedPickup(c, c.orderStatusMsg2Status(msg)) + } + return elmapi.Err2CallbackResponse(err, "elm onOrderAccepted") +} + +func (c *OrderController) onOrderCanceled(msg *elmapi.CallbackOrderStatusMsg) *elmapi.CallbackResponse { + return elmapi.Err2CallbackResponse(c.OnOrderCanceled(c, c.orderStatusMsg2Status(msg)), "elm onOrderCanceled") +} + +func (c *OrderController) onOrderInvalid(msg *elmapi.CallbackOrderStatusMsg) *elmapi.CallbackResponse { + return c.onOrderCanceled(msg) +} + +func (c *OrderController) onOrderForceInvalid(msg *elmapi.CallbackOrderStatusMsg) *elmapi.CallbackResponse { + return c.onOrderCanceled(msg) +} + +func (c *OrderController) onOrderFinished(msg *elmapi.CallbackOrderStatusMsg) *elmapi.CallbackResponse { + return elmapi.Err2CallbackResponse(c.OnOrderDelivered(c, c.orderStatusMsg2Status(msg)), "elm onOrderFinished") +} + +func (c *OrderController) onOrderUserUrgeOrder(msg *elmapi.CallbackOrderUrgeMsg) *elmapi.CallbackResponse { + orderStatus := &model.OrderStatus{ + VendorOrderID: msg.OrderID, + VendorID: controller.VendorIDELM, + OrderType: controller.OrderTypeOrder, + Status: controller.OrderStatusEvent, + VendorStatus: utils.Int2Str(msg.MsgType), + StatusTime: utils.Timestamp2Time(msg.UpdateTime), + } + return elmapi.Err2CallbackResponse(c.OnOrderUserUrgeOrder(c, orderStatus), "elm onOrderUserUrgeOrder") +} + +func (c *OrderController) onOrderUserApplyCancel(msg *elmapi.CallbackOrderCancelRefundMsg) *elmapi.CallbackResponse { + return elmapi.Err2CallbackResponse(c.OnOrderUserApplyCancel(c, c.cancelRefundMsg2Status(msg)), "elm onOrderUserApplyCancel") +} + +func (c *OrderController) onOrderUserApplyRefund(msg *elmapi.CallbackOrderCancelRefundMsg) *elmapi.CallbackResponse { + return elmapi.Err2CallbackResponse(c.OnOrderUserApplyRefund(c, c.cancelRefundMsg2Status(msg)), "elm onOrderUserApplyRefund") +} + +func (c *OrderController) onOrderOtherCancelRefundStatus(msg *elmapi.CallbackOrderCancelRefundMsg) *elmapi.CallbackResponse { + return elmapi.Err2CallbackResponse(c.OnOrderOtherStatus(c, c.cancelRefundMsg2Status(msg)), "elm onOrderOtherCancelRefundStatus") +} + +// PurchasePlatformHandler +func (c *OrderController) AcceptOrRefuseOrder(order *model.Order, isAcceptIt bool) { + if isAcceptIt { + api.ConfirmOrder(order.VendorOrderID) + } else { + api.CancelOrder(order.VendorOrderID, elmapi.CancelOrderTypeOthers, "") + } +} diff --git a/business/controller/elm/waybill.go b/business/controller/elm/waybill.go new file mode 100644 index 000000000..b1e8e3d7a --- /dev/null +++ b/business/controller/elm/waybill.go @@ -0,0 +1,92 @@ +package elm + +import ( + "fmt" + + "git.rosy.net.cn/baseapi/platformapi/elmapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/controller" + "git.rosy.net.cn/jx-callback/business/model" +) + +type WaybillController struct { + controller.WaybillController +} + +func (c *WaybillController) OnWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { + controller.RoutinePool.CallFun(func() { + retVal = c.onWaybillStatusMsg(msg) + }, msg.OrderID) + return retVal +} + +func (c *WaybillController) onWaybillStatusMsg(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { + if msg.MsgType == elmapi.MsgTypeWaybillWait4DeliveryVendor { + retVal = c.onWaybillWait4DeliveryVendor(msg) + } else if msg.MsgType == elmapi.MsgTypeWaybillPickingUp { + retVal = c.onWaybillPickingUp(msg) + } else if msg.MsgType == elmapi.MsgTypeWaybillDelivering { + retVal = c.onWaybillDelivering(msg) + } else if msg.MsgType == elmapi.MsgTypeWaybillDelivered { + retVal = c.onWaybillDelivered(msg) + } else if msg.MsgType >= elmapi.MsgTypeWaybillCanceledByMerchant && msg.MsgType <= elmapi.MsgTypeWaybillCanceledBySystem { + retVal = c.onWaybillCanceled(msg) + } else if msg.MsgType >= elmapi.MsgTypeWaybillFailedCallLate && + msg.MsgType <= elmapi.MsgTypeRejectedSystemError && + msg.MsgType != elmapi.MsgTypeDeiverBySelf { + retVal = c.onWaybillFailed(msg) + } else { + // MsgTypeWait4Courier + // MsgTypeDeiverBySelf + retVal = c.onWaybillOtherStatus(msg) + } + return retVal +} + +func (c *WaybillController) onWaybillWait4DeliveryVendor(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { + order := &model.Waybill{ + VendorOrderID: msg.OrderID, + VendorID: controller.VendorIDELM, + VendorWaybillID: msg.OrderID, + WaybillVendorID: controller.VendorIDELM, + CourierName: msg.Name, + CourierMobile: msg.Phone, + WaybillCreatedAt: utils.Timestamp2Time(msg.UpdateAt / 1000), + } + return elmapi.Err2CallbackResponse(c.OnWaybillNew(order), "elm onWaybillWait4DeliveryVendor") +} + +func (c *WaybillController) onWaybillPickingUp(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { + return elmapi.Err2CallbackResponse(c.OnWaybillAccepted(c.callbackMsg2Status(msg)), "elm onWaybillPickingUp") +} + +func (c *WaybillController) onWaybillDelivering(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { + return elmapi.Err2CallbackResponse(c.OnWaybillDelivering(c.callbackMsg2Status(msg)), "elm onWaybillDelivering") +} + +func (c *WaybillController) onWaybillDelivered(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { + return elmapi.Err2CallbackResponse(c.OnWaybillDelivered(c.callbackMsg2Status(msg)), "elm onWaybillDelivered") +} + +func (c *WaybillController) onWaybillCanceled(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { + return elmapi.Err2CallbackResponse(c.OnWaybillCanceled(c.callbackMsg2Status(msg)), "elm onWaybillCanceled") +} + +func (c *WaybillController) onWaybillFailed(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { + return elmapi.Err2CallbackResponse(c.OnWaybillFailed(c.callbackMsg2Status(msg)), "elm onWaybillFailed") +} + +func (c *WaybillController) onWaybillOtherStatus(msg *elmapi.CallbackWaybillStatusMsg) (retVal *elmapi.CallbackResponse) { + return elmapi.Err2CallbackResponse(c.OnWaybillOtherStatus(c.callbackMsg2Status(msg)), "elm onWaybillOtherStatus") +} + +func (c *WaybillController) callbackMsg2Status(msg *elmapi.CallbackWaybillStatusMsg) (retVal *model.OrderStatus) { + status := &model.OrderStatus{ + VendorOrderID: msg.OrderID, + VendorID: controller.VendorIDELM, + OrderType: controller.OrderTypeWaybill, + VendorStatus: fmt.Sprintf("%s-%s-%d", msg.State, msg.SubState, msg.MsgType), + StatusTime: utils.Timestamp2Time(msg.UpdateAt / 1000), + } + return status +} diff --git a/business/controller/jd/order.go b/business/controller/jd/order.go new file mode 100644 index 000000000..59561146a --- /dev/null +++ b/business/controller/jd/order.go @@ -0,0 +1,144 @@ +package jd + +import ( + "git.rosy.net.cn/baseapi/platformapi/jdapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/controller" + "git.rosy.net.cn/jx-callback/business/model" +) + +type OrderController struct { + controller.OrderController +} + +var ( + api *jdapi.API +) + +func (c *OrderController) OnOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { + controller.RoutinePool.CallFun(func() { + retVal = c.onOrderMsg(msg) + }, msg.BillID) + return retVal +} + +func (c *OrderController) callbackMsg2Status(msg *jdapi.CallbackOrderMsg) *model.OrderStatus { + orderStatus := &model.OrderStatus{ + VendorOrderID: msg.BillID, + VendorID: controller.VendorIDJD, + OrderType: controller.OrderTypeOrder, + VendorStatus: msg.StatusID, + StatusTime: utils.Str2Time(msg.Timestamp), + } + return orderStatus +} + +func (c *OrderController) onOrderMsg(msg *jdapi.CallbackOrderMsg) (retVal *jdapi.CallbackResponse) { + switch msg.StatusID { + case jdapi.OrderStatusNew: + retVal = c.onOrderNew(msg) + case jdapi.OrderStatusAdjust: + retVal = c.onOrderAdjust(msg) + case jdapi.OrderStatusWaitOutStore: + retVal = c.onOrderWaitOutStore(msg) + case jdapi.OrderStatusFinishedPickup: + retVal = c.onOrderFinishedPickup(msg) + case jdapi.OrderStatusDelivering: + retVal = c.onOrderDelivering(msg) + case jdapi.OrderStatusDelivered: + retVal = c.onOrderDelivered(msg) + case jdapi.OrderStatusCanceled: + retVal = c.onOrderCanceled(msg) + case jdapi.OrderStatusUserApplyCancel: + retVal = c.onOrderUserApplyCancel(msg) + default: + retVal = c.onOrderOtherStatus(msg) + } + return retVal +} + +func (c *OrderController) getOrderInfo(msg *jdapi.CallbackOrderMsg) (order *model.Order, orderSkus []*model.OrderSku, err error) { + result, err := api.QuerySingleOrder(msg.BillID) + if err == nil { + order = &model.Order{ + VendorOrderID: msg.BillID, + VendorID: controller.VendorIDJD, + VendorStoreID: result["produceStationNo"].(string), + StoreID: int(utils.MustInterface2Int64(result["produceStationNoIsv"])), + StoreName: result["produceStationName"].(string), + ConsigneeName: result["buyerFullName"].(string), + ConsigneeMobile: result["buyerMobile"].(string), + VendorStatus: msg.StatusID, + OrderCreatedAt: utils.Str2Time(result["orderPurchaseTime"].(string)), + } + // discounts := result["discount"].(map[string]interface{}) + orderSkus = []*model.OrderSku{} + for _, product := range result["product"].([]map[string]interface{}) { + sku := &model.OrderSku{ + VendorOrderID: msg.BillID, + VendorID: controller.VendorIDJD, + Count: int(utils.MustInterface2Int64(product["skuCount"])), + SkuID: int(utils.Str2Int64(product["skuIdIsv"].(string))), + VendorSkuID: product["skuId"].(string), + SkuName: product["skuName"].(string), + SalePrice: utils.MustInterface2Int64(product["skuJdPrice"]), + OrderCreatedAt: order.OrderCreatedAt, + } + orderSkus = append(orderSkus, sku) + order.SkuCount++ + order.SalePrice += sku.SalePrice + } + } + + return order, orderSkus, err +} + +// +func (c *OrderController) onOrderNew(msg *jdapi.CallbackOrderMsg) (response *jdapi.CallbackResponse) { + order, orderSkus, err := c.getOrderInfo(msg) + if err == nil { + err = c.OnOrderNew(c, order, orderSkus) + } + return jdapi.Err2CallbackResponse(err, "jd onOrderNew") +} + +func (c *OrderController) onOrderAdjust(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse { + order, orderSkus, err := c.getOrderInfo(msg) + if err == nil { + err = c.OnOrderAdjust(c, order, orderSkus) + } + return jdapi.Err2CallbackResponse(err, "jd onOrderAdjust") +} + +func (c *OrderController) onOrderWaitOutStore(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse { + return jdapi.Err2CallbackResponse(c.OnOrderAccepted(c, c.callbackMsg2Status(msg)), "jd onOrderWaitOutStore") +} + +func (c *OrderController) onOrderFinishedPickup(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse { + return jdapi.Err2CallbackResponse(c.OnOrderFinishedPickup(c, c.callbackMsg2Status(msg)), "jd onOrderFinishedPickup") +} + +func (c *OrderController) onOrderDelivering(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse { + return jdapi.Err2CallbackResponse(c.OnOrderDelivering(c, c.callbackMsg2Status(msg)), "jd onOrderDelivering") +} + +func (c *OrderController) onOrderDelivered(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse { + return jdapi.Err2CallbackResponse(c.OnOrderDelivered(c, c.callbackMsg2Status(msg)), "jd onOrderDelivered") +} + +func (c *OrderController) onOrderCanceled(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse { + return jdapi.Err2CallbackResponse(c.OnOrderCanceled(c, c.callbackMsg2Status(msg)), "jd onOrderCanceled") +} + +func (c *OrderController) onOrderUserApplyCancel(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse { + return jdapi.Err2CallbackResponse(c.OnOrderUserApplyCancel(c, c.callbackMsg2Status(msg)), "jd onOrderUserApplyCancel") +} + +func (c *OrderController) onOrderOtherStatus(msg *jdapi.CallbackOrderMsg) *jdapi.CallbackResponse { + return jdapi.Err2CallbackResponse(c.OnOrderOtherStatus(c, c.callbackMsg2Status(msg)), "jd onOrderOtherStatus") +} + +// PurchasePlatformHandler +func (c *OrderController) AcceptOrRefuseOrder(order *model.Order, isAcceptIt bool) { + api.OrderAcceptOperate(order.VendorOrderID, isAcceptIt) +} diff --git a/business/controller/jd/waybill.go b/business/controller/jd/waybill.go new file mode 100644 index 000000000..dc780cd99 --- /dev/null +++ b/business/controller/jd/waybill.go @@ -0,0 +1,87 @@ +package jd + +import ( + "git.rosy.net.cn/baseapi/platformapi/jdapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/controller" + "git.rosy.net.cn/jx-callback/business/model" +) + +type WaybillController struct { + controller.WaybillController +} + +func (c *WaybillController) OnWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { + controller.RoutinePool.CallFun(func() { + retVal = c.onWaybillMsg(msg) + }, msg.OrderID) + return retVal +} + +func (c *WaybillController) callbackMsg2Status(msg *jdapi.CallbackDeliveryStatusMsg) *model.OrderStatus { + status := &model.OrderStatus{ + VendorOrderID: msg.OrderID, + VendorID: controller.VendorIDJD, + OrderType: controller.OrderTypeWaybill, + VendorStatus: msg.DeliveryStatus, + StatusTime: utils.Str2Time(msg.DeliveryStatusTime), + } + return status +} + +func (c *WaybillController) onWaybillMsg(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { + switch msg.DeliveryStatus { + case jdapi.DeliveryStatusWait4Grap: + retVal = c.onWaybillNew(msg) + case jdapi.DeliveryStatusAccepted: + retVal = c.onWaybillAccepted(msg) + case jdapi.DeliveryStatusCourierCanceled: + retVal = c.onWaybillAcceptCanceled(msg) + case jdapi.DeliveryStatusGotGoods: + retVal = c.onWaybillGotGoods(msg) + case jdapi.DeliveryStatusFinished: + retVal = c.onWaybillFinished(msg) + case jdapi.DeliveryStatusFailedDelivery: + retVal = c.onWaybillFailed(msg) + default: + retVal = c.onWaybillOtherStatus(msg) + } + return retVal +} + +func (c *WaybillController) onWaybillNew(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { + order := &model.Waybill{ + VendorOrderID: msg.OrderID, + VendorID: controller.VendorIDJD, + VendorWaybillID: msg.OrderID, + WaybillVendorID: controller.VendorIDJD, + CourierName: msg.DeliveryManName, + CourierMobile: msg.DeliveryManPhone, + WaybillCreatedAt: utils.Str2Time(msg.DeliveryStatusTime), + } + return jdapi.Err2CallbackResponse(c.OnWaybillNew(order), "jd onWaybillNew") +} + +func (c *WaybillController) onWaybillAccepted(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { + return jdapi.Err2CallbackResponse(c.OnWaybillAccepted(c.callbackMsg2Status(msg)), "jd onWaybillAccepted") +} + +func (c *WaybillController) onWaybillAcceptCanceled(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { + return jdapi.Err2CallbackResponse(c.OnWaybillAcceptCanceled(c.callbackMsg2Status(msg)), "jd onWaybillAcceptCanceled") +} + +func (c *WaybillController) onWaybillGotGoods(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { + return jdapi.Err2CallbackResponse(c.OnWaybillDelivering(c.callbackMsg2Status(msg)), "jd onWaybillGotGoods") +} + +func (c *WaybillController) onWaybillFinished(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { + return jdapi.Err2CallbackResponse(c.OnWaybillDelivered(c.callbackMsg2Status(msg)), "jd onWaybillFinished") +} + +func (c *WaybillController) onWaybillFailed(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { + return jdapi.Err2CallbackResponse(c.OnWaybillFailed(c.callbackMsg2Status(msg)), "jd onWaybillFailed") +} + +func (c *WaybillController) onWaybillOtherStatus(msg *jdapi.CallbackDeliveryStatusMsg) (retVal *jdapi.CallbackResponse) { + return jdapi.Err2CallbackResponse(c.OnWaybillOtherStatus(c.callbackMsg2Status(msg)), "jd onWaybillOtherStatus") +} diff --git a/business/controller/mtps/waybill.go b/business/controller/mtps/waybill.go new file mode 100644 index 000000000..14cf1a952 --- /dev/null +++ b/business/controller/mtps/waybill.go @@ -0,0 +1,80 @@ +package mtps + +import ( + "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/model" + "git.rosy.net.cn/jx-callback/globals" +) + +type WaybillController struct { + controller.WaybillController +} + +func (c *WaybillController) OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { + controller.RoutinePool.CallFun(func() { + retVal = c.onWaybillMsg(msg) + }, msg.MtPeisongID) + return retVal +} + +func (c *WaybillController) callbackMsg2Status(msg *mtpsapi.CallbackOrderMsg) *model.OrderStatus { + orderStatus := &model.OrderStatus{ + VendorOrderID: msg.MtPeisongID, + VendorID: controller.VendorIDMTPS, + OrderType: controller.OrderTypeWaybill, + VendorStatus: utils.Int2Str(msg.Status), + StatusTime: utils.Timestamp2Time(int64(msg.Timestamp)), + } + return orderStatus +} + +func (c *WaybillController) onWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { + switch msg.Status { + case mtpsapi.OrderStatusWaitingForSchedule: + retVal = c.onWaybillNew(msg) + case mtpsapi.OrderStatusAccepted: + retVal = c.onWaybillAccepted(msg) + case mtpsapi.OrderStatusPickedUp: + retVal = c.onWaybillPickedUp(msg) + case mtpsapi.OrderStatusDeliverred: + retVal = c.onWaybillDelivered(msg) + case mtpsapi.OrderStatusCanceled: + retVal = c.onWaybillCanceled(msg) + default: + globals.SugarLogger.Warnf("unknown msg:%v", msg) + retVal = mtpsapi.SuccessResponse + } + return retVal +} + +func (c *WaybillController) onWaybillNew(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { + order := &model.Waybill{ + VendorOrderID: msg.OrderID, + VendorID: controller.GetVendorIDFromUniversalOrderID(msg.OrderID), + VendorWaybillID: msg.MtPeisongID, + VendorWaybillID2: utils.Int64ToStr(msg.DeliveryID), + WaybillVendorID: controller.VendorIDMTPS, + CourierName: msg.CourierName, + CourierMobile: msg.CourierPhone, + WaybillCreatedAt: utils.Timestamp2Time(msg.Timestamp), + } + return mtpsapi.Err2CallbackResponse(c.OnWaybillNew(order), "mtps onWaybillNew") +} + +func (c *WaybillController) onWaybillAccepted(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { + return mtpsapi.Err2CallbackResponse(c.OnWaybillAccepted(c.callbackMsg2Status(msg)), "mtps onWaybillAccepted") +} + +func (c *WaybillController) onWaybillPickedUp(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { + return mtpsapi.Err2CallbackResponse(c.OnWaybillDelivering(c.callbackMsg2Status(msg)), "mtps onWaybillPickedUp") +} + +func (c *WaybillController) onWaybillDelivered(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { + return mtpsapi.Err2CallbackResponse(c.OnWaybillDelivered(c.callbackMsg2Status(msg)), "mtps onWaybillDelivered") +} + +func (c *WaybillController) onWaybillCanceled(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) { + return mtpsapi.Err2CallbackResponse(c.OnWaybillCanceled(c.callbackMsg2Status(msg)), "mtps onWaybillCanceled") +} diff --git a/business/controller/order.go b/business/controller/order.go new file mode 100644 index 000000000..d39be2b4e --- /dev/null +++ b/business/controller/order.go @@ -0,0 +1,249 @@ +package controller + +import ( + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/baseapi/utils/routinepool" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/globals" + "git.rosy.net.cn/jx-callback/legacy/models" + "github.com/astaxie/beego/orm" +) + +const ( + OrderStatusEvent = -1 + + OrderStatusUnknown = 0 + + OrderStatusNew = 5 // 新定单 + OrderStatusAccepted = 10 // 已经接单,也即待出库,待拣货 + OrderStatusFinishedPickup = 15 // 拣货完成 + OrderStatusDelivering = 20 // 开始配送,配送员已取货,从这里开始就是运单消息了 + + OrderStatusDelivered = 105 // 妥投 + OrderStatusFinished = 110 // 定单已完成 + OrderStatusCanceled = 115 // 定单已取消 + OrderStatusFailed = 120 // 定单已失败 +) + +const ( + LockStatusUnlocked = 0 + LockStatusLocked = 1 +) + +type PurchasePlatformHandler interface { + AcceptOrRefuseOrder(order *model.Order, isAcceptIt bool) +} + +var ( + OrderMap SyncMapWithTimeout +) + +func init() { + RoutinePool = routinepool.New(1000, 1000) +} + +type OrderController struct { +} + +func (c *OrderController) OnOrderNew(purchasePlatform PurchasePlatformHandler, order *model.Order, orderSkus []*model.OrderSku) (err error) { + db := orm.NewOrm() + c.handleAutoAcceptOrder(order.VendorOrderID, order.VendorID, order.ConsigneeMobile, order.StoreID, db, func(isAccept bool) { + // purchasePlatform.AcceptOrRefuseOrder(order, isAccept) + if isAccept { + order.Status = OrderStatusAccepted + } else { + order.Status = OrderStatusFailed + } + }) + + err = c.updateOrderOtherInfo(order, db) + if err == nil { + err = c.updateOrderSkuOtherInfo(orderSkus, db) + if err == nil { + db.Begin() + created, _, err2 := db.ReadOrCreate(order, "VendorOrderID", "VendorID") + err = err2 + if err == nil { + OrderMap.Store(ComposeUniversalOrderID(order.VendorOrderID, order.VendorID), order.ID) + if created { + sql := "" + params := []interface{}{} + for _, sku := range orderSkus { + if sql == "" { + sql = "INSERT INTO order_sku(vendor_order_id, vendor_id, count, sku_id, vendor_sku_id, sku_name, shop_price, sale_price) VALUES(?, ?, ?, ?, ?, ?, ?, ?)" + + } else { + sql += ",(?, ?, ?, ?, ?, ?, ?, ?)" + } + params = append(params, sku.VendorOrderID, sku.VendorID, sku.Count, sku.SkuID, sku.VendorSkuID, sku.SkuName, sku.ShopPrice, sku.SalePrice) + } + sql += ";" + _, err = db.Raw(sql, params...).Exec() + if err != nil { + db.Rollback() + } else { + db.Commit() + } + } else { + db.Rollback() + baseapi.SugarLogger.Warnf("duplicated order:%v msg received", order) + } + } else { + db.Rollback() + } + } + } + return err +} + +func (c *OrderController) OnOrderAdjust(purchasePlatform PurchasePlatformHandler, order *model.Order, orderSkus []*model.OrderSku) (err error) { + db := orm.NewOrm() + err = utils.CallFuncLogError(func() error { + _, err := db.Raw("DELETE FROM order_sku WHERE vendor_order_id=? AND vendor_id=?", order.VendorOrderID, order.VendorID).Exec() + return err + }, "OnAdjustOrder delete order_sku") + if err != nil { + return err + } + + err = utils.CallFuncLogError(func() error { + _, err := db.Raw("DELETE FROM order WHERE vendor_order_id=? AND vendor_id=?", order.VendorOrderID, order.VendorID).Exec() + return err + }, "OnAdjustOrder delete order") + if err != nil { + return err + } + + return c.OnOrderNew(purchasePlatform, order, orderSkus) +} + +func (c *OrderController) OnOrderAccepted(purchasePlatform PurchasePlatformHandler, msg *model.OrderStatus) (err error) { + msg.Status = OrderStatusAccepted + return c.addOrderStatus(msg) +} + +func (c *OrderController) OnOrderFinishedPickup(purchasePlatform PurchasePlatformHandler, msg *model.OrderStatus) (err error) { + msg.Status = OrderStatusFinishedPickup + return c.addOrderStatus(msg) +} + +func (c *OrderController) OnOrderDelivering(purchasePlatform PurchasePlatformHandler, msg *model.OrderStatus) (err error) { + msg.Status = OrderStatusDelivering + return c.addOrderStatus(msg) +} + +func (c *OrderController) OnOrderDelivered(purchasePlatform PurchasePlatformHandler, msg *model.OrderStatus) (err error) { + msg.Status = OrderStatusDelivered + return c.addOrderStatus(msg) +} + +func (c *OrderController) OnOrderCanceled(purchasePlatform PurchasePlatformHandler, msg *model.OrderStatus) (err error) { + msg.Status = OrderStatusFailed + return c.addOrderStatus(msg) +} + +func (c *OrderController) OnOrderFailed(purchasePlatform PurchasePlatformHandler, msg *model.OrderStatus) (err error) { + msg.Status = OrderStatusFailed + return c.addOrderStatus(msg) +} + +// +func (c *OrderController) OnOrderUserApplyCancel(purchasePlatform PurchasePlatformHandler, msg *model.OrderStatus) (err error) { + msg.Status = OrderStatusEvent + return c.addOrderStatus(msg) +} + +func (c *OrderController) OnOrderUserApplyRefund(purchasePlatform PurchasePlatformHandler, msg *model.OrderStatus) (err error) { + msg.Status = OrderStatusEvent + return c.addOrderStatus(msg) +} + +func (c *OrderController) OnOrderUserUrgeOrder(purchasePlatform PurchasePlatformHandler, msg *model.OrderStatus) (err error) { + msg.Status = OrderStatusEvent + return c.addOrderStatus(msg) +} + +// +func (c *OrderController) OnOrderOtherStatus(purchasePlatform PurchasePlatformHandler, msg *model.OrderStatus) (err error) { + msg.Status = OrderStatusEvent + return c.addOrderStatus(msg) +} + +// private +func (c *OrderController) updateOrderSkuOtherInfo(orderSkus []*model.OrderSku, db orm.Ormer) (err error) { + return nil +} + +func (c *OrderController) updateOrderOtherInfo(order *model.Order, db orm.Ormer) (err error) { + return nil +} + +func (c *OrderController) handleAutoAcceptOrder(orderID string, vendorID int, userMobile string, jxStoreID int, db orm.Ormer, handler func(accepted bool)) int { + handleType := 0 + if userMobile != "" { + if db == nil { + db = orm.NewOrm() + } + user := &models.BlackClient{ + Mobile: userMobile, + } + if err := db.Read(user, "Mobile"); err != nil { + if err != orm.ErrNoRows { + globals.SugarLogger.Errorf("read data error:%v, data:%v, vendorID:%d", err, user, vendorID) + } + // 在访问数据库出错的情况下,也需要自动接单 + handleType = 1 + } else { + // 强制拒单 + globals.SugarLogger.Infof("force reject order:%s, vendorID:%d", orderID, vendorID) + handleType = -1 + } + } else { + globals.SugarLogger.Infof("order:%s, vendorID:%d, mobile is empty, should accept it", orderID, vendorID) + handleType = 1 + } + + if handleType == 1 { + handler(true) + } else if handleType == -1 { + handler(false) + } + + return handleType +} + +func (c *OrderController) addOrderStatus(msg *model.OrderStatus) (err error) { + order := &model.Order{ + VendorOrderID: msg.VendorOrderID, + VendorID: msg.VendorID, + } + db := orm.NewOrm() + value, ok := OrderMap.Load(ComposeUniversalOrderID(msg.VendorOrderID, msg.VendorID)) + if !ok { + globals.SugarLogger.Warnf("can not get order:%v, from cache", order) + err = db.Read(order, "VendorOrderID", "VendorID") + } else { + order.ID = value.(int64) + } + + if err == nil { + if msg.Status != OrderStatusEvent { + order.Status = msg.Status + utils.CallFuncLogError(func() error { + columns := []string{"Status"} + if msg.Status >= OrderStatusDelivered { + order.OrderFinishedAt = msg.StatusTime + columns = append(columns, "OrderFinishedAt") + } + _, err := db.Update(order, columns...) + return err + }, "update order") + } + utils.CallFuncLogError(func() error { + _, err := db.Insert(msg) + return err + }, "insert status") + } + return err +} diff --git a/business/controller/waybill.go b/business/controller/waybill.go new file mode 100644 index 000000000..10993c27e --- /dev/null +++ b/business/controller/waybill.go @@ -0,0 +1,111 @@ +package controller + +import ( + "git.rosy.net.cn/baseapi" + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/globals" + "github.com/astaxie/beego/orm" +) + +const ( + WaybillStatusUnknown = 0 + + WaybillStatusNew = 5 + WaybillStatusAccepted = 10 + WaybillStatusDelivering = 20 + + WaybillStatusDelivered = 105 + WaybillStatusCanceled = 115 + WaybillStatusFailed = 120 +) + +type WaybillController struct { +} + +var ( + WaybillMap SyncMapWithTimeout +) + +func (w *WaybillController) OnWaybillNew(bill *model.Waybill) (err error) { + db := orm.NewOrm() + bill.Status = WaybillStatusNew + created, _, err := db.ReadOrCreate(bill, "VendorWaybillID", "WaybillVendorID") + if err == nil { + WaybillMap.Store(ComposeUniversalOrderID(bill.VendorWaybillID, bill.WaybillVendorID), bill.ID) + if !created { + baseapi.SugarLogger.Warnf("duplicated waybill:%v msg received", bill) + } + } + return err +} + +func (w *WaybillController) OnWaybillAccepted(msg *model.OrderStatus) (err error) { + msg.Status = WaybillStatusAccepted + return w.addWaybillStatus(msg) +} + +func (w *WaybillController) OnWaybillAcceptCanceled(msg *model.OrderStatus) (err error) { + msg.Status = WaybillStatusNew + return w.addWaybillStatus(msg) +} + +func (w *WaybillController) OnWaybillDelivering(msg *model.OrderStatus) (err error) { + msg.Status = WaybillStatusDelivering + return w.addWaybillStatus(msg) +} + +func (w *WaybillController) OnWaybillDelivered(msg *model.OrderStatus) (err error) { + msg.Status = WaybillStatusDelivered + return w.addWaybillStatus(msg) +} + +func (w *WaybillController) OnWaybillCanceled(msg *model.OrderStatus) (err error) { + msg.Status = WaybillStatusCanceled + return w.addWaybillStatus(msg) +} + +func (w *WaybillController) OnWaybillFailed(msg *model.OrderStatus) (err error) { + msg.Status = WaybillStatusFailed + return w.addWaybillStatus(msg) +} + +func (w *WaybillController) OnWaybillOtherStatus(msg *model.OrderStatus) (err error) { + msg.Status = OrderStatusEvent + return w.addWaybillStatus(msg) +} + +func (w *WaybillController) addWaybillStatus(msg *model.OrderStatus) (err error) { + order := &model.Waybill{ + VendorWaybillID: msg.VendorOrderID, + WaybillVendorID: msg.VendorID, + } + db := orm.NewOrm() + value, ok := OrderMap.Load(ComposeUniversalOrderID(msg.VendorOrderID, msg.VendorID)) + if !ok { + globals.SugarLogger.Warnf("can not get order:%v, from cache", order) + err = db.Read(order, "VendorWaybillID", "WaybillVendorID") + } else { + order.ID = value.(int64) + } + + if err == nil { + if msg.Status != OrderStatusEvent { + order.Status = msg.Status + utils.CallFuncLogError(func() error { + columns := []string{"Status"} + if msg.Status >= OrderStatusDelivered { + order.WaybillFinishedAt = msg.StatusTime + columns = append(columns, "WaybillFinishedAt") + } + _, err := db.Update(order, columns...) + return err + }, "update order") + } + utils.CallFuncLogError(func() error { + _, err := db.Insert(msg) + return err + }, "insert status") + } + return err +} diff --git a/business/model/order.go b/business/model/order.go new file mode 100644 index 000000000..cb9d5f153 --- /dev/null +++ b/business/model/order.go @@ -0,0 +1,108 @@ +package model + +import "time" + +type ModelTimeInfo struct { + CreatedAt time.Time `orm:"auto_now_add;type(datetime)"` + UpdatedAt time.Time `orm:"auto_now;type(datetime)"` +} + +type Order struct { + ID int64 `orm:"column(id)"` + VendorOrderID string `orm:"column(vendor_order_id);size(48)"` + VendorID int `orm:"column(vendor_id)"` + VendorStoreID string `orm:"column(vendor_store_id);size(48)"` + StoreID int `orm:"column(store_id)"` // 外部系统里记录的 jxstoreid + JxStoreID int `orm:"column(jx_store_id)"` // 根据VendorStoreID在本地系统里查询出来的 jxstoreid + StoreName string `orm:"size(64)"` + SubStoreID int `orm:"column(sub_store_id)"` + SubStoreName string `orm:"size(64)"` + ShopPrice int64 + SalePrice int64 + ConsigneeName string `orm:"size(32)"` + ConsigneeMobile string `orm:"size(32)"` + SkuCount int + Status int + VendorStatus string `orm:"size(16)"` + LockStatus int + CancelApplyReason string `orm:"size(255);null;default(null)"` // null表示没有申请,不为null表示用户正在取消申请 + WaybillVendorID int `orm:"column(waybill_vendor_id)"` + OriginalData string `orm:"type(text)"` + OrderCreatedAt time.Time `orm:"type(datetime);index"` + OrderFinishedAt time.Time `orm:"type(datetime)"` + ModelTimeInfo +} + +func (o *Order) TableUnique() [][]string { + return [][]string{ + []string{"VendorOrderID", "VendorID"}, + } +} + +type OrderSku struct { + ID int64 `orm:"column(id)"` + VendorOrderID string `orm:"column(vendor_order_id);size(48)"` + VendorID int `orm:"column(vendor_id)"` + Count int + VendorSkuID string `orm:"column(vendor_sku_id),size(48)"` + SkuID int `orm:"column(sku_id)"` // 外部系统里记录的 jxskuid + JxSkuID int `orm:"column(jx_sku_id)"` // 根据VendorSkuID在本地系统里查询出来的 jxskuid + SkuName string `orm:"size(255)"` + ShopPrice int64 + SalePrice int64 + OrderCreatedAt time.Time `orm:"type(datetime);index"` +} + +func (o *OrderSku) TableUnique() [][]string { + return [][]string{ + []string{"VendorOrderID", "SkuID", "VendorID"}, + } +} + +type Waybill struct { + ID int64 `orm:"column(id)"` + VendorOrderID string `orm:"column(vendor_order_id);size(48)"` + VendorID int `orm:"column(vendor_id)"` + VendorWaybillID string `orm:"column(vendor_waybill_id);size(48)"` + VendorWaybillID2 string `orm:"column(vendor_waybill_id2);size(48)"` + WaybillVendorID int `orm:"column(waybill_vendor_id)"` + CourierName string `orm:"size(32)"` + CourierMobile string `orm:"size(32)"` + Status int + VendorStatus string `orm:"size(16)"` + ActualFee int64 + WaybillCreatedAt time.Time `orm:"type(datetime);index"` + WaybillFinishedAt time.Time `orm:"type(datetime)"` + ModelTimeInfo +} + +func (w *Waybill) TableUnique() [][]string { + return [][]string{ + []string{"VendorWaybillID", "WaybillVendorID"}, + } +} + +func (w *Waybill) TableIndex() [][]string { + return [][]string{ + []string{"VendorOrderID"}, + } +} + +// 包含定单与运单的状态及事件vendor status +type OrderStatus struct { + ID int64 `orm:"column(id)"` + VendorOrderID string `orm:"column(vendor_order_id);size(48)"` + VendorID int `orm:"column(vendor_id)"` + OrderType int // 0:定单,1:运单 + Status int // 如果Status为OrderStatusEvent,表示VendorStatus只是一个事件,不是状态 + VendorStatus string `orm:"size(16)"` + StatusTime time.Time `orm:"type(datetime);index"` + Count int `orm:"default(1)"` + ModelTimeInfo +} + +func (v *OrderStatus) TableIndex() [][]string { + return [][]string{ + []string{"VendorOrderID", "Status"}, + } +} diff --git a/globals/globals.go b/globals/globals.go index 72f1a5e2a..d68ad9fd9 100644 --- a/globals/globals.go +++ b/globals/globals.go @@ -33,6 +33,9 @@ func initDB() { orm.RegisterDataBase("default", "mysql", beego.AppConfig.String("dbConnectStr"), 30) models.RegisterModels() // orm.RegisterModel(new(model.Order)) + // orm.RegisterModel(new(model.OrderSku)) + // orm.RegisterModel(new(model.Waybill)) + // orm.RegisterModel(new(model.OrderStatus)) // create table orm.RunSyncdb("default", false, true) } diff --git a/legacy/elm/controller/order.go b/legacy/elm/controller/order.go index 0eaf683f8..6af123fc8 100644 --- a/legacy/elm/controller/order.go +++ b/legacy/elm/controller/order.go @@ -43,7 +43,7 @@ func (o *OrderController) OrderMessage(msg *elmapi.CallbackMsg) (retVal *elmapi. baseapi.SugarLogger.Warnf("elm can not get mobile info from %v, error:%v", msg, err) } retVal = o.NewOrder(msg, orderID, userMobile) - } else if msg.Type >= elmapi.MsgTypeMerchantValid && msg.Type <= elmapi.MsgTypeOrderFinished { + } else if msg.Type >= elmapi.MsgTypeOrderAccepted && msg.Type <= elmapi.MsgTypeOrderFinished { retVal = o.OrderStatusChanged(msg, orderID, innerMsg) } else { retVal = o.OrderOtherMsg(msg, orderID, innerMsg) @@ -138,7 +138,7 @@ func (o *OrderController) OrderStatusChanged(msg *elmapi.CallbackMsg, orderId st func (o *OrderController) OrderOtherMsg(msg *elmapi.CallbackMsg, orderId string, innerMsg map[string]interface{}) *elmapi.CallbackResponse { var err error - if msg.Type == elmapi.MsgTypeClientUrgeOrder { + if msg.Type == elmapi.MsgTypeUserUrgeOrder { err = freshfood.FreshFoodAPI.ELMClientUrgeOrder(orderId) } diff --git a/legacy/freshfood/freshfood.go b/legacy/freshfood/freshfood.go index 601c68924..5988a24ab 100644 --- a/legacy/freshfood/freshfood.go +++ b/legacy/freshfood/freshfood.go @@ -113,7 +113,7 @@ func init() { } func New(baseURL string) *API { - return &API{baseURL, &http.Client{Timeout: time.Second * 20}} + return &API{baseURL, &http.Client{Timeout: time.Second * 5}} } func (f *API) AccessFreshFood(apiStr string, params url.Values) error { @@ -227,7 +227,7 @@ func (f *API) MtpsOrderStatusChanged(order *mtpsapi.CallbackOrderMsg) error { params := make(url.Values) params.Set(URL_FRESHFOOD_PARA_DELIVERYID, utils.Int64ToStr(order.DeliveryID)) params.Set(URL_FRESHFOOD_PARA_MTPEISONID, order.MtPeisongID) - params.Set(URL_FRESHFOOD_PARA_ORDERID, order.OrderId) + params.Set(URL_FRESHFOOD_PARA_ORDERID, order.OrderID) params.Set(URL_FRESHFOOD_PARA_STATUS, utils.Int2Str(order.Status)) params.Set(URL_FRESHFOOD_PARA_COURIERNAME, order.CourierName) params.Set(URL_FRESHFOOD_PARA_COURIERPHONE, order.CourierPhone) @@ -244,7 +244,7 @@ func (f *API) MtpsOrderException(order *mtpsapi.CallbackOrderExceptionMsg) error params := make(url.Values) params.Set(URL_FRESHFOOD_PARA_DELIVERYID, utils.Int64ToStr(order.DeliveryID)) params.Set(URL_FRESHFOOD_PARA_MTPEISONID, order.MtPeisongID) - params.Set(URL_FRESHFOOD_PARA_ORDERID, order.OrderId) + params.Set(URL_FRESHFOOD_PARA_ORDERID, order.OrderID) params.Set(URL_FRESHFOOD_PARA_EXCEPTIONID, utils.Int64ToStr(order.ExceptionID)) params.Set(URL_FRESHFOOD_PARA_EXCEPTIONCODE, utils.Int2Str(order.ExceptionCode)) params.Set(URL_FRESHFOOD_PARA_EXCEPTIONDESC, order.ExceptionDescr) diff --git a/main.go b/main.go index 2abb73bc8..d77be3f7b 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,10 @@ package main import ( + _ "git.rosy.net.cn/jx-callback/business/controller/dada" + _ "git.rosy.net.cn/jx-callback/business/controller/elm" + _ "git.rosy.net.cn/jx-callback/business/controller/jd" + _ "git.rosy.net.cn/jx-callback/business/controller/mtps" "git.rosy.net.cn/jx-callback/legacy/jd/controller" "git.rosy.net.cn/jx-callback/legacy/tasks" _ "git.rosy.net.cn/jx-callback/routers"