package delivery import ( "crypto/rand" "fmt" "math/big" "time" "git.rosy.net.cn/baseapi/platformapi/mtpsapi" "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api" "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/business/partner" "git.rosy.net.cn/jx-callback/globals" ) // 订单骑手信息推送:将获取到的三方配送订单,且订单状态为配送中的订单,将配送人员的信息返回给订单方 // 该方法为定时任务,没五分钟推送一次订单消息,订单状态发生变化时 //配送状态code,如下提供配送状态枚举值, //以及各配送状态对应在C端(用户端)和B端(商家PC端)后台展示的配送状态信息。 //未同步配送状态时(C端:商家已接单;B端:待发配送) //0-配送单发往配送(C端:商家已接单;B端:待骑手接单) //1-已创建配送包裹(C端:商家已接单;B端:待骑手接单) //5-已分配骑手(C端:商家已接单;B端:已分配骑手) //10-骑手已接单(C端:骑手正在赶往商家;B端:待骑手取货) //15-骑手已到店(C端:骑手到店取货中;B端:骑手已到店) //20-骑手已取货(C端:商品配送中/骑手正在送货;B端:骑手已取货) //40-骑手已送达(C端:商品已送达;B端:骑手已送达) //100-配送单已取消(C端:商家已接单;B端:配送已取消) //注:若同步配送状态为“配送单已取消”,接口仍支持继续同步配送状态。 说明:商家如未上传此信息,则平台默认值为20(现已要求必传)。 func GetOrderRiderInfoToPlatform(orderId string, wayBillStatus int) { params := make(map[string]interface{}, 0) params["isDateFinish"] = false params["isIncludeFake"] = true params["mustInvoice"] = false params["adjustCount"] = 0 params["waybillVendorIDs"] = `[101,102,103,105]` if orderId != "" { // 订单id会忽略其他参数 params["keyword"] = orderId } else { params["statuss"] = "[20]" } // 每五分钟查询当前订单信息,待配送状态订单1 orders, _, err := dao.GetOrders(dao.GetDB(), nil, false, true, time.Now().Add(-24*time.Hour).Format("2006-01-02"), time.Now().Format("2006-01-02"), false, nil, false, "", params, 0, 10000) if err != nil { return } //1.此接口用于同步自配送商家自配订单(除在B2C清单中的商家)的配送信息,包括物流平台、骑手名称、骑手电话,且此配送信息会同步展示在用户端订单详情的“配送信息”中。 //(注:美团跑腿订单的配送信息,平台会自动回流,无需商家再同步。自配的配送信息目前只能在用户端查询,不支持在商家端查询 //2.从订单状态为“商家已确认”(status=4)到“订单已完成”(status=8)后的24小时之内,均可使用此接口创建和更新配送信息。 //3.当同一个订单已经上传了一次配送信息,如再次同步会更新配送信息,以最新的一次为准。 //4.如订单已完成、已取消等状态发货将失败。 for _, v := range orders { if orderId == "" && v.VendorID == model.VendorIDDD { // 抖音门店订单除了三方配送回调时推送,不在主动推送配送消息 continue } if orderId == "" { // 订单id为空是,是定时轮询操作,不做此状态 waybillList, _ := dao.GetWaybills(dao.GetDB(), v.VendorOrderID) if len(waybillList) > 0 && waybillList[0].Status > model.WaybillStatusEndBegin { globals.SugarLogger.Debugf("订单物流状态结束,不在推送订单状态:orderID[%s],wayBillId[%s]", v.VendorOrderID, waybillList[0].VendorWaybillID) continue } } riderInfo := &mtpsapi.RiderInfo{} if handlerInfo := partner.GetDeliveryPlatformFromVendorID(v.WaybillVendorID); handlerInfo != nil { if v.WaybillVendorID == model.VendorIDDada || v.WaybillVendorID == model.VendorIDFengNiao || v.WaybillVendorID == model.VendorIDUUPT { riderInfo, err = handlerInfo.Handler.GetRiderInfo(v.VendorOrderID, 0, v.VendorWaybillID) if err != nil { globals.SugarLogger.Debug("Get Order waybill rider info err FN/DADA/DYPS :%v", err) } } else if v.WaybillVendorID == model.VendorIDMTPS { if v.VendorWaybillID != "" { riderInfo, err = handlerInfo.Handler.GetRiderInfo(v.VendorOrderID, v.ID+1000000, v.VendorWaybillID) if err != nil { globals.SugarLogger.Debug("Get Order waybill rider info err MT:%v", err) } } } } if riderInfo == nil || wayBillStatus == model.OrderStatusNew || wayBillStatus == model.OrderStatusCanceled || (riderInfo.CourierName == "" && v.WaybillVendorID == -1 && v.DeliveryType == "store") { // 真商家自送 riderInfo.OrderId = v.VendorOrderID riderInfo.CourierName = "石锋" riderInfo.CourierPhone = "18048531223" riderInfo.LogisticsProviderCode = "10017" } switch riderInfo.LogisticsStatus { case 5: // 呼叫骑手 riderInfo.LogisticsStatus = 0 riderInfo.OpCode = tiktok_api.TiktokLogisticsStatusCALLRIDER case 12: // 骑手接单 riderInfo.LogisticsStatus = 12 riderInfo.OpCode = tiktok_api.TiktokLogisticsORDERRECEIVED case 15: // 到店 riderInfo.LogisticsStatus = 15 riderInfo.OpCode = tiktok_api.TiktokLogisticsRIDERARRIVED case 20: //配送中 riderInfo.LogisticsStatus = 20 riderInfo.OpCode = tiktok_api.TiktokLogisticsRIDERPICKUP case 110: // 完成 riderInfo.LogisticsStatus = 40 riderInfo.OpCode = tiktok_api.TiktokLogisticsDELIVERED case 105: // 完成 riderInfo.LogisticsStatus = 40 riderInfo.OpCode = tiktok_api.TiktokLogisticsDELIVERED case 115: // 取消 riderInfo.CourierName = "" riderInfo.CourierPhone = "" riderInfo.LogisticsStatus = 100 riderInfo.OpCode = tiktok_api.TiktokLogisticsCANCELDELIVERY case 22, 0, 120: // 异常配送 riderInfo.LogisticsStatus = 22 riderInfo.OpCode = tiktok_api.TiktokLogisticsINDDELIVERYEXCEPTION default: continue } if riderInfo.Longitude == "" { riderInfo.Longitude = utils.Float64ToStr(utils.Int2Float64(v.ConsigneeLng) / 1000000) } if riderInfo.Latitude == "" { riderInfo.Latitude = utils.Float64ToStr(utils.Int2Float64(v.ConsigneeLat) / 1000000) } // 目前只推送美团骑手信息 switch v.VendorID { case model.VendorIDMTWM: // 美团订单 paramsMap := utils.Struct2Map(riderInfo, "", true) if handler := partner.GetPurchaseOrderHandlerFromVendorID(v.VendorID); handler != nil { if err := handler.GetOrderRider(v.VendorOrgCode, v.VendorStoreID, paramsMap); err != nil { globals.SugarLogger.Errorf("Error pushing meituan rider information :%s--%s--%v", riderInfo.OrderId, riderInfo.ThirdCarrierOrderId, err) } } case model.VendorIDELM: // 饿了么 continue case model.VendorIDEBAI: // 饿百发单 continue case model.VendorIDJD: // 京东发单 continue case model.VendorIDGD: // 美团发单 continue case model.VendorIDYB: // 银豹发单 continue case model.VendorIDJDShop: // 京东商城 continue case model.VendorIDWSC: // 微盟微商城 continue case model.VendorIDDD: // 抖店小时达 continue default: globals.SugarLogger.Errorf("Order source error, non system order") continue } } return } func PullTiktokRiderInfo(riderInfo *mtpsapi.RiderInfo) { switch riderInfo.LogisticsStatus { case 5: // 呼叫骑手 riderInfo.LogisticsStatus = 0 riderInfo.OpCode = tiktok_api.TiktokLogisticsStatusCALLRIDER case 12: // 骑手接单 riderInfo.LogisticsStatus = 12 riderInfo.OpCode = tiktok_api.TiktokLogisticsORDERRECEIVED case 15: // 到店 riderInfo.LogisticsStatus = 15 riderInfo.OpCode = tiktok_api.TiktokLogisticsRIDERARRIVED case 20: //配送中 riderInfo.LogisticsStatus = 20 riderInfo.OpCode = tiktok_api.TiktokLogisticsRIDERPICKUP case 110: // 完成 riderInfo.LogisticsStatus = 40 riderInfo.OpCode = tiktok_api.TiktokLogisticsDELIVERED case 105: // 完成 riderInfo.LogisticsStatus = 40 riderInfo.OpCode = tiktok_api.TiktokLogisticsDELIVERED case 115: // 取消 riderInfo.LogisticsStatus = 100 riderInfo.OpCode = tiktok_api.TiktokLogisticsCANCELDELIVERY case 22, 0, 120: // 异常配送 riderInfo.LogisticsStatus = 22 riderInfo.OpCode = tiktok_api.TiktokLogisticsINDDELIVERYEXCEPTION } if riderInfo.CourierPhone == "" { riderInfo.CourierPhone = " 暂无电话 " } if riderInfo.CourierName == "" { riderInfo.CourierName = " 暂无骑手 " } if riderInfo.LogisticsStatus != 22 && riderInfo.LogisticsStatus != 120 && riderInfo.LogisticsStatus != 0 { riderInfo.LogisticsContext = fmt.Sprintf(riderInfo.LogisticsContext, riderInfo.CourierName, riderInfo.CourierPhone) } // 呼叫骑手的时候推送发货 // 抖店由于发配送时运单id已经固定了,我们系统在重新发货,或者运单号发生改变时去推送信息时.抖店只识别第一个运单号所以在这儿修改成发单时的第一个运单号! paramsMap := utils.Struct2Map(riderInfo, "", true) if handler := partner.GetPurchaseOrderHandlerFromVendorID(model.VendorIDDD); handler != nil { if err := handler.GetOrderRider("", "", paramsMap); err != nil { globals.SugarLogger.Errorf("PullTiktokRiderInfo Err %s", err.Error()) } } } //将以过期订单状态为配送中的订单修改为完成状态 func UpdateOrder2Complete() { sql := `UPDATE goods_order g SET g.status=110 WHERE g.status=20 AND g.order_created_at < ?` sqlParams := []interface{}{ time.Now().AddDate(0, 1, 0), } if num, err := dao.ExecuteSQL(dao.GetDB(), sql, sqlParams); err != nil { globals.SugarLogger.Debug("Update Order Status 20 To 110 Time,Count", time.Now(), num) } return } // UpdateFakeWayBillToTiktok 轮询更新假订单到抖音 func UpdateFakeWayBillToTiktok() { scheduleTimer, _ := rand.Int(rand.Reader, big.NewInt(1000)) randTimeSchedule := scheduleTimer.Int64() if randTimeSchedule > 200 { return } fakeWayBill, err := dao.GetWayBillFakeOrder() if err != nil { globals.SugarLogger.Debugf("Get Fake Order Err : %s", err.Error()) return } if len(fakeWayBill) == 0 { return } for i := 0; i < len(fakeWayBill); i++ { // 判断当前订单是否可以推送,UpdatedAt > 当前时间 就跳过 if fakeWayBill[i].StatusTime.After(time.Now()) { continue } riderInfo := &mtpsapi.RiderInfo{ OrderId: fakeWayBill[i].VendorOrderID, ThirdCarrierOrderId: fakeWayBill[i].VendorOrderID, CourierName: fakeWayBill[i].CourierName, CourierPhone: fakeWayBill[i].CourierMobile, LogisticsProviderCode: "10002", LogisticsStatus: fakeWayBill[i].Status, } switch fakeWayBill[i].Status { case 5: // 呼叫骑手 riderInfo.LogisticsContext = "呼叫骑手,新建运单" riderInfo.LogisticsStatus = 0 riderInfo.CourierName = "" riderInfo.CourierPhone = "" riderInfo.OpCode = tiktok_api.TiktokLogisticsStatusCALLRIDER // 下一状态以及推送时间 fakeWayBill[i].Status = model.WaybillStatusCourierAssigned fakeWayBill[i].VendorStatus = utils.Int64ToStr(model.WaybillStatusCourierAssigned) case 12: // 骑手接单 riderInfo.LogisticsContext = model.RiderWaitGetGoods riderInfo.LogisticsStatus = 12 riderInfo.OpCode = tiktok_api.TiktokLogisticsORDERRECEIVED // 下一状态以及推送时间 fakeWayBill[i].Status = model.WaybillStatusCourierArrived fakeWayBill[i].VendorStatus = utils.Int64ToStr(model.WaybillStatusCourierArrived) case 15: // 到店 riderInfo.LogisticsContext = model.RiderToStore riderInfo.LogisticsStatus = 15 riderInfo.OpCode = tiktok_api.TiktokLogisticsRIDERARRIVED // 下一状态以及推送时间 fakeWayBill[i].Status = model.WaybillStatusDelivering fakeWayBill[i].VendorStatus = utils.Int64ToStr(model.WaybillStatusDelivering) case 20: //配送中 riderInfo.LogisticsContext = model.RiderGetOrderDelivering riderInfo.LogisticsStatus = 20 riderInfo.OpCode = tiktok_api.TiktokLogisticsRIDERPICKUP // 下一状态以及推送时间 fakeWayBill[i].Status = model.WaybillStatusDelivered fakeWayBill[i].VendorStatus = utils.Int64ToStr(model.WaybillStatusDelivered) case 105: // 完成 riderInfo.LogisticsContext = model.RiderGetOrderDelivered riderInfo.LogisticsStatus = 40 riderInfo.OpCode = tiktok_api.TiktokLogisticsDELIVERED // 下一状态以及推送时间 fakeWayBill[i].Status = model.WaybillStatusFailed fakeWayBill[i].VendorStatus = utils.Int64ToStr(model.WaybillStatusFailed) default: continue } if riderInfo.LogisticsContext != model.RiderGetOrderDeliverFailed && riderInfo.LogisticsContext != model.RiderGetOrderDeliverOther && riderInfo.LogisticsContext != model.RiderWaitRider { riderInfo.LogisticsContext = fmt.Sprintf(riderInfo.LogisticsContext, riderInfo.CourierName, riderInfo.CourierPhone) } // 推送骑手信息 paramsMap := utils.Struct2Map(riderInfo, "", true) if handler := partner.GetPurchaseOrderHandlerFromVendorID(model.VendorIDDD); handler != nil { if err := handler.GetOrderRider(fakeWayBill[i].VendorOrgCode, "", paramsMap); err != nil { globals.SugarLogger.Errorf("Fake Pull Rider Info Err :%s--%s--%v", riderInfo.OrderId, riderInfo.ThirdCarrierOrderId, err) continue } } randNumber, _ := rand.Int(rand.Reader, big.NewInt(640)) randTime := randNumber.Int64() if randTime < 66 { randTime += 60 } fakeWayBill[i].StatusTime = time.Now().Add(time.Duration(randTime) * time.Second).Local() fakeWayBill[i].WaybillFinishedAt = time.Now() // 更新假运单 if _, err := dao.UpdateEntity(dao.GetDB(), fakeWayBill[i], "Status", "VendorStatus", "StatusTime", "WaybillFinishedAt"); err != nil { globals.SugarLogger.Errorf("Update Fake Way Bill Err:%s--%s--%v", riderInfo.OrderId, riderInfo.ThirdCarrierOrderId, err) } // 更新运单为完成状态 if fakeWayBill[i].Status == model.WaybillStatusDelivered { sql := `UPDATE goods_order g SET g.status = ?,g.vendor_status = ?,g.order_finished_at = ? WHERE g.vendor_order_id = ? ` _, err := dao.ExecuteSQL(dao.GetDB(), sql, []interface{}{model.OrderStatusFinished, model.OrderStatusFinished, time.Now(), fakeWayBill[i].VendorOrderID}...) if err != nil { globals.SugarLogger.Debugf("UPDATA goods_order Err :%s", err.Error()) } } } }