14 Commits

Author SHA1 Message Date
吕翠丽
36664d298e feature/ip优化 2025-06-17 17:05:22 +08:00
吕翠丽
0bbbfa3c1e feature/ip优化 2025-06-17 17:03:31 +08:00
吕翠丽
169996cc8a feature/ip优化 2025-06-17 16:57:42 +08:00
吕翠丽
6d3891390f feature/ip优化 2025-06-17 16:50:28 +08:00
zhongqiang
5574b1ba4e Merge branch 'refs/heads/feature/对接新供应链-唯品尚' 2025-06-17 12:03:21 +08:00
zhongqiang
0b6b76c708 对接新供应链-唯品尚 2025-06-17 12:03:01 +08:00
zhongqiang
4c27cecde1 Merge branch 'refs/heads/feature/对接新供应链-唯品尚' 2025-06-04 11:00:37 +08:00
zhongqiang
1b97811c6a 对接新供应链-唯品尚 2025-06-04 11:00:10 +08:00
zhongqiang
2483d9c305 Merge branch 'refs/heads/feature/对接新供应链-唯品尚' 2025-05-29 17:45:13 +08:00
zhongqiang
e936dd6622 对接新供应链-唯品尚 2025-05-29 17:45:03 +08:00
zhongqiang
3e765809e1 Merge branch 'refs/heads/feature/对接新供应链-唯品尚' 2025-05-29 17:30:44 +08:00
zhongqiang
ecfa733a9b 对接新供应链-唯品尚 2025-05-29 17:30:36 +08:00
zhongqiang
448d47d0cb Merge branch 'refs/heads/feature/对接新供应链-唯品尚' 2025-05-29 17:20:42 +08:00
zhongqiang
fa3ae27283 对接新供应链-唯品尚 2025-05-29 17:20:36 +08:00
9 changed files with 297 additions and 24 deletions

3
go.mod
View File

@@ -5,8 +5,11 @@ go 1.18.0
require github.com/pkg/errors v0.9.1
require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/redis/go-redis/v9 v9.10.0 // indirect
github.com/stretchr/testify v1.10.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

6
go.sum
View File

@@ -1,9 +1,15 @@
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.10.0 h1:FxwK3eV8p/CQa0Ch276C7u2d0eNC9kCmAYQ7mCXCzVs=
github.com/redis/go-redis/v9 v9.10.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -1,6 +1,7 @@
package ip_tool
import (
"context"
"encoding/json"
"fmt"
"io"
@@ -15,12 +16,14 @@ import (
type HuaChenIpClient struct {
AppCode string
Host string
cache ICacheAdapter
}
func NewHuaChenIpClient(appCode string) *HuaChenIpClient {
func NewHuaChenIpClient(appCode string, cache ICacheAdapter) *HuaChenIpClient {
return &HuaChenIpClient{
AppCode: appCode,
Host: "https://c2ba.api.huachen.cn",
cache: cache,
}
}
@@ -87,6 +90,37 @@ func (h *HuaChenIpClient) GetIpInfo(ip string) (res *ApiResult, err error) {
return &apiResult, nil
}
func (h *HuaChenIpClient) GetIpInfoFormCache(ctx context.Context, ip string, ttl time.Duration) (res *ApiResult, err error) {
getCache, err := h.cache.Get(ctx, h.ipKey(ip))
if err != nil {
return nil, errors.Wrapf(err, "获取缓存失败ip:%s", ip)
}
if getCache != nil {
return getCache, nil
}
res, err = h.GetIpInfo(ip)
if err != nil {
return nil, errors.Wrapf(err, "获取ip:%s信息失败", ip)
}
var infoJson []byte
infoJson, err = json.Marshal(res)
if err != nil {
return nil, errors.Wrapf(err, "无法将IP信息转换为JSONip:%s", ip)
}
err = h.cache.Set(ctx, h.ipKey(ip), string(infoJson), ttl)
if err != nil {
return nil, errors.Wrapf(err, "缓存ip:%s信息失败", ip)
}
return
}
// ipKey 生成Redis key
func (h *HuaChenIpClient) ipKey(ip string) string {
return fmt.Sprintf("ip:%s", ip)
}
type ApiResult struct {
Ret int `json:"ret"`
Msg string `json:"msg"`

View File

@@ -1,8 +1,14 @@
package ip_tool
import (
"context"
"encoding/json"
"fmt"
"github.com/pkg/errors"
"github.com/redis/go-redis/v9"
"log"
"testing"
"time"
)
func TestHuaChenIpClient_GetIpInfo(t *testing.T) {
@@ -42,3 +48,73 @@ func TestHuaChenIpClient_GetIpInfo(t *testing.T) {
})
}
}
func TestHuaChenIpClient_GetIpInfo1(t *testing.T) {
rdb := redis.NewClient(&redis.Options{
Addr: "",
Password: "",
DB: 1,
})
// 创建IP缓存实例
ipCache := NewRedisCache(rdb)
h := &HuaChenIpClient{
AppCode: "",
Host: "https://c2ba.api.huachen.cn",
cache: ipCache,
}
gotRes, err := h.GetIpInfoFormCache(context.Background(), "8.138.116.112")
log.Println(gotRes, err)
}
type RedisCache struct {
client *redis.Client
}
func NewRedisCache(client *redis.Client) *RedisCache {
return &RedisCache{client: client}
}
func (r *RedisCache) Set(ctx context.Context, ip string, info string, ttl time.Duration) error {
if ip == "" {
return errors.New("ip不能为空")
}
return r.client.Set(ctx, ip, info, ttl).Err()
}
// Get 从Redis获取IP信息
func (r *RedisCache) Get(ctx context.Context, ip string) (*ApiResult, error) {
if ip == "" {
return nil, errors.New("ip不能为空")
}
data, err := r.client.Get(ctx, ip).Bytes()
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, nil // 键不存在返回nil而不是错误
}
return nil, fmt.Errorf("无法获取IP信息: %w", err)
}
var info ApiResult
if err = json.Unmarshal(data, &info); err != nil {
return nil, fmt.Errorf("无法解析IP信息: %w", err)
}
return &info, nil
}
// Exists 检查IP是否存在缓存中
func (r *RedisCache) Exists(ctx context.Context, ip string) (bool, error) {
if ip == "" {
return false, errors.New("ip不能为空")
}
exists, err := r.client.Exists(ctx, ip).Result()
if err != nil {
return false, fmt.Errorf("无法检查IP是否存在: %w", err)
}
return exists > 0, nil
}

13
ip_tool/ip_cache.go Normal file
View File

@@ -0,0 +1,13 @@
package ip_tool
import (
"context"
"time"
)
// Cache 定义缓存接口,遵循接口隔离原则
type ICacheAdapter interface {
Set(ctx context.Context, ip string, info string, ttl time.Duration) error
Get(ctx context.Context, ip string) (*ApiResult, error)
Exists(ctx context.Context, ip string) (bool, error)
}

View File

@@ -1,7 +1,7 @@
package weipinshang_api
type CreateAfsApplyReq struct {
McOrderNo int `json:"mcOrderNo"` // 子订单号 是 int 下单时候返回子订单号 20190704124955600363
McOrderNo string `json:"mcOrderNo"` // 子订单号 是 int 下单时候返回子订单号 20190704124955600363
CustomerExpect int `json:"customerExpect"` // 售后类型 是 int [退货(10)、仅退款(40)] 10
QuestionDesc string `json:"questionDesc"` // 原因描述 否 String [产品问题描述最多600字符] 看下面请求示例
QuestionPic string `json:"questionPic"` //问题描述图片 否 String [问题描述图片.最多2000字符] 支持多张图片,用逗号分隔(英文逗号)
@@ -46,6 +46,14 @@ type CreateOrderReq struct {
NoticeUrl string `json:"noticeUrl"` //合作方通知地址 noticeUrl 否 String 规定值 如支持,订单更新实时通知。此参数可不用传,统一走异步回调
}
type RefundDeliveryReq struct {
McOrderNo string `json:"mcOrderNo"` // 子订单号 是 int 下单时候返回子订单号 20190704124955600363
DeliveryName string `json:"deliveryName"` // 快递公司
DeliveryNo string `json:"deliveryNo"` // 快递单号
Freight string `json:"freight"` // 运费金额 freight 否 string 单位:元
FreightImg string `json:"freightImg"` // 运费支付凭证 freightImg 否 string 图片地址
}
// test ------------------------------------------------
type DeliverGoodsReq struct {

View File

@@ -69,6 +69,12 @@ type Data struct {
}
type GetOrderInfoByItemNORes struct {
Code int `json:"code"` // 0为成功其它为失败
Msg string `json:"msg"` // 请求接口消息
Data OrderInfoByItemNOData `json:"data"` // 返回数据 data array
}
type OrderInfoByItemNOData struct {
OrderItemNo string `json:"order_item_no"` // 子订单号
SendStatus string `json:"send_status"` //发货状态【CHECKED订单被创建,INSTOCK已备货,SENDED已发货,RECEIVED已收货
DeliveryName string `json:"delivery_name"` // 快递公司
@@ -119,6 +125,11 @@ type OrderCancelRes struct {
Msg string `json:"msg"` // 请求接口消息
}
type RefundDeliveryRes struct {
Code int `json:"code"` // 0为成功其它为失败
Msg string `json:"msg"` // 请求接口消息
}
// test -------------------------------------
type TestRes struct {

View File

@@ -5,6 +5,7 @@ import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@@ -143,11 +144,9 @@ func (w *WeiPinShangClient) GetOrderInfoByThirdNO(orderNo string) (res *GetOrder
func (w *WeiPinShangClient) GetOrderInfoByItemNO(mcOrderNo string) (res *GetOrderInfoByItemNORes, err error) {
fmt.Println("mcOrderNo", mcOrderNo)
//paramMap := make(map[string]any)
//paramMap["mcOrderNo"] = mcOrderNo
paramMap := map[string]any{
"mcOrderNo": mcOrderNo,
}
paramMap := make(map[string]any)
paramMap["mcOrderNo"] = mcOrderNo
postRes, err := w.WPSPost("mcang/Order/getOrderInfoByItemNO", paramMap)
if err != nil {
return
@@ -197,7 +196,7 @@ func (w *WeiPinShangClient) CreateAfsApply(createAfsApplyReq *CreateAfsApplyReq)
paramMap["pickwareCounty"] = createAfsApplyReq.PickwareCounty
paramMap["pickwareAddress"] = createAfsApplyReq.PickwareAddress
postRes, err := w.WPSPost("mcang/Refunds/IsRefund", paramMap)
postRes, err := w.WPSPost("mcang/Refunds/createAfsApply", paramMap)
if err != nil {
return
}
@@ -214,7 +213,7 @@ func (w *WeiPinShangClient) OrderCancel(mcOrderNo string) (res *OrderCancelRes,
fmt.Println("mcOrderNo", mcOrderNo)
paramMap := make(map[string]any)
paramMap["mcOrderNo"] = mcOrderNo
postRes, err := w.WPSPost("mcang/Refunds/IsRefund", paramMap)
postRes, err := w.WPSPost("mcang/Refunds/orderCancel", paramMap)
if err != nil {
return
}
@@ -227,6 +226,27 @@ func (w *WeiPinShangClient) OrderCancel(mcOrderNo string) (res *OrderCancelRes,
return
}
func (w *WeiPinShangClient) RefundDelivery(refundDeliveryReq RefundDeliveryReq) (res *RefundDeliveryRes, err error) {
fmt.Println("refundDeliveryReq", refundDeliveryReq)
paramMap := make(map[string]any)
paramMap["mcOrderNo"] = refundDeliveryReq.McOrderNo
paramMap["deliveryName"] = refundDeliveryReq.DeliveryName
paramMap["deliveryNo"] = refundDeliveryReq.DeliveryNo
paramMap["freight"] = refundDeliveryReq.Freight
paramMap["freightImg"] = refundDeliveryReq.FreightImg
postRes, err := w.WPSPost("mcang/Refunds/refundDelivery", paramMap)
if err != nil {
return
}
err = json.Unmarshal(postRes, &res)
if err != nil || res == nil {
err = fmt.Errorf("转换RefundDeliveryRes结构体失败: %s", string(postRes))
return
}
return
}
func (w *WeiPinShangClient) Sign(paramMap map[string]any) (res string, err error) {
var sumParamString string
if len(paramMap) != 0 {
@@ -278,7 +298,7 @@ func (w *WeiPinShangClient) WPSPost(url string, paramMap map[string]any) (res []
fmt.Printf("res: %s\n", string(res))
if !json.Valid(res) {
return nil, fmt.Errorf("响应不是有效的JSON格式: %s", string(res))
return nil, errors.New("响应不是有效的JSON格式")
}
return

View File

@@ -80,14 +80,14 @@ func TestWeiPinShangClient_PreOrder(t *testing.T) {
Key: "f654ea5bde7635c3f46191191e5c4c8e",
},
args: PreOrderReq{
GoodsInfo: "[{\"goodsId\":\"WPS9_282520\",\"goodSpecId\":\"WPS9_1221183858889276\",\"num\":2},{\"goodsId\":\"WPS2_0213160707208717\",\"goodSpecId\":\"WPS2_0213160707965791\",\"num\":2}]",
GoodsInfo: "[{\"goodsId\":\"WPS9_282520\",\"goodSpecId\":\"WPS9_1221183858889276\",\"num\":2}]",
Province: "广东省",
Address: "奥园",
City: "广州市",
Area: "番禺区",
ConsigneePhone: "15375390426",
ConsigneeContacts: "张三",
LockCode: "L0123456789",
LockCode: "L100000000",
Source: "AILEHUI",
},
},
@@ -135,8 +135,8 @@ func TestWeiPinShangClient_CreateOrder(t *testing.T) {
Key: "f654ea5bde7635c3f46191191e5c4c8e",
},
args: CreateOrderReq{
LockCode: "L0123456789",
OrderNo: "20000000000",
LockCode: "L100000000",
OrderNo: "30000000000",
},
},
}
@@ -233,7 +233,7 @@ func TestWeiPinShangClient_GetOrderInfoByItemNO(t *testing.T) {
},
args: args{
//mcOrderNo: "mc20250527174640537475",
mcOrderNo: "mc20250529102347907570",
mcOrderNo: "mc20250616115732440085",
},
},
}
@@ -292,7 +292,7 @@ func TestWeiPinShangClient_GetOrderInfoByThirdNO(t *testing.T) {
Key: "f654ea5bde7635c3f46191191e5c4c8e",
},
args: args{
orderNo: "20250527172503439229",
orderNo: "570872619444771455",
},
},
}
@@ -339,7 +339,7 @@ func TestWeiPinShangClient_IsRefund(t *testing.T) {
Key: "f654ea5bde7635c3f46191191e5c4c8e",
},
args: args{
mcOrderNo: "mc20250529102347907570",
mcOrderNo: "mc20250613182629112823",
},
},
}
@@ -362,6 +362,108 @@ func TestWeiPinShangClient_IsRefund(t *testing.T) {
}
}
func TestWeiPinShangClient_OrderCancel(t *testing.T) {
type fields struct {
Host string
ChannelType string
Key string
}
type args struct {
mcOrderNo string
}
tests := []struct {
name string
fields fields
args args
wantRes *IsRefundRes
wantErr bool
}{
{
name: "test1",
fields: fields{
Host: "https://uat.api.weipinshang.net/",
ChannelType: "AILEHUI",
Key: "f654ea5bde7635c3f46191191e5c4c8e",
},
args: args{
mcOrderNo: "mc20250529102347485667",
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
h := &WeiPinShangClient{
Host: test.fields.Host,
ChannelType: test.fields.ChannelType,
Key: test.fields.Key,
}
gotRes, err := h.OrderCancel(test.args.mcOrderNo)
log.Println(gotRes, err)
if (err != nil) != test.wantErr {
t.Errorf("GetManyPostage() error = %v, wantErr %v", err, test.wantErr)
}
})
}
}
func TestWeiPinShangClient_CreateAfsApply(t *testing.T) {
type fields struct {
Host string
ChannelType string
Key string
}
tests := []struct {
name string
fields fields
args CreateAfsApplyReq
wantRes *IsRefundRes
wantErr bool
}{
{
name: "test1",
fields: fields{
Host: "https://uat.api.weipinshang.net/",
ChannelType: "AILEHUI",
Key: "f654ea5bde7635c3f46191191e5c4c8e",
},
args: CreateAfsApplyReq{
CustomerContactName: "钟",
CustomerExpect: 10,
CustomerMobilePhone: "15375399426",
CustomerTel: "15375399426",
McOrderNo: "mc20250613182629112823",
PickwareAddress: "奥园",
PickwareCity: "广州",
PickwareCounty: "番禺",
PickwareProvince: "广东",
QuestionDesc: "商品问题",
QuestionPic: "11",
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
h := &WeiPinShangClient{
Host: test.fields.Host,
ChannelType: test.fields.ChannelType,
Key: test.fields.Key,
}
gotRes, err := h.CreateAfsApply(&test.args)
log.Println(gotRes, err)
if (err != nil) != test.wantErr {
t.Errorf("GetManyPostage() error = %v, wantErr %v", err, test.wantErr)
}
})
}
}
// test ---------------------------------------------------
func TestWeiPinShangClient_DeliverGoods(t *testing.T) {
@@ -386,7 +488,7 @@ func TestWeiPinShangClient_DeliverGoods(t *testing.T) {
Key: "f654ea5bde7635c3f46191191e5c4c8e",
},
args: DeliverGoodsReq{
COrderItemNo: "mc20250527172503957733",
COrderItemNo: "mc20250613182629112823",
CDeliveryName: "顺丰",
CDeliveryNo: "1234567890",
},
@@ -400,9 +502,9 @@ func TestWeiPinShangClient_DeliverGoods(t *testing.T) {
Key: "f654ea5bde7635c3f46191191e5c4c8e",
},
args: DeliverGoodsReq{
COrderItemNo: "mc20250527172503673418",
CDeliveryName: "京东",
CDeliveryNo: "1234567890",
COrderItemNo: "mc20250616113428587322",
CDeliveryName: "顺丰0",
CDeliveryNo: "SF9900000099",
},
},
}
@@ -446,7 +548,7 @@ func TestWeiPinShangClient_UpdateService(t *testing.T) {
Key: "f654ea5bde7635c3f46191191e5c4c8e",
},
args: UpdateServiceReq{
COrderItemNo: "20250527172503439229",
COrderItemNo: "mc20250612153935670660",
CType: "1",
},
},
@@ -459,8 +561,8 @@ func TestWeiPinShangClient_UpdateService(t *testing.T) {
Key: "f654ea5bde7635c3f46191191e5c4c8e",
},
args: UpdateServiceReq{
COrderItemNo: "10000000000",
CType: "2",
COrderItemNo: "mc20250609180246814560",
CType: "3",
},
},
}