diff --git a/bff/internal/request/user.go b/bff/internal/request/user.go index 7f1892e..a49a48a 100644 --- a/bff/internal/request/user.go +++ b/bff/internal/request/user.go @@ -1,7 +1,6 @@ package request import ( - "bytes" "context" "io" "lone-services/pkg/utils" @@ -17,24 +16,22 @@ import ( type ctxKey string const ( - CtxUserId ctxKey = "X-User-Id" - CtxUserName ctxKey = "X-User-Name" - CtxRefresh ctxKey = "X-Refresh" - CtxClientIP ctxKey = "X-Client-Ip" - CtxUserAgent ctxKey = "X-User-Agent" - CtxClientCode ctxKey = "X-Client-Code" - CtxSaleId ctxKey = "X-Sale-Id" - CtxSaleName ctxKey = "X-Sale-Name" - CtxSaleMobile ctxKey = "X-Sale-Mobile" - CtxSaleProvince ctxKey = "X-Sale-Province" - CtxStoreId ctxKey = "X-Store-Id" - CtxStoreName ctxKey = "X-Store-Name" - CtxGroupId ctxKey = "X-Group-Id" - CtxGroupName ctxKey = "X-Group-Name" - CtxUserType ctxKey = "X-User-Type" - CtxCallbackRawBody ctxKey = "callback_raw_body" - CtxCallbackHeaders ctxKey = "callback_headers" - CtxCallbackErr ctxKey = "callback_read_err" + CtxUserId ctxKey = "X-User-Id" + CtxUserName ctxKey = "X-User-Name" + CtxRefresh ctxKey = "X-Refresh" + CtxClientIP ctxKey = "X-Client-Ip" + CtxUserAgent ctxKey = "X-User-Agent" + CtxClientCode ctxKey = "X-Client-Code" + CtxSaleId ctxKey = "X-Sale-Id" + CtxSaleName ctxKey = "X-Sale-Name" + CtxSaleMobile ctxKey = "X-Sale-Mobile" + CtxSaleProvince ctxKey = "X-Sale-Province" + CtxStoreId ctxKey = "X-Store-Id" + CtxStoreName ctxKey = "X-Store-Name" + CtxGroupId ctxKey = "X-Group-Id" + CtxGroupName ctxKey = "X-Group-Name" + CtxUserType ctxKey = "X-User-Type" + CtxRawBody ctxKey = "X-Raw-Body" ) var callbackPrefixes = []string{ @@ -60,6 +57,7 @@ type UserInfo struct { StoreName string GroupId string GroupName string + RawBody string Valid bool } @@ -79,6 +77,7 @@ func GetUserInfo(ctx context.Context) UserInfo { storeName, _ := ctx.Value(CtxStoreName).(string) groupId, _ := ctx.Value(CtxGroupId).(string) groupName, _ := ctx.Value(CtxGroupName).(string) + rawBody, _ := ctx.Value(CtxRawBody).(string) info := UserInfo{ RawUID: rawUID, @@ -96,6 +95,7 @@ func GetUserInfo(ctx context.Context) UserInfo { StoreName: storeName, GroupId: groupId, GroupName: groupName, + RawBody: rawBody, } if rawUID == "" { return info @@ -122,29 +122,17 @@ func getRealClientIP(r *http.Request) string { return r.RemoteAddr } +// UserReadMiddleware +/** 增加透传的方法 + * 1、这里加上代码 + * 2、UserClientInterceptor这个方法里也要写相应的代码对可以 + */ func UserReadMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - newCtx := r.Context() - if isCallbackPath(r.URL.Path) { - body, err := io.ReadAll(r.Body) - if err != nil { - newCtx = context.WithValue(newCtx, CtxCallbackRawBody, []byte(nil)) - newCtx = context.WithValue(newCtx, CtxCallbackHeaders, http.Header(nil)) - newCtx = context.WithValue(newCtx, CtxCallbackErr, err) - } else { - r.Body = io.NopCloser(bytes.NewBuffer(body)) - header := make(http.Header) - for k, vv := range r.Header { - header[k] = vv - } - newCtx = context.WithValue(newCtx, CtxCallbackRawBody, body) - newCtx = context.WithValue(newCtx, CtxCallbackHeaders, header) - newCtx = context.WithValue(newCtx, CtxCallbackErr, error(nil)) - } - next(w, r.WithContext(newCtx)) - return - } + newCtx := r.Context() + body, _ := io.ReadAll(r.Body) + newCtx = context.WithValue(newCtx, CtxRawBody, string(body)) newCtx = context.WithValue(newCtx, CtxUserId, r.Header.Get("X-User-Id")) newCtx = context.WithValue(newCtx, CtxUserName, r.Header.Get("X-User-Name")) newCtx = context.WithValue(newCtx, CtxRefresh, r.Header.Get("X-Refresh")) @@ -160,7 +148,6 @@ func UserReadMiddleware(next http.HandlerFunc) http.HandlerFunc { newCtx = context.WithValue(newCtx, CtxStoreName, r.Header.Get("X-Store-Name")) newCtx = context.WithValue(newCtx, CtxGroupId, r.Header.Get("X-Group-Id")) newCtx = context.WithValue(newCtx, CtxGroupName, r.Header.Get("X-Group-Name")) - next(w, r.WithContext(newCtx)) } } @@ -189,6 +176,7 @@ func UserClientInterceptor(ctx context.Context, method string, req, reply any, c md.Set("x-user-name", url.QueryEscape(user.Name)) } + setMDIfNotEmpty(md, "x-raw-body", user.RawBody) setMDIfNotEmpty(md, "x-refresh", user.Refresh) setMDIfNotEmpty(md, "x-client-ip", user.ClientIP) if user.UserAgent != utils.StringEmpty { diff --git a/bff/internal/response/middleware.go b/bff/internal/response/middleware.go index 464f6e0..57bff72 100644 --- a/bff/internal/response/middleware.go +++ b/bff/internal/response/middleware.go @@ -2,6 +2,7 @@ package response import ( "bytes" + "lone-services/pkg/utils" "net/http" "strings" @@ -16,6 +17,11 @@ type bodyWriter struct { buf bytes.Buffer } +type responseDataBack struct { + ReturnCode string `json:"returnCode"` + ReturnMsg string `json:"returnMsg"` +} + type responseData struct { Code int32 `json:"code"` Data any `json:"data"` @@ -48,7 +54,21 @@ func Wrap(next http.HandlerFunc) http.HandlerFunc { return } } - ctrl.OutPut(w, data.Code, unwrapJSONData(data.Data), data.Msg) + if data.Code < utils.NumberOne { + var back responseDataBack + + if err := jsoniter.Unmarshal(raw, &back); err != nil { + ctrl.Fail(w) + return + } + if len(back.ReturnCode) < utils.NumberOne { + ctrl.Fail(w) + return + } + ctrl.OutPutBack(w, back) + } else { + ctrl.OutPut(w, data.Code, unwrapJSONData(data.Data), data.Msg) + } } } diff --git a/bff/internal/response/response.go b/bff/internal/response/response.go index f1ad1be..11b600c 100644 --- a/bff/internal/response/response.go +++ b/bff/internal/response/response.go @@ -53,3 +53,10 @@ func (b *BaseController) OutPut(w http.ResponseWriter, code int32, data any, msg w.WriteHeader(http.StatusOK) _ = jsoniter.NewEncoder(w).Encode(out) } + +func (b *BaseController) OutPutBack(w http.ResponseWriter, back responseDataBack) { + + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(http.StatusOK) + _ = jsoniter.NewEncoder(w).Encode(back) +} diff --git a/pkg/utils/loginInfo.go b/pkg/utils/loginInfo.go index d66e725..492cee5 100644 --- a/pkg/utils/loginInfo.go +++ b/pkg/utils/loginInfo.go @@ -2,7 +2,6 @@ package utils import ( "context" - "net/http" "net/url" "strconv" @@ -10,12 +9,6 @@ import ( "google.golang.org/grpc/metadata" ) -const ( - CtxCallbackRawBody string = "callback_raw_body" - CtxCallbackHeaders string = "callback_headers" - CtxCallbackErr string = "callback_read_err" -) - type UserInfo struct { ID int64 Name string @@ -38,11 +31,6 @@ type UserInfo struct { Valid bool } -type HeaderAndBody struct { - Header http.Header - Body []byte -} - func firstMD(md metadata.MD, keys ...string) string { for _, key := range keys { vals := md.Get(key) @@ -122,13 +110,11 @@ func GetUserFromCtx(ctx context.Context) UserInfo { return userInfo } -// GetHeaderAndBody 只从ctx拿数据,不写http响应,Err交给handler处理 -func GetHeaderAndBody(ctx context.Context) HeaderAndBody { - rawBody, _ := ctx.Value(CtxCallbackRawBody).([]byte) - headers, _ := ctx.Value(CtxCallbackHeaders).(http.Header) - - return HeaderAndBody{ - Header: headers, - Body: rawBody, +// GetBody 只从ctx拿数据,不写http响应,Err交给handler处理 +func GetBody(ctx context.Context) string { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return StringEmpty } + return firstMD(md, "x-raw-body") } diff --git a/pkg/utils/tools.go b/pkg/utils/tools.go index 0acd02a..821e373 100644 --- a/pkg/utils/tools.go +++ b/pkg/utils/tools.go @@ -14,6 +14,7 @@ import ( "time" jsoniter "github.com/json-iterator/go" + "github.com/zeromicro/go-zero/core/logx" "github.com/gin-gonic/gin" "github.com/xuri/excelize/v2" @@ -245,7 +246,7 @@ func RoundMoney(amount float64) float64 { func Decrypt(str string) (string, Error) { str, err := Crypto{}.AESDecryptECB(str) if err != nil { - Logger.Error("decrypt str error", str, err) + logx.Error("decrypt str error", str, err) return str, err } @@ -259,7 +260,7 @@ func DecryptMobile(mobile string) string { mobile, err := Decrypt(mobile) if err != nil { - Logger.Error("decrypt mobile error", mobile, err) + logx.Error("decrypt mobile error", mobile, err) return mobile } @@ -488,12 +489,12 @@ func Unique(s []string) []string { func MapToStruct(data map[string]interface{}, target interface{}) error { jsonData, err := jsoniter.Marshal(data) // 将 map 转换为 JSON 字节切片 if err != nil { - Logger.Error("Error marshalling map to JSON:", err) + logx.Error("Error marshalling map to JSON:", err) return err } err = jsoniter.Unmarshal(jsonData, &target) // 将 JSON 字节切片解析到结构体中 if err != nil { - Logger.Error("Error unmarshalling JSON:", err) + logx.Error("Error unmarshalling JSON:", err) return err } @@ -503,14 +504,14 @@ func MapToStruct(data map[string]interface{}, target interface{}) error { func JsonStringToStruct(jsonStr string, v interface{}) bool { // 1. 校验入参:确保v是指针类型(否则json.Unmarshal无法工作) if v == nil { - Logger.Error("传入的结构体指针不能为nil") + logx.Error("传入的结构体指针不能为nil") return false } // 2. 将JSON字符串转为字节数组,执行解析 err := jsoniter.Unmarshal([]byte(jsonStr), v) if err != nil { - Logger.Error("JSON解析失败: ", err, jsonStr) + logx.Error("JSON解析失败: ", err, jsonStr) return false } diff --git a/rpc/express/express.pb b/rpc/express/express.pb index 6ba1f7f..8b5282a 100644 Binary files a/rpc/express/express.pb and b/rpc/express/express.pb differ diff --git a/rpc/express/express.proto b/rpc/express/express.proto index e3ec088..26e8713 100644 --- a/rpc/express/express.proto +++ b/rpc/express/express.proto @@ -14,7 +14,6 @@ message Response { message SfResponse { string return_code = 1; string return_msg = 2; - string return_status = 3; } message IdResponse { diff --git a/rpc/express/pb/express.pb.go b/rpc/express/pb/express.pb.go index fdcbc94..d05d559 100644 --- a/rpc/express/pb/express.pb.go +++ b/rpc/express/pb/express.pb.go @@ -86,7 +86,6 @@ type SfResponse struct { state protoimpl.MessageState `protogen:"open.v1"` ReturnCode string `protobuf:"bytes,1,opt,name=return_code,json=returnCode,proto3" json:"return_code,omitempty"` ReturnMsg string `protobuf:"bytes,2,opt,name=return_msg,json=returnMsg,proto3" json:"return_msg,omitempty"` - ReturnStatus string `protobuf:"bytes,3,opt,name=return_status,json=returnStatus,proto3" json:"return_status,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -135,13 +134,6 @@ func (x *SfResponse) GetReturnMsg() string { return "" } -func (x *SfResponse) GetReturnStatus() string { - if x != nil { - return x.ReturnStatus - } - return "" -} - type IdResponse struct { state protoimpl.MessageState `protogen:"open.v1"` Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` @@ -854,14 +846,13 @@ const file_express_express_proto_rawDesc = "" + "\bResponse\x12\x12\n" + "\x04code\x18\x01 \x01(\x05R\x04code\x12\x10\n" + "\x03msg\x18\x02 \x01(\tR\x03msg\x12\x12\n" + - "\x04data\x18\x03 \x01(\tR\x04data\"q\n" + + "\x04data\x18\x03 \x01(\tR\x04data\"L\n" + "\n" + "SfResponse\x12\x1f\n" + "\vreturn_code\x18\x01 \x01(\tR\n" + "returnCode\x12\x1d\n" + "\n" + - "return_msg\x18\x02 \x01(\tR\treturnMsg\x12#\n" + - "\rreturn_status\x18\x03 \x01(\tR\freturnStatus\"\x1c\n" + + "return_msg\x18\x02 \x01(\tR\treturnMsg\"\x1c\n" + "\n" + "IdResponse\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\"\x0e\n" + diff --git a/services/express/internal/logic/expressSfBackLogic.go b/services/express/internal/logic/expressSfBackLogic.go index e9855bb..f51474f 100644 --- a/services/express/internal/logic/expressSfBackLogic.go +++ b/services/express/internal/logic/expressSfBackLogic.go @@ -2,10 +2,15 @@ package logic import ( "context" + "lone-services/pkg/modelbase" "lone-services/pkg/utils" - "lone-services/rpc/express/pb" + order "lone-services/rpc/order/pb" + "lone-services/services/express/internal/dao" + "lone-services/services/express/internal/model" "lone-services/services/express/internal/svc" + "lone-services/services/express/internal/transit" + "strconv" "github.com/zeromicro/go-zero/core/logx" ) @@ -26,7 +31,181 @@ func NewExpressSfBackLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Exp } func (l *ExpressSfBackLogic) ExpressSfBack(in *express.EmtpyRequest) (*express.SfResponse, error) { - info := utils.GetHeaderAndBody(l.ctx) - l.Logger.Error("ExpressSfBack", "info", string(info.Body)) - return &express.SfResponse{}, nil + body := utils.GetBody(l.ctx) + ret := express.SfResponse{ + ReturnCode: "1000", + ReturnMsg: "系统异常", + } + if body == utils.StringEmpty { + return &ret, nil + } + l.Logger.Info("SF back data:", body) + + ok := l.Back(body) + if ok { + ret.ReturnCode = "000" + ret.ReturnMsg = "成功" + } + + return &ret, nil +} + +func (l *ExpressSfBackLogic) Back(body string) bool { + var result map[string]interface{} + ok := utils.JsonStringToStruct(body, &result) + if !ok { + return false + } + + bodyData, ok := result["Body"].(map[string]interface{}) + if !ok { + l.Logger.Error("back Body interface error ") + return false + } + waybillRoute, ok := bodyData["WaybillRoute"].([]interface{}) + if !ok || len(waybillRoute) < utils.NumberOne { + l.Logger.Error("back body WaybillRoute error empty") + return false + } + items := make(map[string][]dao.ExpressQueryItems) + var orderIds []string + end := make(map[string]bool) + + for i := utils.NumberZero; i < len(waybillRoute); i++ { + route := waybillRoute[i].(map[string]interface{}) + if _, ok := route["orderid"].(string); !ok { + l.Logger.Error("back body WaybillRoute error empty") + continue + } + orderId := route["orderid"].(string) + orderIds = append(orderIds, orderId) + tmp := dao.ExpressQueryItems{ + AcceptAddress: route["acceptAddress"].(string), + AcceptTime: route["acceptTime"].(string), + OpCode: route["opCode"].(string), + Remark: route["remark"].(string), + } + tmp.LastMd5 = utils.MD5Encrypt(tmp.OpCode + tmp.AcceptTime + tmp.Remark) + if _, okk := route["secondaryStatusCode"]; okk { + tmp.SecondaryStatusCode = route["secondaryStatusCode"].(string) + } + if _, okk := route["secondaryStatusName"]; okk { + tmp.SecondaryStatusName = route["secondaryStatusName"].(string) + } + if _, okk := route["firstStatusCode"]; okk { + tmp.FirstStatusCode = route["firstStatusCode"].(string) + } + if _, okk := route["firstStatusName"]; okk { + tmp.FirstStatusName = route["firstStatusName"].(string) + } + + items[orderId] = append(items[orderId], tmp) + end[orderId] = false + if ok := transit.SfSingedCodeMap[tmp.OpCode]; ok { + end[orderId] = true + } + } + if len(orderIds) < utils.NumberOne { + l.Logger.Error("no ", orderIds) + return false + } + orderIds = utils.UniqueStr(orderIds) + + modelObj := model.DeliveryOrderModel{}.Init() + + w := modelbase.Params{In: map[string][]string{ + "order_sn": orderIds, + }} + var info []dao.DeliveryOrderUpTransit + err := modelObj.Items(w, &info) + if err != nil { + utils.Logger.Error("get deliverGoods error ", err) + return false + } + if len(info) < utils.NumberOne { + return false + } + modelObj.Begin() + + for _, item := range info { + if item.Status == dao.SendStatusOver { + continue + } + if end[item.OrderSn] { + item.Status = dao.SendStatusOver + item.ChangeEstimatedTime = utils.StatusFail + + w = modelbase.Params{Eq: map[string]string{"delivery_order_id": strconv.Itoa(item.Id)}} + expEdit := dao.DeliveryExpStatus{ + Status: utils.StatusOk, + } + _, err = model.DeliveryOrderExpModel{}.Init().Edit(w, &expEdit) + if err != nil { + l.Logger.Error("back set deliver exp error ", err) + modelObj.Rollback() + return false + } + } + + if v, iOk := items[item.OrderSn]; iOk { + var old []dao.ExpressQueryItems + if utils.JsonStringToStruct(item.TransitQuery, &old) { + l.Logger.Error("back set deliver transit error: ", item.TransitQuery) + } + oldMap := l.getSfMap(old) + for i := len(v) - 1; i >= utils.NumberZero; i-- { + if cOk := oldMap[v[i].LastMd5]; !cOk { + old = append(old, v[i]) + } + } + item.TransitQuery = utils.StructToJson(old) + w := modelbase.Params{Eq: map[string]string{"id": strconv.Itoa(item.Id)}} + if end[item.OrderSn] { + item.SignTime = utils.Now() + } + _, err = modelObj.Edit(w, &item) + if err != nil { + l.Logger.Error("back set deliver info error ", err) + modelObj.Rollback() + return false + } + } + + if end[item.OrderSn] { + if item.Type == dao.DeliveryTypeOrder { + cli, err := svc.GetRpcClient(l.svcCtx.OrderSvcName) + if err != nil { + modelObj.Rollback() + logx.Errorf("get order err: %v", err) + return false + } + + client := order.NewOrderClient(cli.Conn()) + update := order.UpdateOrderDeliverStatusRequest{ + Id: item.ObjId, + DeliverStatus: int32(item.Status), + SignTime: utils.Now().GoString(), + } + _, err = client.UpdateOrderDeliverStatus(l.ctx, &update) + if err != nil { + modelObj.Rollback() + logx.Errorf("get order err: %v", err) + return false + } + } + } + + } + modelObj.Commit() + + return true + +} + +func (l *ExpressSfBackLogic) getSfMap(items []dao.ExpressQueryItems) map[string]bool { + ret := make(map[string]bool) + for _, item := range items { + ret[item.LastMd5] = true + } + return ret }