正在显示
16 个修改的文件
包含
1211 行增加
和
103 行删除
| @@ -7,6 +7,7 @@ require ( | @@ -7,6 +7,7 @@ require ( | ||
| 7 | github.com/Shopify/sarama v1.23.1 | 7 | github.com/Shopify/sarama v1.23.1 |
| 8 | github.com/ajg/form v1.5.1 // indirect | 8 | github.com/ajg/form v1.5.1 // indirect |
| 9 | github.com/astaxie/beego v1.12.2 | 9 | github.com/astaxie/beego v1.12.2 |
| 10 | + github.com/beego/beego/v2 v2.0.1 | ||
| 10 | github.com/bsm/sarama-cluster v2.1.15+incompatible | 11 | github.com/bsm/sarama-cluster v2.1.15+incompatible |
| 11 | github.com/dgrijalva/jwt-go v3.2.0+incompatible | 12 | github.com/dgrijalva/jwt-go v3.2.0+incompatible |
| 12 | github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 // indirect | 13 | github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 // indirect |
| @@ -7,14 +7,25 @@ type ListOrderBaseQuery struct { | @@ -7,14 +7,25 @@ type ListOrderBaseQuery struct { | ||
| 7 | // 查询限制 | 7 | // 查询限制 |
| 8 | Limit int `json:"limit"` | 8 | Limit int `json:"limit"` |
| 9 | //发货单号 | 9 | //发货单号 |
| 10 | - PartnerOrCode string `json:"partnerOrCode"` | 10 | + //PartnerOrCode string `json:"partnerOrCode"` |
| 11 | + //合伙人姓名 | ||
| 12 | + PartnerName string `json:"partnerName"` | ||
| 13 | + //订单号 | ||
| 14 | + OrderCode string `json:"orderCode"` | ||
| 15 | + //发货单号 | ||
| 16 | + DeliveryCode string `json:"deliveryCode"` | ||
| 17 | + //公司id | ||
| 11 | CompanyId int64 `json:"companyId"` | 18 | CompanyId int64 `json:"companyId"` |
| 12 | //订单类型 | 19 | //订单类型 |
| 13 | OrderType int `json:"orderType"` | 20 | OrderType int `json:"orderType"` |
| 14 | //合伙人分类 | 21 | //合伙人分类 |
| 15 | PartnerCategory int `json:"partnerCategory"` | 22 | PartnerCategory int `json:"partnerCategory"` |
| 23 | + //更新时间开始 | ||
| 16 | UpdateTimeBegin string `json:"updateTimeBegin"` | 24 | UpdateTimeBegin string `json:"updateTimeBegin"` |
| 25 | + //更新时间截止 | ||
| 17 | UpdateTimeEnd string `json:"updateTimeEnd"` | 26 | UpdateTimeEnd string `json:"updateTimeEnd"` |
| 27 | + //创建时间开始 | ||
| 18 | CreateTimeBegin string `json:"createTimeBegin"` | 28 | CreateTimeBegin string `json:"createTimeBegin"` |
| 29 | + //创建时间截止 | ||
| 19 | CreateTimeEnd string `json:"createTimeEnd"` | 30 | CreateTimeEnd string `json:"createTimeEnd"` |
| 20 | } | 31 | } |
| @@ -26,7 +26,13 @@ func NewOrderInfoService(option map[string]interface{}) *OrderInfoService { | @@ -26,7 +26,13 @@ func NewOrderInfoService(option map[string]interface{}) *OrderInfoService { | ||
| 26 | return newAdminUserService | 26 | return newAdminUserService |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | -// PageListOrderBase 获取订单列表 | 29 | +/** |
| 30 | + * @Author SteveChan | ||
| 31 | + * @Description // 获取订单列表 | ||
| 32 | + * @Date 22:05 2021/1/10 | ||
| 33 | + * @Param | ||
| 34 | + * @return | ||
| 35 | + **/ | ||
| 30 | func (service OrderInfoService) PageListOrderBase(listOrderQuery query.ListOrderBaseQuery) ([]map[string]interface{}, int, error) { | 36 | func (service OrderInfoService) PageListOrderBase(listOrderQuery query.ListOrderBaseQuery) ([]map[string]interface{}, int, error) { |
| 31 | var err error | 37 | var err error |
| 32 | transactionContext, err := factory.CreateTransactionContext(nil) | 38 | transactionContext, err := factory.CreateTransactionContext(nil) |
| @@ -53,7 +59,9 @@ func (service OrderInfoService) PageListOrderBase(listOrderQuery query.ListOrder | @@ -53,7 +59,9 @@ func (service OrderInfoService) PageListOrderBase(listOrderQuery query.ListOrder | ||
| 53 | orders, cnt, err = orderDao.OrderListByCondition( | 59 | orders, cnt, err = orderDao.OrderListByCondition( |
| 54 | listOrderQuery.CompanyId, | 60 | listOrderQuery.CompanyId, |
| 55 | listOrderQuery.OrderType, | 61 | listOrderQuery.OrderType, |
| 56 | - listOrderQuery.PartnerOrCode, | 62 | + listOrderQuery.PartnerName, // 合伙人姓名 |
| 63 | + listOrderQuery.OrderCode, // 订单号 | ||
| 64 | + listOrderQuery.DeliveryCode, // 发货单号 | ||
| 57 | [2]string{listOrderQuery.UpdateTimeBegin, listOrderQuery.UpdateTimeEnd}, | 65 | [2]string{listOrderQuery.UpdateTimeBegin, listOrderQuery.UpdateTimeEnd}, |
| 58 | [2]string{listOrderQuery.CreateTimeBegin, listOrderQuery.CreateTimeEnd}, | 66 | [2]string{listOrderQuery.CreateTimeBegin, listOrderQuery.CreateTimeEnd}, |
| 59 | listOrderQuery.PartnerCategory, | 67 | listOrderQuery.PartnerCategory, |
| @@ -865,6 +873,13 @@ func (service OrderInfoService) ListOrderBonusForExcel(listOrderQuery query.List | @@ -865,6 +873,13 @@ func (service OrderInfoService) ListOrderBonusForExcel(listOrderQuery query.List | ||
| 865 | return resultMaps, column, nil | 873 | return resultMaps, column, nil |
| 866 | } | 874 | } |
| 867 | 875 | ||
| 876 | +/** | ||
| 877 | + * @Author SteveChan | ||
| 878 | + * @Description // 导出订单数据 | ||
| 879 | + * @Date 22:05 2021/1/10 | ||
| 880 | + * @Param | ||
| 881 | + * @return | ||
| 882 | + **/ | ||
| 868 | func (service OrderInfoService) ListOrderForExcel(listOrderQuery query.ListOrderBaseQuery) ([]map[string]string, [][2]string, error) { | 883 | func (service OrderInfoService) ListOrderForExcel(listOrderQuery query.ListOrderBaseQuery) ([]map[string]string, [][2]string, error) { |
| 869 | transactionContext, err := factory.CreateTransactionContext(nil) | 884 | transactionContext, err := factory.CreateTransactionContext(nil) |
| 870 | if err != nil { | 885 | if err != nil { |
| @@ -876,6 +891,7 @@ func (service OrderInfoService) ListOrderForExcel(listOrderQuery query.ListOrder | @@ -876,6 +891,7 @@ func (service OrderInfoService) ListOrderForExcel(listOrderQuery query.ListOrder | ||
| 876 | defer func() { | 891 | defer func() { |
| 877 | transactionContext.RollbackTransaction() | 892 | transactionContext.RollbackTransaction() |
| 878 | }() | 893 | }() |
| 894 | + | ||
| 879 | var ( | 895 | var ( |
| 880 | orderBaseDao *dao.OrderBaseDao | 896 | orderBaseDao *dao.OrderBaseDao |
| 881 | ) | 897 | ) |
| @@ -887,7 +903,9 @@ func (service OrderInfoService) ListOrderForExcel(listOrderQuery query.ListOrder | @@ -887,7 +903,9 @@ func (service OrderInfoService) ListOrderForExcel(listOrderQuery query.ListOrder | ||
| 887 | } | 903 | } |
| 888 | ordersData, err := orderBaseDao.OrderListForExcel( | 904 | ordersData, err := orderBaseDao.OrderListForExcel( |
| 889 | listOrderQuery.CompanyId, | 905 | listOrderQuery.CompanyId, |
| 890 | - listOrderQuery.PartnerOrCode, | 906 | + listOrderQuery.PartnerName, // 合伙人姓名 |
| 907 | + listOrderQuery.OrderCode, // 订单号 | ||
| 908 | + listOrderQuery.DeliveryCode, // 发货单号 | ||
| 891 | [2]string{listOrderQuery.UpdateTimeBegin, listOrderQuery.UpdateTimeEnd}, | 909 | [2]string{listOrderQuery.UpdateTimeBegin, listOrderQuery.UpdateTimeEnd}, |
| 892 | [2]string{listOrderQuery.CreateTimeBegin, listOrderQuery.CreateTimeEnd}, | 910 | [2]string{listOrderQuery.CreateTimeBegin, listOrderQuery.CreateTimeEnd}, |
| 893 | listOrderQuery.PartnerCategory, | 911 | listOrderQuery.PartnerCategory, |
| @@ -944,28 +962,29 @@ func (service OrderInfoService) ListOrderForExcel(listOrderQuery query.ListOrder | @@ -944,28 +962,29 @@ func (service OrderInfoService) ListOrderForExcel(listOrderQuery query.ListOrder | ||
| 944 | 962 | ||
| 945 | /** | 963 | /** |
| 946 | * @Author SteveChan | 964 | * @Author SteveChan |
| 947 | - * @Description // 批量导入创建订单 | 965 | + * @Description //TODO 批量导入创建订单 |
| 948 | * @Date 11:00 2021/1/7 | 966 | * @Date 11:00 2021/1/7 |
| 949 | * @Param | 967 | * @Param |
| 950 | * @return | 968 | * @return |
| 951 | **/ | 969 | **/ |
| 952 | -func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*command.CreateOrderCommand) ([]interface{}, error) { | 970 | +func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*command.CreateOrderCommand) ([]*domain.ImportInfo, error) { |
| 953 | // 事务初始化 | 971 | // 事务初始化 |
| 954 | var ( | 972 | var ( |
| 955 | transactionContext, _ = factory.CreateTransactionContext(nil) | 973 | transactionContext, _ = factory.CreateTransactionContext(nil) |
| 956 | err error | 974 | err error |
| 957 | - failureDataList []interface{} // 错误数据返回 | 975 | + errorDataList []*domain.ImportInfo // 错误数据返回 |
| 958 | ) | 976 | ) |
| 959 | 977 | ||
| 960 | // 循环校验命令 | 978 | // 循环校验命令 |
| 961 | for _, cmd := range createOrderCommands { | 979 | for _, cmd := range createOrderCommands { |
| 962 | if err = cmd.Valid(); err != nil { | 980 | if err = cmd.Valid(); err != nil { |
| 963 | // 返回信息 0: 订单号, 1: 发货单号, 2: 客户名称, 3: 订单区域, 4: 编号, 5: 合伙人, 6: 类型, 7: 业务抽成比例, 8: 产品名称, 9: 数量, 10: 单价, 11: 合伙人分红比例 | 981 | // 返回信息 0: 订单号, 1: 发货单号, 2: 客户名称, 3: 订单区域, 4: 编号, 5: 合伙人, 6: 类型, 7: 业务抽成比例, 8: 产品名称, 9: 数量, 10: 单价, 11: 合伙人分红比例 |
| 964 | - row := []interface{}{ | ||
| 965 | - lib.ThrowError(lib.BUSINESS_ERROR, err.Error()), // 错误信息 | ||
| 966 | - cmd.LineNumbers, // 错误影响的行 | 982 | + row := &domain.ImportInfo{ |
| 983 | + Error: lib.ThrowError(lib.BUSINESS_ERROR, err.Error()), // 错误信息 | ||
| 984 | + LineNumbers: cmd.LineNumbers, // 错误影响的行 | ||
| 985 | + GoodLine: map[int]interface{}{}, | ||
| 967 | } | 986 | } |
| 968 | - failureDataList = append(failureDataList, row) | 987 | + errorDataList = append(errorDataList, row) |
| 969 | continue | 988 | continue |
| 970 | } | 989 | } |
| 971 | } | 990 | } |
| @@ -987,6 +1006,7 @@ func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*co | @@ -987,6 +1006,7 @@ func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*co | ||
| 987 | categoryRepository domain.PartnerCategoryRepository | 1006 | categoryRepository domain.PartnerCategoryRepository |
| 988 | orderBaseDao *dao.OrderBaseDao | 1007 | orderBaseDao *dao.OrderBaseDao |
| 989 | ) | 1008 | ) |
| 1009 | + | ||
| 990 | // 合伙人信息仓储初始化 | 1010 | // 合伙人信息仓储初始化 |
| 991 | if PartnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{ | 1011 | if PartnerInfoRepository, err = factory.CreatePartnerInfoRepository(map[string]interface{}{ |
| 992 | "transactionContext": transactionContext, | 1012 | "transactionContext": transactionContext, |
| @@ -1028,26 +1048,55 @@ func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*co | @@ -1028,26 +1048,55 @@ func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*co | ||
| 1028 | var partnerData *domain.PartnerInfo | 1048 | var partnerData *domain.PartnerInfo |
| 1029 | partnerData, err = PartnerInfoRepository.FindOne(domain.PartnerFindOneQuery{UserId: cmd.PartnerId}) | 1049 | partnerData, err = PartnerInfoRepository.FindOne(domain.PartnerFindOneQuery{UserId: cmd.PartnerId}) |
| 1030 | if err != nil { | 1050 | if err != nil { |
| 1031 | - return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("检索合伙人数据失败")) | 1051 | + row := &domain.ImportInfo{ |
| 1052 | + Error: lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("检索合伙人数据失败")), | ||
| 1053 | + LineNumbers: cmd.LineNumbers, // 错误影响的行 | ||
| 1054 | + GoodLine: map[int]interface{}{}, | ||
| 1055 | + } | ||
| 1056 | + errorDataList = append(errorDataList, row) | ||
| 1057 | + continue | ||
| 1032 | } | 1058 | } |
| 1033 | 1059 | ||
| 1034 | // 批量校验订单 | 1060 | // 批量校验订单 |
| 1035 | if ok, err := orderBaseDao.CheckOrderExist(cmd.CompanyId, cmd.OrderCode, cmd.DeliveryCode, | 1061 | if ok, err := orderBaseDao.CheckOrderExist(cmd.CompanyId, cmd.OrderCode, cmd.DeliveryCode, |
| 1036 | cmd.PartnerCategory, cmd.PartnerId, 0); err != nil { | 1062 | cmd.PartnerCategory, cmd.PartnerId, 0); err != nil { |
| 1037 | - return nil, lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()) | 1063 | + row := &domain.ImportInfo{ |
| 1064 | + Error: lib.ThrowError(lib.TRANSACTION_ERROR, err.Error()), | ||
| 1065 | + LineNumbers: cmd.LineNumbers, // 错误影响的行 | ||
| 1066 | + GoodLine: map[int]interface{}{}, | ||
| 1067 | + } | ||
| 1068 | + errorDataList = append(errorDataList, row) | ||
| 1069 | + continue | ||
| 1038 | } else if ok { | 1070 | } else if ok { |
| 1039 | - return nil, lib.ThrowError(lib.BUSINESS_ERROR, "订单已存在") | 1071 | + row := &domain.ImportInfo{ |
| 1072 | + Error: lib.ThrowError(lib.BUSINESS_ERROR, "订单已存在"), | ||
| 1073 | + LineNumbers: cmd.LineNumbers, // 错误影响的行 | ||
| 1074 | + GoodLine: map[int]interface{}{}, | ||
| 1075 | + } | ||
| 1076 | + errorDataList = append(errorDataList, row) | ||
| 1077 | + continue | ||
| 1040 | } | 1078 | } |
| 1041 | 1079 | ||
| 1042 | // 批量校验产品 | 1080 | // 批量校验产品 |
| 1043 | var goodMap = map[string]int{} | 1081 | var goodMap = map[string]int{} |
| 1082 | + goodErrMap := make(map[int]interface{}, 0) | ||
| 1044 | for i := range cmd.Goods { | 1083 | for i := range cmd.Goods { |
| 1045 | goodName := cmd.Goods[i].GoodName | 1084 | goodName := cmd.Goods[i].GoodName |
| 1046 | if _, ok := goodMap[goodName]; ok { | 1085 | if _, ok := goodMap[goodName]; ok { |
| 1047 | - return nil, lib.ThrowError(lib.BUSINESS_ERROR, "订单中货品重复已存在") | 1086 | + goodErrMap[cmd.Goods[i].LineNumber] = lib.ThrowError(lib.BUSINESS_ERROR, "订单中货品重复已存在") |
| 1087 | + continue | ||
| 1048 | } | 1088 | } |
| 1049 | goodMap[goodName] = 1 | 1089 | goodMap[goodName] = 1 |
| 1050 | } | 1090 | } |
| 1091 | + if len(goodErrMap) > 0 { | ||
| 1092 | + row := &domain.ImportInfo{ | ||
| 1093 | + Error: lib.ThrowError(lib.BUSINESS_ERROR, "订单中货品重复已存在"), | ||
| 1094 | + LineNumbers: cmd.LineNumbers, // 错误影响的行 | ||
| 1095 | + GoodLine: goodErrMap, // 错误产品行号记录 | ||
| 1096 | + } | ||
| 1097 | + errorDataList = append(errorDataList, row) | ||
| 1098 | + continue | ||
| 1099 | + } | ||
| 1051 | 1100 | ||
| 1052 | newOrder := &domain.OrderBase{ | 1101 | newOrder := &domain.OrderBase{ |
| 1053 | OrderType: cmd.OrderType, OrderCode: cmd.OrderCode, | 1102 | OrderType: cmd.OrderType, OrderCode: cmd.OrderCode, |
| @@ -1083,12 +1132,19 @@ func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*co | @@ -1083,12 +1132,19 @@ func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*co | ||
| 1083 | } | 1132 | } |
| 1084 | } | 1133 | } |
| 1085 | if !cmdPartnerCategoryOk { | 1134 | if !cmdPartnerCategoryOk { |
| 1086 | - return nil, lib.ThrowError(lib.BUSINESS_ERROR, "合伙人类型选择错误") | 1135 | + row := &domain.ImportInfo{ |
| 1136 | + Error: lib.ThrowError(lib.BUSINESS_ERROR, "合伙人类型选择错误"), | ||
| 1137 | + LineNumbers: cmd.LineNumbers, // 错误影响的行 | ||
| 1138 | + GoodLine: map[int]interface{}{}, | ||
| 1139 | + } | ||
| 1140 | + errorDataList = append(errorDataList, row) | ||
| 1141 | + continue | ||
| 1087 | } | 1142 | } |
| 1088 | 1143 | ||
| 1089 | // 订单产品分红核算 | 1144 | // 订单产品分红核算 |
| 1090 | var orderGoods []domain.OrderGood | 1145 | var orderGoods []domain.OrderGood |
| 1091 | - for _, good := range cmd.Goods { | 1146 | + orderGoodErrMap := make(map[int]interface{}, 0) |
| 1147 | + for i, good := range cmd.Goods { | ||
| 1092 | m := domain.NewOrderGood() | 1148 | m := domain.NewOrderGood() |
| 1093 | m.OrderId = 0 | 1149 | m.OrderId = 0 |
| 1094 | m.GoodName = good.GoodName | 1150 | m.GoodName = good.GoodName |
| @@ -1097,28 +1153,54 @@ func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*co | @@ -1097,28 +1153,54 @@ func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*co | ||
| 1097 | m.PartnerBonusPercent = good.PartnerBonusPercent | 1153 | m.PartnerBonusPercent = good.PartnerBonusPercent |
| 1098 | m.Remark = good.Remark | 1154 | m.Remark = good.Remark |
| 1099 | m.CompanyId = cmd.CompanyId | 1155 | m.CompanyId = cmd.CompanyId |
| 1156 | + | ||
| 1100 | err = m.Compute() | 1157 | err = m.Compute() |
| 1101 | if err != nil { | 1158 | if err != nil { |
| 1102 | - return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("核算订单中商品的数值失败:%s", err)) | 1159 | + orderGoodErrMap[cmd.Goods[i].LineNumber] = lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("核算订单中商品的数值失败:%s", err)) |
| 1160 | + continue | ||
| 1103 | } | 1161 | } |
| 1162 | + | ||
| 1104 | err = m.CurrentBonusStatus.WartPayPartnerBonus(&m) | 1163 | err = m.CurrentBonusStatus.WartPayPartnerBonus(&m) |
| 1105 | if err != nil { | 1164 | if err != nil { |
| 1106 | - return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("核算订单中商品的分红数值失败:%s", err)) | 1165 | + orderGoodErrMap[cmd.Goods[i].LineNumber] = lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("核算订单中商品的分红数值失败:%s", err)) |
| 1166 | + continue | ||
| 1107 | } | 1167 | } |
| 1168 | + | ||
| 1108 | orderGoods = append(orderGoods, m) | 1169 | orderGoods = append(orderGoods, m) |
| 1109 | } | 1170 | } |
| 1171 | + if len(orderGoodErrMap) > 0 { | ||
| 1172 | + row := &domain.ImportInfo{ | ||
| 1173 | + Error: lib.ThrowError(lib.BUSINESS_ERROR, "核算订单中商品错误"), | ||
| 1174 | + LineNumbers: cmd.LineNumbers, // 错误影响的行 | ||
| 1175 | + GoodLine: orderGoodErrMap, // 错误产品行号记录 | ||
| 1176 | + } | ||
| 1177 | + errorDataList = append(errorDataList, row) | ||
| 1178 | + continue | ||
| 1179 | + } | ||
| 1110 | 1180 | ||
| 1111 | newOrder.Goods = orderGoods | 1181 | newOrder.Goods = orderGoods |
| 1112 | 1182 | ||
| 1113 | err = newOrder.Compute() | 1183 | err = newOrder.Compute() |
| 1114 | if err != nil { | 1184 | if err != nil { |
| 1115 | - return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("核算订单中合计的数值失败:%s", err)) | 1185 | + row := &domain.ImportInfo{ |
| 1186 | + Error: lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("核算订单中合计的数值失败:%s", err)), | ||
| 1187 | + LineNumbers: cmd.LineNumbers, // 错误影响的行 | ||
| 1188 | + GoodLine: map[int]interface{}{}, | ||
| 1189 | + } | ||
| 1190 | + errorDataList = append(errorDataList, row) | ||
| 1191 | + continue | ||
| 1116 | } | 1192 | } |
| 1117 | 1193 | ||
| 1118 | // 保存订单数据 | 1194 | // 保存订单数据 |
| 1119 | err = orderBaseRepository.Save(newOrder) | 1195 | err = orderBaseRepository.Save(newOrder) |
| 1120 | if err != nil { | 1196 | if err != nil { |
| 1121 | - return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("保存订单数据失败:%s", err)) | 1197 | + row := &domain.ImportInfo{ |
| 1198 | + Error: lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("保存订单数据失败:%s", err)), | ||
| 1199 | + LineNumbers: cmd.LineNumbers, // 错误影响的行 | ||
| 1200 | + GoodLine: map[int]interface{}{}, | ||
| 1201 | + } | ||
| 1202 | + errorDataList = append(errorDataList, row) | ||
| 1203 | + continue | ||
| 1122 | } | 1204 | } |
| 1123 | 1205 | ||
| 1124 | for i := range newOrder.Goods { | 1206 | for i := range newOrder.Goods { |
| @@ -1128,22 +1210,27 @@ func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*co | @@ -1128,22 +1210,27 @@ func (service OrderInfoService) CreateNewOrderByImport(createOrderCommands []*co | ||
| 1128 | // 保存订单产品 | 1210 | // 保存订单产品 |
| 1129 | err = orderGoodRepository.Save(orderGoods) | 1211 | err = orderGoodRepository.Save(orderGoods) |
| 1130 | if err != nil { | 1212 | if err != nil { |
| 1131 | - return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("保存订单中的商品数据失败:%s", err)) | 1213 | + row := &domain.ImportInfo{ |
| 1214 | + Error: lib.ThrowError(lib.INTERNAL_SERVER_ERROR, fmt.Sprintf("保存订单中的商品数据失败:%s", err)), | ||
| 1215 | + LineNumbers: cmd.LineNumbers, // 错误影响的行 | ||
| 1216 | + GoodLine: map[int]interface{}{}, | ||
| 1217 | + } | ||
| 1218 | + errorDataList = append(errorDataList, row) | ||
| 1219 | + continue | ||
| 1132 | } | 1220 | } |
| 1133 | - | ||
| 1134 | newOrder.Goods = orderGoods | 1221 | newOrder.Goods = orderGoods |
| 1135 | } | 1222 | } |
| 1136 | 1223 | ||
| 1137 | - if len(failureDataList) == 0 { | 1224 | + if len(errorDataList) == 0 { |
| 1138 | // 完成事务 | 1225 | // 完成事务 |
| 1139 | err = transactionContext.CommitTransaction() | 1226 | err = transactionContext.CommitTransaction() |
| 1140 | if err != nil { | 1227 | if err != nil { |
| 1141 | return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) | 1228 | return nil, lib.ThrowError(lib.INTERNAL_SERVER_ERROR, err.Error()) |
| 1142 | } | 1229 | } |
| 1143 | - return failureDataList, nil | 1230 | + return errorDataList, nil |
| 1144 | } | 1231 | } |
| 1145 | 1232 | ||
| 1146 | - return failureDataList, nil | 1233 | + return errorDataList, nil |
| 1147 | } | 1234 | } |
| 1148 | 1235 | ||
| 1149 | /** | 1236 | /** |
| @@ -6,6 +6,7 @@ const SERVICE_NAME = "partnermg" | @@ -6,6 +6,7 @@ const SERVICE_NAME = "partnermg" | ||
| 6 | 6 | ||
| 7 | var LOG_LEVEL = "debug" | 7 | var LOG_LEVEL = "debug" |
| 8 | var LOG_File = "./logs/partnermg.log" | 8 | var LOG_File = "./logs/partnermg.log" |
| 9 | +var IMPORT_EXCEL = "./download/订单数据模板.xlsx" | ||
| 9 | var Log_PREFIX = "[partnermg_dev]" | 10 | var Log_PREFIX = "[partnermg_dev]" |
| 10 | var ( | 11 | var ( |
| 11 | UCENTER_HOST = "https://suplus-ucenter-test.fjmaimaimai.com" //统一用户中心地址 | 12 | UCENTER_HOST = "https://suplus-ucenter-test.fjmaimaimai.com" //统一用户中心地址 |
| @@ -14,7 +14,7 @@ var KafkaCfg KafkaConfig | @@ -14,7 +14,7 @@ var KafkaCfg KafkaConfig | ||
| 14 | 14 | ||
| 15 | func init() { | 15 | func init() { |
| 16 | KafkaCfg = KafkaConfig{ | 16 | KafkaCfg = KafkaConfig{ |
| 17 | - Servers: []string{"106.52.15.41:9092"}, | 17 | + Servers: []string{"127.0.0.1:9092"}, |
| 18 | ConsumerId: "partnermg_dev", | 18 | ConsumerId: "partnermg_dev", |
| 19 | } | 19 | } |
| 20 | if os.Getenv("KAFKA_HOST") != "" { | 20 | if os.Getenv("KAFKA_HOST") != "" { |
| @@ -314,6 +314,17 @@ type OrderBaseFindQuery struct { | @@ -314,6 +314,17 @@ type OrderBaseFindQuery struct { | ||
| 314 | CompanyId int64 | 314 | CompanyId int64 |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | +// 导入错误信息 | ||
| 318 | +type ImportInfo struct { | ||
| 319 | + Error error | ||
| 320 | + LineNumbers []int | ||
| 321 | + GoodLine map[int]interface{} | ||
| 322 | +} | ||
| 323 | + | ||
| 324 | +// 导入产品错误信息 | ||
| 325 | +type GoodErrInfo struct { | ||
| 326 | +} | ||
| 327 | + | ||
| 317 | type OrderBaseRepository interface { | 328 | type OrderBaseRepository interface { |
| 318 | Save(order *OrderBase) error | 329 | Save(order *OrderBase) error |
| 319 | FindOne(qureyOptions OrderBaseFindOneQuery) (*OrderBase, error) | 330 | FindOne(qureyOptions OrderBaseFindOneQuery) (*OrderBase, error) |
| @@ -186,7 +186,7 @@ func (dao OrderBaseDao) OrderBonusListForExcel(companyId int64, orderType int, p | @@ -186,7 +186,7 @@ func (dao OrderBaseDao) OrderBonusListForExcel(companyId int64, orderType int, p | ||
| 186 | //@param partnerCategory 合伙人类型id | 186 | //@param partnerCategory 合伙人类型id |
| 187 | //@param updateTime 订单更新时间范围"[开始时间,结束时间]",时间格式"2006-01-02 15:04:05+07" | 187 | //@param updateTime 订单更新时间范围"[开始时间,结束时间]",时间格式"2006-01-02 15:04:05+07" |
| 188 | //@param createTime 订单的创建时间范围"[开始时间,结束时间]" 时间格式"2006-01-02 15:04:05+07" | 188 | //@param createTime 订单的创建时间范围"[开始时间,结束时间]" 时间格式"2006-01-02 15:04:05+07" |
| 189 | -func (dao OrderBaseDao) OrderListByCondition(companyId int64, orderType int, partnerOrCode string, | 189 | +func (dao OrderBaseDao) OrderListByCondition(companyId int64, orderType int, partnerName string, orderCode string, deliveryCode string, |
| 190 | updateTime [2]string, createTime [2]string, partnerCategory int, limit, offset int) ([]models.OrderBase, int, error) { | 190 | updateTime [2]string, createTime [2]string, partnerCategory int, limit, offset int) ([]models.OrderBase, int, error) { |
| 191 | tx := dao.transactionContext.GetDB() | 191 | tx := dao.transactionContext.GetDB() |
| 192 | var orders []models.OrderBase | 192 | var orders []models.OrderBase |
| @@ -211,16 +211,25 @@ func (dao OrderBaseDao) OrderListByCondition(companyId int64, orderType int, par | @@ -211,16 +211,25 @@ func (dao OrderBaseDao) OrderListByCondition(companyId int64, orderType int, par | ||
| 211 | if len(createTime[1]) > 0 { | 211 | if len(createTime[1]) > 0 { |
| 212 | query = query.Where(`order_base.create_time<=?`, createTime[1]) | 212 | query = query.Where(`order_base.create_time<=?`, createTime[1]) |
| 213 | } | 213 | } |
| 214 | - | ||
| 215 | - if len(partnerOrCode) > 0 { | 214 | + if len(partnerName) > 0 { |
| 216 | query = query.Join("LEFT JOIN partner_info as p ON order_base.partner_id=p.id"). | 215 | query = query.Join("LEFT JOIN partner_info as p ON order_base.partner_id=p.id"). |
| 217 | - WhereGroup(func(q *orm.Query) (*orm.Query, error) { | ||
| 218 | - q = q.WhereOr("order_base.order_code like ? ", "%"+partnerOrCode+"%"). | ||
| 219 | - WhereOr("order_base.delivery_code like ? ", "%"+partnerOrCode+"%"). | ||
| 220 | - WhereOr("p.partner_name like ? ", "%"+partnerOrCode+"%") | ||
| 221 | - return q, nil | ||
| 222 | - }) | 216 | + Where("p.partner_name like ? ", "%"+partnerName+"%") |
| 217 | + } | ||
| 218 | + if len(orderCode) > 0 { | ||
| 219 | + query = query.Where("order_base.order_code like ? ", "%"+orderCode+"%") | ||
| 223 | } | 220 | } |
| 221 | + if len(deliveryCode) > 0 { | ||
| 222 | + query = query.Where("order_base.delivery_code like ? ", "%"+deliveryCode+"%") | ||
| 223 | + } | ||
| 224 | + //if len(partnerOrCode) > 0 { | ||
| 225 | + // query = query.Join("LEFT JOIN partner_info as p ON order_base.partner_id=p.id"). | ||
| 226 | + // WhereGroup(func(q *orm.Query) (*orm.Query, error) { | ||
| 227 | + // q = q.WhereOr("order_base.order_code like ? ", "%"+partnerOrCode+"%"). | ||
| 228 | + // WhereOr("order_base.delivery_code like ? ", "%"+partnerOrCode+"%"). | ||
| 229 | + // WhereOr("p.partner_name like ? ", "%"+partnerOrCode+"%") | ||
| 230 | + // return q, nil | ||
| 231 | + // }) | ||
| 232 | + //} | ||
| 224 | query = query.Order("order_base.create_time DESC"). | 233 | query = query.Order("order_base.create_time DESC"). |
| 225 | Offset(offset). | 234 | Offset(offset). |
| 226 | Limit(limit) | 235 | Limit(limit) |
| @@ -253,7 +262,7 @@ type CustomOrderListForExcel struct { | @@ -253,7 +262,7 @@ type CustomOrderListForExcel struct { | ||
| 253 | //@param partnerCategory 合伙人类型id | 262 | //@param partnerCategory 合伙人类型id |
| 254 | //@param updateTime 订单更新时间范围"[开始时间,结束时间]",时间格式"2006-01-02 15:04:05+07" | 263 | //@param updateTime 订单更新时间范围"[开始时间,结束时间]",时间格式"2006-01-02 15:04:05+07" |
| 255 | //@param createTime 订单的创建时间范围"[开始时间,结束时间]" 时间格式"2006-01-02 15:04:05+07" | 264 | //@param createTime 订单的创建时间范围"[开始时间,结束时间]" 时间格式"2006-01-02 15:04:05+07" |
| 256 | -func (dao OrderBaseDao) OrderListForExcel(companyId int64, partnerOrCode string, | 265 | +func (dao OrderBaseDao) OrderListForExcel(companyId int64, partnerName string, orderCode string, deliveryCode string, |
| 257 | updateTime [2]string, createTime [2]string, partnerCategory int) ( | 266 | updateTime [2]string, createTime [2]string, partnerCategory int) ( |
| 258 | result []CustomOrderListForExcel, err error) { | 267 | result []CustomOrderListForExcel, err error) { |
| 259 | sqlstr := ` | 268 | sqlstr := ` |
| @@ -269,12 +278,26 @@ func (dao OrderBaseDao) OrderListForExcel(companyId int64, partnerOrCode string, | @@ -269,12 +278,26 @@ func (dao OrderBaseDao) OrderListForExcel(companyId int64, partnerOrCode string, | ||
| 269 | WHERE 1=1 AND t1.order_type = 1 AND t1.company_id=? | 278 | WHERE 1=1 AND t1.order_type = 1 AND t1.company_id=? |
| 270 | ` | 279 | ` |
| 271 | params := []interface{}{companyId} | 280 | params := []interface{}{companyId} |
| 272 | - if len(partnerOrCode) > 0 { | ||
| 273 | - like := "%" + partnerOrCode + "%" | ||
| 274 | - params = append(params, like, like, like) | ||
| 275 | - sqlstr += " AND (t1.order_code like ? OR t1.delivery_code like ? OR t2.partner_name like ? ) " | 281 | + //if len(partnerOrCode) > 0 { |
| 282 | + // like := "%" + partnerOrCode + "%" | ||
| 283 | + // params = append(params, like, like, like) | ||
| 284 | + // sqlstr += " AND (t1.order_code like ? OR t1.delivery_code like ? OR t2.partner_name like ? ) " | ||
| 285 | + //} | ||
| 286 | + if len(partnerName) > 0 { | ||
| 287 | + like := "%" + partnerName + "%" | ||
| 288 | + params = append(params, like) | ||
| 289 | + sqlstr += ` AND t2.partner_name like ? ` | ||
| 290 | + } | ||
| 291 | + if len(orderCode) > 0 { | ||
| 292 | + like := "%" + orderCode + "%" | ||
| 293 | + params = append(params, like) | ||
| 294 | + sqlstr += ` AND t1.order_code like ? ` | ||
| 295 | + } | ||
| 296 | + if len(deliveryCode) > 0 { | ||
| 297 | + like := "%" + deliveryCode + "%" | ||
| 298 | + params = append(params, like) | ||
| 299 | + sqlstr += ` AND t1.delivery_code like ? ` | ||
| 276 | } | 300 | } |
| 277 | - | ||
| 278 | if partnerCategory > 0 { | 301 | if partnerCategory > 0 { |
| 279 | params = append(params, partnerCategory) | 302 | params = append(params, partnerCategory) |
| 280 | sqlstr += ` AND t1.partner_category@>'{"id":?}' ` | 303 | sqlstr += ` AND t1.partner_category@>'{"id":?}' ` |
| @@ -3,9 +3,9 @@ package controllers | @@ -3,9 +3,9 @@ package controllers | ||
| 3 | import ( | 3 | import ( |
| 4 | "crypto/md5" | 4 | "crypto/md5" |
| 5 | "encoding/hex" | 5 | "encoding/hex" |
| 6 | - "encoding/json" | ||
| 7 | "errors" | 6 | "errors" |
| 8 | "fmt" | 7 | "fmt" |
| 8 | + "github.com/beego/beego/v2/client/httplib" | ||
| 9 | "path" | 9 | "path" |
| 10 | "regexp" | 10 | "regexp" |
| 11 | "strconv" | 11 | "strconv" |
| @@ -70,6 +70,7 @@ func (postData *postPurposeOrderDetail) Valid() error { | @@ -70,6 +70,7 @@ func (postData *postPurposeOrderDetail) Valid() error { | ||
| 70 | } | 70 | } |
| 71 | if postData.PartnerId == 0 { | 71 | if postData.PartnerId == 0 { |
| 72 | return lib.ThrowError(lib.ARG_ERROR, "合伙人信息必填") | 72 | return lib.ThrowError(lib.ARG_ERROR, "合伙人信息必填") |
| 73 | + | ||
| 73 | } | 74 | } |
| 74 | if len(postData.OrderDist) == 0 { | 75 | if len(postData.OrderDist) == 0 { |
| 75 | return lib.ThrowError(lib.ARG_ERROR, "订单区域必填") | 76 | return lib.ThrowError(lib.ARG_ERROR, "订单区域必填") |
| @@ -149,10 +150,19 @@ func (postData *postOrderPurposeDelivery) Valid() error { | @@ -149,10 +150,19 @@ func (postData *postOrderPurposeDelivery) Valid() error { | ||
| 149 | return nil | 150 | return nil |
| 150 | } | 151 | } |
| 151 | 152 | ||
| 152 | -//PageListOrderReal 获取实发订单列表 | 153 | +/** |
| 154 | + * @Author SteveChan | ||
| 155 | + * @Description // 获取实发订单列表,修改搜索条件 | ||
| 156 | + * @Date 20:23 2021/1/10 | ||
| 157 | + * @Param | ||
| 158 | + * @return | ||
| 159 | + **/ | ||
| 153 | func (c *OrderInfoController) PageListOrderReal() { | 160 | func (c *OrderInfoController) PageListOrderReal() { |
| 154 | type Parameter struct { | 161 | type Parameter struct { |
| 155 | - SearchText string `json:"searchText"` | 162 | + //SearchText string `json:"searchText"` |
| 163 | + PartnerName string `json:"partnerName"` // 合伙人姓名 | ||
| 164 | + OrderCode string `json:"orderCode"` // 订单号 | ||
| 165 | + DeliveryCode string `json:"deliveryCode"` // 发货单号 | ||
| 156 | PartnerCategory int `json:"PartnerCategory"` | 166 | PartnerCategory int `json:"PartnerCategory"` |
| 157 | PageSize int `json:"pageSize"` | 167 | PageSize int `json:"pageSize"` |
| 158 | PageNumber int `json:"pageNumber"` | 168 | PageNumber int `json:"pageNumber"` |
| @@ -230,7 +240,10 @@ func (c *OrderInfoController) PageListOrderReal() { | @@ -230,7 +240,10 @@ func (c *OrderInfoController) PageListOrderReal() { | ||
| 230 | companyId := c.GetUserCompany() | 240 | companyId := c.GetUserCompany() |
| 231 | orderSrv := orderService.NewOrderInfoService(nil) | 241 | orderSrv := orderService.NewOrderInfoService(nil) |
| 232 | orderinfos, cnt, err := orderSrv.PageListOrderBase(orderQuery.ListOrderBaseQuery{ | 242 | orderinfos, cnt, err := orderSrv.PageListOrderBase(orderQuery.ListOrderBaseQuery{ |
| 233 | - PartnerOrCode: param.SearchText, | 243 | + //PartnerOrCode: param.SearchText, |
| 244 | + PartnerName: param.PartnerName, | ||
| 245 | + OrderCode: param.OrderCode, | ||
| 246 | + DeliveryCode: param.DeliveryCode, | ||
| 234 | OrderType: domain.OrderReal, | 247 | OrderType: domain.OrderReal, |
| 235 | Limit: param.PageSize, | 248 | Limit: param.PageSize, |
| 236 | Offset: (param.PageNumber - 1) * param.PageSize, | 249 | Offset: (param.PageNumber - 1) * param.PageSize, |
| @@ -514,7 +527,10 @@ func (c *OrderInfoController) RemoveOrderReal() { | @@ -514,7 +527,10 @@ func (c *OrderInfoController) RemoveOrderReal() { | ||
| 514 | //ListOrderForExcel excel 导出实际订单的列表 | 527 | //ListOrderForExcel excel 导出实际订单的列表 |
| 515 | func (c *OrderInfoController) ListOrderForExcel() { | 528 | func (c *OrderInfoController) ListOrderForExcel() { |
| 516 | type Parameter struct { | 529 | type Parameter struct { |
| 517 | - SearchText string `json:"searchText"` | 530 | + //SearchText string `json:"searchText"` |
| 531 | + PartnerName string `json:"partnerName"` // 合伙人姓名 | ||
| 532 | + OrderCode string `json:"orderCode"` // 订单号 | ||
| 533 | + DeliveryCode string `json:"deliveryCode"` // 发货单号 | ||
| 518 | PartnerCategory int `json:"PartnerCategory"` | 534 | PartnerCategory int `json:"PartnerCategory"` |
| 519 | UpdateTime []string `json:"updateTime"` | 535 | UpdateTime []string `json:"updateTime"` |
| 520 | CreateTime []string `json:"createTime"` | 536 | CreateTime []string `json:"createTime"` |
| @@ -584,7 +600,10 @@ func (c *OrderInfoController) ListOrderForExcel() { | @@ -584,7 +600,10 @@ func (c *OrderInfoController) ListOrderForExcel() { | ||
| 584 | companyId := c.GetUserCompany() | 600 | companyId := c.GetUserCompany() |
| 585 | orderSrv := orderService.NewOrderInfoService(nil) | 601 | orderSrv := orderService.NewOrderInfoService(nil) |
| 586 | orderinfos, columns, err := orderSrv.ListOrderForExcel(orderQuery.ListOrderBaseQuery{ | 602 | orderinfos, columns, err := orderSrv.ListOrderForExcel(orderQuery.ListOrderBaseQuery{ |
| 587 | - PartnerOrCode: param.SearchText, | 603 | + //PartnerOrCode: param.SearchText, |
| 604 | + PartnerName: param.PartnerName, | ||
| 605 | + OrderCode: param.OrderCode, | ||
| 606 | + DeliveryCode: param.DeliveryCode, | ||
| 588 | OrderType: domain.OrderReal, | 607 | OrderType: domain.OrderReal, |
| 589 | CompanyId: companyId, | 608 | CompanyId: companyId, |
| 590 | PartnerCategory: param.PartnerCategory, | 609 | PartnerCategory: param.PartnerCategory, |
| @@ -614,6 +633,56 @@ func (c *OrderInfoController) ListOrderForExcel() { | @@ -614,6 +633,56 @@ func (c *OrderInfoController) ListOrderForExcel() { | ||
| 614 | 633 | ||
| 615 | /** | 634 | /** |
| 616 | * @Author SteveChan | 635 | * @Author SteveChan |
| 636 | + * @Description // 下载导入模板 | ||
| 637 | + * @Date 16:48 2021/1/8 | ||
| 638 | + * @Param | ||
| 639 | + * @return | ||
| 640 | + **/ | ||
| 641 | +func (c *OrderInfoController) DownloadTemplate() { | ||
| 642 | + type Parameter struct { | ||
| 643 | + TYPE string `json:"type"` | ||
| 644 | + } | ||
| 645 | + | ||
| 646 | + var ( | ||
| 647 | + param Parameter | ||
| 648 | + err error | ||
| 649 | + ) | ||
| 650 | + | ||
| 651 | + if err = c.BindJsonData(¶m); err != nil { | ||
| 652 | + logs.Error(err) | ||
| 653 | + c.ResponseError(errors.New("json数据解析失败")) | ||
| 654 | + return | ||
| 655 | + } | ||
| 656 | + | ||
| 657 | + // 校验类型编码 | ||
| 658 | + if param.TYPE != "PARTNER_ORDER_FILE" { | ||
| 659 | + c.ResponseError(errors.New("类型编码错误")) | ||
| 660 | + } | ||
| 661 | + | ||
| 662 | + // 获取导入模板 | ||
| 663 | + req := httplib.Get("http://suplus-file-dev.fjmaimaimai.com/upload/file/2021010803305336443.xlsx") | ||
| 664 | + err = req.ToFile(constant.IMPORT_EXCEL) | ||
| 665 | + if err != nil { | ||
| 666 | + logs.Error("could not save to file: ", err) | ||
| 667 | + } | ||
| 668 | + | ||
| 669 | + // 返回字段定义 | ||
| 670 | + ret := map[string]interface{}{} | ||
| 671 | + | ||
| 672 | + resp, err := req.Response() | ||
| 673 | + if err != nil { | ||
| 674 | + logs.Error("could not get response: ", err) | ||
| 675 | + } else { | ||
| 676 | + logs.Info(resp) | ||
| 677 | + ret = map[string]interface{}{ | ||
| 678 | + "url": "http://" + c.Ctx.Request.Host + "/download/订单数据模板.xlsx", | ||
| 679 | + } | ||
| 680 | + c.ResponseData(ret) | ||
| 681 | + } | ||
| 682 | +} | ||
| 683 | + | ||
| 684 | +/** | ||
| 685 | + * @Author SteveChan | ||
| 617 | * @Description //TODO 导入excel订单 | 686 | * @Description //TODO 导入excel订单 |
| 618 | * @Date 10:52 2021/1/6 | 687 | * @Date 10:52 2021/1/6 |
| 619 | * @Param | 688 | * @Param |
| @@ -621,17 +690,20 @@ func (c *OrderInfoController) ListOrderForExcel() { | @@ -621,17 +690,20 @@ func (c *OrderInfoController) ListOrderForExcel() { | ||
| 621 | **/ | 690 | **/ |
| 622 | func (c *OrderInfoController) ImportOrderFromExcel() { | 691 | func (c *OrderInfoController) ImportOrderFromExcel() { |
| 623 | // 获取参数 | 692 | // 获取参数 |
| 624 | - where := c.GetString("where") | 693 | + typeCode := c.GetString("type") |
| 625 | file, h, _ := c.GetFile("file") | 694 | file, h, _ := c.GetFile("file") |
| 626 | - | ||
| 627 | companyId := c.GetUserCompany() | 695 | companyId := c.GetUserCompany() |
| 628 | 696 | ||
| 629 | // Json数据解析 | 697 | // Json数据解析 |
| 630 | - jsonMap := make(map[string]interface{}) | ||
| 631 | - err := json.Unmarshal([]byte(where), &jsonMap) | ||
| 632 | - if err != nil { | ||
| 633 | - logs.Error(err) | ||
| 634 | - c.ResponseError(errors.New("json数据解析失败")) | 698 | + //jsonMap := make(map[string]interface{}) |
| 699 | + //err := json.Unmarshal([]byte(where), &jsonMap) | ||
| 700 | + //if err != nil { | ||
| 701 | + // logs.Error(err) | ||
| 702 | + // c.ResponseError(errors.New("json数据解析失败")) | ||
| 703 | + //} | ||
| 704 | + | ||
| 705 | + if typeCode != "PARTNER_ORDER_IMPORT" { | ||
| 706 | + c.ResponseError(errors.New("类型编码错误")) | ||
| 635 | } | 707 | } |
| 636 | 708 | ||
| 637 | // 返回字段定义 | 709 | // 返回字段定义 |
| @@ -678,7 +750,7 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | @@ -678,7 +750,7 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | ||
| 678 | var tmpRow = row | 750 | var tmpRow = row |
| 679 | var myRow []string | 751 | var myRow []string |
| 680 | for j, cell := range row { | 752 | for j, cell := range row { |
| 681 | - if j != 8 { // 业务员抽成比例不校验 | 753 | + if j != 8 { // 业务员抽成比例非必填 |
| 682 | if cell == "" || cell == " " { // 空字符串填充 | 754 | if cell == "" || cell == " " { // 空字符串填充 |
| 683 | tmpRow[j] = "null" | 755 | tmpRow[j] = "null" |
| 684 | nullFlag = true | 756 | nullFlag = true |
| @@ -728,11 +800,13 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | @@ -728,11 +800,13 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | ||
| 728 | var myRow []string | 800 | var myRow []string |
| 729 | for j, cell := range row { | 801 | for j, cell := range row { |
| 730 | switch j { | 802 | switch j { |
| 731 | - case 0, 1, 2, 3, 4, 5, 8: // 订单号、发货单号、客户名称、订单区域、编号、合伙人、产品名称、 | 803 | + case 0, 1, 2, 3, 4, 5, 8: // 订单号、发货单号、客户名称、订单区域、编号、合伙人、产品名称长度校验 |
| 732 | { | 804 | { |
| 733 | - if len(cell) > 50 { | 805 | + cellStr := strings.TrimSpace(cell) |
| 806 | + lenCellStr := utf8.RuneCountInString(cellStr) | ||
| 807 | + if lenCellStr > 50 { | ||
| 734 | var tmpRow []string | 808 | var tmpRow []string |
| 735 | - tmpRow = append(tmpRow, tableHeader[j+2]+"长度超过50,请重新输入") // 错误信息 | 809 | + tmpRow = append(tmpRow, tableHeader[j+2]+"长度超过50位,请重新输入") // 错误信息 |
| 736 | s := strconv.Itoa(i + 1) | 810 | s := strconv.Itoa(i + 1) |
| 737 | tmpRow = append(tmpRow, s) // 行号 | 811 | tmpRow = append(tmpRow, s) // 行号 |
| 738 | tmpRow = append(tmpRow, row...) // 错误行数据 | 812 | tmpRow = append(tmpRow, row...) // 错误行数据 |
| @@ -752,50 +826,76 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | @@ -752,50 +826,76 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | ||
| 752 | } | 826 | } |
| 753 | case 7: // 业务员抽成比例,非必填,精确到小数点后两位 | 827 | case 7: // 业务员抽成比例,非必填,精确到小数点后两位 |
| 754 | { | 828 | { |
| 829 | + var ( | ||
| 830 | + typeErrFlag bool | ||
| 831 | + lenErrFlag bool | ||
| 832 | + ratioErrFlag bool | ||
| 833 | + ) | ||
| 755 | if len(cell) > 0 { | 834 | if len(cell) > 0 { |
| 756 | - _, err := strconv.ParseFloat(cell, 64) | 835 | + // 参数类型转换 |
| 836 | + shareRatio, err := strconv.ParseFloat(cell, 64) | ||
| 757 | if err != nil { | 837 | if err != nil { |
| 838 | + typeErrFlag = true | ||
| 839 | + } | ||
| 840 | + | ||
| 841 | + // 比例不能超过100% | ||
| 842 | + if shareRatio > 100 { | ||
| 843 | + ratioErrFlag = true | ||
| 844 | + } | ||
| 845 | + | ||
| 846 | + // 长度校验 | ||
| 847 | + regexpStr := `^(100|[1-9]\d|\d)(.\d{1,2})?$` | ||
| 848 | + ok := regexp.MustCompile(regexpStr).MatchString(cell) | ||
| 849 | + if !ok { | ||
| 850 | + lenErrFlag = true | ||
| 851 | + } | ||
| 852 | + | ||
| 853 | + if typeErrFlag || lenErrFlag || ratioErrFlag { | ||
| 758 | var tmpRow []string | 854 | var tmpRow []string |
| 759 | tmpRow = append(tmpRow, "业务员抽成比例格式错误,请输入正确的业务员抽成比例比例,保留两位小数") // 错误信息 | 855 | tmpRow = append(tmpRow, "业务员抽成比例格式错误,请输入正确的业务员抽成比例比例,保留两位小数") // 错误信息 |
| 760 | s := strconv.Itoa(i + 1) | 856 | s := strconv.Itoa(i + 1) |
| 761 | tmpRow = append(tmpRow, s) // 行号 | 857 | tmpRow = append(tmpRow, s) // 行号 |
| 762 | tmpRow = append(tmpRow, row...) // 错误行数据 | 858 | tmpRow = append(tmpRow, row...) // 错误行数据 |
| 763 | myRow = tmpRow | 859 | myRow = tmpRow |
| 860 | + typeErrFlag = false | ||
| 861 | + lenErrFlag = false | ||
| 862 | + ratioErrFlag = false | ||
| 764 | } | 863 | } |
| 765 | - //if isOk, _ := regexp.MatchString("^(.[0-9]{0,1,2})?$", cell); !isOk { // 最多两位小数 | ||
| 766 | - // var tmpRow []string | ||
| 767 | - // tmpRow = append(tmpRow, "业务员员抽成比例格式错误,请输入正确的单价,保留两位小数") // 错误信息 | ||
| 768 | - // s := strconv.Itoa(i + 1) | ||
| 769 | - // tmpRow = append(tmpRow, s) // 行号 | ||
| 770 | - // tmpRow = append(tmpRow, row...) // 错误行数据 | ||
| 771 | - // myRow = tmpRow | ||
| 772 | - //} | ||
| 773 | } | 864 | } |
| 774 | } | 865 | } |
| 775 | case 9: // 数量不超过16位正整数 | 866 | case 9: // 数量不超过16位正整数 |
| 776 | { | 867 | { |
| 777 | - _, err := strconv.ParseInt(cell, 10, 64) | 868 | + var ( |
| 869 | + typeErrFlag bool | ||
| 870 | + lenErrFlag bool | ||
| 871 | + ) | ||
| 872 | + | ||
| 873 | + //参数类型转换 | ||
| 874 | + orderNum, err := strconv.ParseInt(cell, 10, 64) | ||
| 778 | if err != nil { | 875 | if err != nil { |
| 779 | - var tmpRow []string | ||
| 780 | - tmpRow = append(tmpRow, "数量须为整数,请重新填写") // 错误信息 | ||
| 781 | - s := strconv.Itoa(i + 1) | ||
| 782 | - tmpRow = append(tmpRow, s) // 行号 | ||
| 783 | - tmpRow = append(tmpRow, row...) // 错误行数据 | ||
| 784 | - myRow = tmpRow | 876 | + typeErrFlag = true |
| 877 | + } | ||
| 878 | + | ||
| 879 | + // 长度校验 | ||
| 880 | + if orderNum > 1e16 { | ||
| 881 | + lenErrFlag = true | ||
| 785 | } | 882 | } |
| 786 | 883 | ||
| 787 | - if len(cell) > 16 { | 884 | + if typeErrFlag || lenErrFlag { |
| 788 | var tmpRow []string | 885 | var tmpRow []string |
| 789 | tmpRow = append(tmpRow, "数量长度超过最大限制十六位整数,请重新填写") // 错误信息 | 886 | tmpRow = append(tmpRow, "数量长度超过最大限制十六位整数,请重新填写") // 错误信息 |
| 790 | s := strconv.Itoa(i + 1) | 887 | s := strconv.Itoa(i + 1) |
| 791 | tmpRow = append(tmpRow, s) // 行号 | 888 | tmpRow = append(tmpRow, s) // 行号 |
| 792 | tmpRow = append(tmpRow, row...) // 错误行数据 | 889 | tmpRow = append(tmpRow, row...) // 错误行数据 |
| 793 | myRow = tmpRow | 890 | myRow = tmpRow |
| 891 | + typeErrFlag = false | ||
| 892 | + lenErrFlag = false | ||
| 794 | } | 893 | } |
| 795 | } | 894 | } |
| 796 | case 10: // 单价,精确到小数点后两位,小数点左侧最多可输入16位数字 | 895 | case 10: // 单价,精确到小数点后两位,小数点左侧最多可输入16位数字 |
| 797 | { | 896 | { |
| 798 | - _, err := strconv.ParseFloat(cell, 64) | 897 | + // 参数类型转换 |
| 898 | + univalent, err := strconv.ParseFloat(cell, 64) | ||
| 799 | if err != nil { | 899 | if err != nil { |
| 800 | var tmpRow []string | 900 | var tmpRow []string |
| 801 | tmpRow = append(tmpRow, "单价格式错误,请输入正确的单价,保留两位小数点,小数点前面不能超过十六位数字") // 错误信息 | 901 | tmpRow = append(tmpRow, "单价格式错误,请输入正确的单价,保留两位小数点,小数点前面不能超过十六位数字") // 错误信息 |
| @@ -804,34 +904,53 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | @@ -804,34 +904,53 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | ||
| 804 | tmpRow = append(tmpRow, row...) // 错误行数据 | 904 | tmpRow = append(tmpRow, row...) // 错误行数据 |
| 805 | myRow = tmpRow | 905 | myRow = tmpRow |
| 806 | } | 906 | } |
| 807 | - //if isOk, _ := regexp.MatchString("^d{1,16}(.[0-9]{0,1,2})?$", cell); !isOk { // 非负的16位整数最多两位小数 | ||
| 808 | - // var tmpRow []string | ||
| 809 | - // tmpRow = append(tmpRow, "单价格式错误,请输入正确的单价,保留两位小数点,小数点前面不能超过十六位数字") // 错误信息 | ||
| 810 | - // s := strconv.Itoa(i + 1) | ||
| 811 | - // tmpRow = append(tmpRow, s) // 行号 | ||
| 812 | - // tmpRow = append(tmpRow, row...) // 错误行数据 | ||
| 813 | - // myRow = tmpRow | ||
| 814 | - //} | 907 | + // 长度校验 |
| 908 | + if univalent >= 1e16 { | ||
| 909 | + var tmpRow []string | ||
| 910 | + tmpRow = append(tmpRow, "单价格式错误,请输入正确的单价,保留两位小数点,小数点前面不能超过十六位数字") // 错误信息 | ||
| 911 | + s := strconv.Itoa(i + 1) | ||
| 912 | + tmpRow = append(tmpRow, s) // 行号 | ||
| 913 | + tmpRow = append(tmpRow, row...) // 错误行数据 | ||
| 914 | + myRow = tmpRow | ||
| 915 | + } | ||
| 815 | } | 916 | } |
| 816 | case 11: // 合伙人分红比例,精确到小数点后两位 | 917 | case 11: // 合伙人分红比例,精确到小数点后两位 |
| 817 | { | 918 | { |
| 818 | - _, err := strconv.ParseFloat(cell, 64) | 919 | + var ( |
| 920 | + typeErrFlag bool | ||
| 921 | + lenErrFlag bool | ||
| 922 | + ratioErrFlag bool | ||
| 923 | + ) | ||
| 924 | + | ||
| 925 | + //参数类型转换 | ||
| 926 | + partnerRatio, err := strconv.ParseFloat(cell, 64) | ||
| 819 | if err != nil { | 927 | if err != nil { |
| 928 | + typeErrFlag = true | ||
| 929 | + } | ||
| 930 | + | ||
| 931 | + // 合伙人分红比例超额 | ||
| 932 | + if partnerRatio > 100 { | ||
| 933 | + ratioErrFlag = true | ||
| 934 | + } | ||
| 935 | + | ||
| 936 | + // 长度判断 | ||
| 937 | + regexpStr := `^(100|[1-9]\d|\d)(.\d{1,2})?$` | ||
| 938 | + ok := regexp.MustCompile(regexpStr).MatchString(cell) | ||
| 939 | + if !ok { | ||
| 940 | + lenErrFlag = true | ||
| 941 | + } | ||
| 942 | + | ||
| 943 | + if typeErrFlag || lenErrFlag || ratioErrFlag { | ||
| 820 | var tmpRow []string | 944 | var tmpRow []string |
| 821 | tmpRow = append(tmpRow, "合伙人分红比例格式错误,请输入正确的合伙人分红比例,保留两位小数") // 错误信息 | 945 | tmpRow = append(tmpRow, "合伙人分红比例格式错误,请输入正确的合伙人分红比例,保留两位小数") // 错误信息 |
| 822 | s := strconv.Itoa(i + 1) | 946 | s := strconv.Itoa(i + 1) |
| 823 | tmpRow = append(tmpRow, s) // 行号 | 947 | tmpRow = append(tmpRow, s) // 行号 |
| 824 | tmpRow = append(tmpRow, row...) // 错误行数据 | 948 | tmpRow = append(tmpRow, row...) // 错误行数据 |
| 825 | myRow = tmpRow | 949 | myRow = tmpRow |
| 950 | + typeErrFlag = false | ||
| 951 | + lenErrFlag = false | ||
| 952 | + ratioErrFlag = false | ||
| 826 | } | 953 | } |
| 827 | - //if isOk, _ := regexp.MatchString("^(.[0-9]{1,2})?$", cell); !isOk { // 最多两位小数 | ||
| 828 | - // var tmpRow []string | ||
| 829 | - // tmpRow = append(tmpRow, "合伙人分红比例错误,请输入正确的合伙人分红比例,保留两位小数") // 错误信息 | ||
| 830 | - // s := strconv.Itoa(i + 1) | ||
| 831 | - // tmpRow = append(tmpRow, s) // 行号 | ||
| 832 | - // tmpRow = append(tmpRow, row...) // 错误行数据 | ||
| 833 | - // myRow = tmpRow | ||
| 834 | - //} | ||
| 835 | } | 954 | } |
| 836 | } | 955 | } |
| 837 | } | 956 | } |
| @@ -888,11 +1007,12 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | @@ -888,11 +1007,12 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | ||
| 888 | PlanGoodNumber: int(amount), | 1007 | PlanGoodNumber: int(amount), |
| 889 | Price: price, | 1008 | Price: price, |
| 890 | PartnerBonusPercent: percent, | 1009 | PartnerBonusPercent: percent, |
| 1010 | + LineNumber: i, | ||
| 891 | }, | 1011 | }, |
| 892 | }, | 1012 | }, |
| 893 | CompanyId: companyId, | 1013 | CompanyId: companyId, |
| 894 | PartnerCategory: 1, | 1014 | PartnerCategory: 1, |
| 895 | - LineNumbers: []int{i}, | 1015 | + LineNumbers: []int{i}, // 记录行号 |
| 896 | } | 1016 | } |
| 897 | 1017 | ||
| 898 | // 获取partnerId | 1018 | // 获取partnerId |
| @@ -952,17 +1072,37 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | @@ -952,17 +1072,37 @@ func (c *OrderInfoController) ImportOrderFromExcel() { | ||
| 952 | // 新增成功记录计数 | 1072 | // 新增成功记录计数 |
| 953 | var successDataCount int64 | 1073 | var successDataCount int64 |
| 954 | 1074 | ||
| 955 | - // 新增错误信息 | ||
| 956 | - var createError error | ||
| 957 | - | ||
| 958 | // 批量新增订单 | 1075 | // 批量新增订单 |
| 959 | - failureDataList, createError = orderSrv.CreateNewOrderByImport(createOrderCommands) | 1076 | + errorDataList, createError := orderSrv.CreateNewOrderByImport(createOrderCommands) |
| 960 | if createError != nil { | 1077 | if createError != nil { |
| 961 | c.ResponseError(createError) | 1078 | c.ResponseError(createError) |
| 962 | return | 1079 | return |
| 963 | } else { | 1080 | } else { |
| 964 | - if len(failureDataList) > 0 { // 导入失败返回 | 1081 | + if len(errorDataList) > 0 { // 导入失败返回 |
| 965 | successDataCount = 0 | 1082 | successDataCount = 0 |
| 1083 | + // 错误记录处理 | ||
| 1084 | + for _, errorData := range errorDataList { | ||
| 1085 | + if len(errorData.GoodLine) == 0 { // 订单错误 | ||
| 1086 | + for _, line := range errorData.LineNumbers { | ||
| 1087 | + var tmpRow []string | ||
| 1088 | + tmpRow = append(tmpRow, errorData.Error.Error()) // 错误信息 | ||
| 1089 | + s := strconv.Itoa(line + 1) | ||
| 1090 | + tmpRow = append(tmpRow, s) // 行号 | ||
| 1091 | + tmpRow = append(tmpRow, rows[line]...) // 错误行数据 | ||
| 1092 | + failureDataList = append(failureDataList, tmpRow) | ||
| 1093 | + } | ||
| 1094 | + } else if len(errorData.GoodLine) > 0 { // 订单产品错误 | ||
| 1095 | + for line := range errorData.GoodLine { | ||
| 1096 | + var tmpRow []string | ||
| 1097 | + tmpRow = append(tmpRow, errorData.Error.Error()) // 错误信息 | ||
| 1098 | + s := strconv.Itoa(line + 1) | ||
| 1099 | + tmpRow = append(tmpRow, s) // 行号 | ||
| 1100 | + tmpRow = append(tmpRow, rows[line]...) // 错误行数据 | ||
| 1101 | + failureDataList = append(failureDataList, tmpRow) | ||
| 1102 | + } | ||
| 1103 | + } | ||
| 1104 | + } | ||
| 1105 | + | ||
| 966 | ret = map[string]interface{}{ | 1106 | ret = map[string]interface{}{ |
| 967 | "successCount": successDataCount, | 1107 | "successCount": successDataCount, |
| 968 | "fail": map[string]interface{}{ | 1108 | "fail": map[string]interface{}{ |
| @@ -6,6 +6,10 @@ import ( | @@ -6,6 +6,10 @@ import ( | ||
| 6 | ) | 6 | ) |
| 7 | 7 | ||
| 8 | func init() { | 8 | func init() { |
| 9 | + // 导入相关 | ||
| 10 | + beego.Router("/fileImportTemplate", &controllers.OrderInfoController{}, "POST:DownloadTemplate") // 下载导入模板 | ||
| 11 | + beego.Router("/fileImport", &controllers.OrderInfoController{}, "POST:ImportOrderFromExcel") // 导入订单数据 | ||
| 12 | + | ||
| 9 | adminRouter := beego.NewNamespace("/v1", | 13 | adminRouter := beego.NewNamespace("/v1", |
| 10 | beego.NSNamespace("/auth", | 14 | beego.NSNamespace("/auth", |
| 11 | beego.NSRouter("/login", &controllers.AdminLoginController{}, "POST:Login"), | 15 | beego.NSRouter("/login", &controllers.AdminLoginController{}, "POST:Login"), |
| @@ -36,8 +40,7 @@ func init() { | @@ -36,8 +40,7 @@ func init() { | ||
| 36 | ), | 40 | ), |
| 37 | beego.NSNamespace("/order", | 41 | beego.NSNamespace("/order", |
| 38 | beego.NSRouter("/actual/list", &controllers.OrderInfoController{}, "POST:PageListOrderReal"), // 返归订单列表 | 42 | beego.NSRouter("/actual/list", &controllers.OrderInfoController{}, "POST:PageListOrderReal"), // 返归订单列表 |
| 39 | - beego.NSRouter("/actual/list/excel", &controllers.OrderInfoController{}, "POST:ListOrderForExcel"), // 导出excel | ||
| 40 | - beego.NSRouter("/actual/import/excel", &controllers.OrderInfoController{}, "POST:ImportOrderFromExcel"), // 导入订单数据 | 43 | + beego.NSRouter("/actual/list/excel", &controllers.OrderInfoController{}, "POST:ListOrderForExcel"), // 导出订单记录 |
| 41 | beego.NSRouter("/actual/detail", &controllers.OrderInfoController{}, "POST:GetOrderReal"), // 查看实际订单详情 | 44 | beego.NSRouter("/actual/detail", &controllers.OrderInfoController{}, "POST:GetOrderReal"), // 查看实际订单详情 |
| 42 | beego.NSRouter("/actual/del", &controllers.OrderInfoController{}, "POST:RemoveOrderReal"), // 删除实际订单 | 45 | beego.NSRouter("/actual/del", &controllers.OrderInfoController{}, "POST:RemoveOrderReal"), // 删除实际订单 |
| 43 | beego.NSRouter("/actual/update", &controllers.OrderInfoController{}, "POST:UpdateOrderReal"), // 新增实际订单 | 46 | beego.NSRouter("/actual/update", &controllers.OrderInfoController{}, "POST:UpdateOrderReal"), // 新增实际订单 |
| @@ -20,4 +20,7 @@ func init() { | @@ -20,4 +20,7 @@ func init() { | ||
| 20 | http.ServeFile(ctx.ResponseWriter, ctx.Request, constant.LOG_File) | 20 | http.ServeFile(ctx.ResponseWriter, ctx.Request, constant.LOG_File) |
| 21 | return | 21 | return |
| 22 | }) | 22 | }) |
| 23 | + | ||
| 24 | + // 静态文件路径映射 | ||
| 25 | + beego.SetStaticPath("/download", "download") | ||
| 23 | } | 26 | } |
vendor/github.com/beego/beego/v2/LICENSE
0 → 100644
| 1 | +Copyright 2014 astaxie | ||
| 2 | + | ||
| 3 | +Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | +you may not use this file except in compliance with the License. | ||
| 5 | +You may obtain a copy of the License at | ||
| 6 | + | ||
| 7 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | + | ||
| 9 | +Unless required by applicable law or agreed to in writing, software | ||
| 10 | +distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | +See the License for the specific language governing permissions and | ||
| 13 | +limitations under the License. |
| 1 | +# httplib | ||
| 2 | + | ||
| 3 | +httplib is an libs help you to curl remote url. | ||
| 4 | + | ||
| 5 | +# How to use? | ||
| 6 | + | ||
| 7 | +## GET | ||
| 8 | + | ||
| 9 | +you can use Get to crawl data. | ||
| 10 | + | ||
| 11 | + import "github.com/beego/beego/v2/httplib" | ||
| 12 | + | ||
| 13 | + str, err := httplib.Get("http://beego.me/").String() | ||
| 14 | + if err != nil { | ||
| 15 | + // error | ||
| 16 | + } | ||
| 17 | + fmt.Println(str) | ||
| 18 | + | ||
| 19 | +## POST | ||
| 20 | + | ||
| 21 | +POST data to remote url | ||
| 22 | + | ||
| 23 | + req := httplib.Post("http://beego.me/") | ||
| 24 | + req.Param("username","astaxie") | ||
| 25 | + req.Param("password","123456") | ||
| 26 | + str, err := req.String() | ||
| 27 | + if err != nil { | ||
| 28 | + // error | ||
| 29 | + } | ||
| 30 | + fmt.Println(str) | ||
| 31 | + | ||
| 32 | +## Set timeout | ||
| 33 | + | ||
| 34 | +The default timeout is `60` seconds, function prototype: | ||
| 35 | + | ||
| 36 | + SetTimeout(connectTimeout, readWriteTimeout time.Duration) | ||
| 37 | + | ||
| 38 | +Example: | ||
| 39 | + | ||
| 40 | + // GET | ||
| 41 | + httplib.Get("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second) | ||
| 42 | + | ||
| 43 | + // POST | ||
| 44 | + httplib.Post("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second) | ||
| 45 | + | ||
| 46 | +## Debug | ||
| 47 | + | ||
| 48 | +If you want to debug the request info, set the debug on | ||
| 49 | + | ||
| 50 | + httplib.Get("http://beego.me/").Debug(true) | ||
| 51 | + | ||
| 52 | +## Set HTTP Basic Auth | ||
| 53 | + | ||
| 54 | + str, err := Get("http://beego.me/").SetBasicAuth("user", "passwd").String() | ||
| 55 | + if err != nil { | ||
| 56 | + // error | ||
| 57 | + } | ||
| 58 | + fmt.Println(str) | ||
| 59 | + | ||
| 60 | +## Set HTTPS | ||
| 61 | + | ||
| 62 | +If request url is https, You can set the client support TSL: | ||
| 63 | + | ||
| 64 | + httplib.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) | ||
| 65 | + | ||
| 66 | +More info about the `tls.Config` please visit http://golang.org/pkg/crypto/tls/#Config | ||
| 67 | + | ||
| 68 | +## Set HTTP Version | ||
| 69 | + | ||
| 70 | +some servers need to specify the protocol version of HTTP | ||
| 71 | + | ||
| 72 | + httplib.Get("http://beego.me/").SetProtocolVersion("HTTP/1.1") | ||
| 73 | + | ||
| 74 | +## Set Cookie | ||
| 75 | + | ||
| 76 | +some http request need setcookie. So set it like this: | ||
| 77 | + | ||
| 78 | + cookie := &http.Cookie{} | ||
| 79 | + cookie.Name = "username" | ||
| 80 | + cookie.Value = "astaxie" | ||
| 81 | + httplib.Get("http://beego.me/").SetCookie(cookie) | ||
| 82 | + | ||
| 83 | +## Upload file | ||
| 84 | + | ||
| 85 | +httplib support mutil file upload, use `req.PostFile()` | ||
| 86 | + | ||
| 87 | + req := httplib.Post("http://beego.me/") | ||
| 88 | + req.Param("username","astaxie") | ||
| 89 | + req.PostFile("uploadfile1", "httplib.pdf") | ||
| 90 | + str, err := req.String() | ||
| 91 | + if err != nil { | ||
| 92 | + // error | ||
| 93 | + } | ||
| 94 | + fmt.Println(str) | ||
| 95 | + | ||
| 96 | +See godoc for further documentation and examples. | ||
| 97 | + | ||
| 98 | +* [godoc.org/github.com/beego/beego/v2/httplib](https://godoc.org/github.com/beego/beego/v2/httplib) |
| 1 | +// Copyright 2020 beego | ||
| 2 | +// | ||
| 3 | +// Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | +// you may not use this file except in compliance with the License. | ||
| 5 | +// You may obtain a copy of the License at | ||
| 6 | +// | ||
| 7 | +// http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | +// | ||
| 9 | +// Unless required by applicable law or agreed to in writing, software | ||
| 10 | +// distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | +// See the License for the specific language governing permissions and | ||
| 13 | +// limitations under the License. | ||
| 14 | + | ||
| 15 | +package httplib | ||
| 16 | + | ||
| 17 | +import ( | ||
| 18 | + "context" | ||
| 19 | + "net/http" | ||
| 20 | +) | ||
| 21 | + | ||
| 22 | +type FilterChain func(next Filter) Filter | ||
| 23 | + | ||
| 24 | +type Filter func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) |
| 1 | +// Copyright 2014 beego Author. All Rights Reserved. | ||
| 2 | +// | ||
| 3 | +// Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | +// you may not use this file except in compliance with the License. | ||
| 5 | +// You may obtain a copy of the License at | ||
| 6 | +// | ||
| 7 | +// http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | +// | ||
| 9 | +// Unless required by applicable law or agreed to in writing, software | ||
| 10 | +// distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | +// See the License for the specific language governing permissions and | ||
| 13 | +// limitations under the License. | ||
| 14 | + | ||
| 15 | +// Package httplib is used as http.Client | ||
| 16 | +// Usage: | ||
| 17 | +// | ||
| 18 | +// import "github.com/beego/beego/v2/httplib" | ||
| 19 | +// | ||
| 20 | +// b := httplib.Post("http://beego.me/") | ||
| 21 | +// b.Param("username","astaxie") | ||
| 22 | +// b.Param("password","123456") | ||
| 23 | +// b.PostFile("uploadfile1", "httplib.pdf") | ||
| 24 | +// b.PostFile("uploadfile2", "httplib.txt") | ||
| 25 | +// str, err := b.String() | ||
| 26 | +// if err != nil { | ||
| 27 | +// t.Fatal(err) | ||
| 28 | +// } | ||
| 29 | +// fmt.Println(str) | ||
| 30 | +// | ||
| 31 | +// more docs http://beego.me/docs/module/httplib.md | ||
| 32 | +package httplib | ||
| 33 | + | ||
| 34 | +import ( | ||
| 35 | + "bytes" | ||
| 36 | + "compress/gzip" | ||
| 37 | + "context" | ||
| 38 | + "crypto/tls" | ||
| 39 | + "encoding/json" | ||
| 40 | + "encoding/xml" | ||
| 41 | + "io" | ||
| 42 | + "io/ioutil" | ||
| 43 | + "log" | ||
| 44 | + "mime/multipart" | ||
| 45 | + "net" | ||
| 46 | + "net/http" | ||
| 47 | + "net/http/cookiejar" | ||
| 48 | + "net/http/httputil" | ||
| 49 | + "net/url" | ||
| 50 | + "os" | ||
| 51 | + "path" | ||
| 52 | + "strings" | ||
| 53 | + "sync" | ||
| 54 | + "time" | ||
| 55 | + | ||
| 56 | + "gopkg.in/yaml.v2" | ||
| 57 | +) | ||
| 58 | + | ||
| 59 | +var defaultSetting = BeegoHTTPSettings{ | ||
| 60 | + UserAgent: "beegoServer", | ||
| 61 | + ConnectTimeout: 60 * time.Second, | ||
| 62 | + ReadWriteTimeout: 60 * time.Second, | ||
| 63 | + Gzip: true, | ||
| 64 | + DumpBody: true, | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +var defaultCookieJar http.CookieJar | ||
| 68 | +var settingMutex sync.Mutex | ||
| 69 | + | ||
| 70 | +// it will be the last filter and execute request.Do | ||
| 71 | +var doRequestFilter = func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) { | ||
| 72 | + return req.doRequest(ctx) | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +// createDefaultCookie creates a global cookiejar to store cookies. | ||
| 76 | +func createDefaultCookie() { | ||
| 77 | + settingMutex.Lock() | ||
| 78 | + defer settingMutex.Unlock() | ||
| 79 | + defaultCookieJar, _ = cookiejar.New(nil) | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +// SetDefaultSetting overwrites default settings | ||
| 83 | +func SetDefaultSetting(setting BeegoHTTPSettings) { | ||
| 84 | + settingMutex.Lock() | ||
| 85 | + defer settingMutex.Unlock() | ||
| 86 | + defaultSetting = setting | ||
| 87 | +} | ||
| 88 | + | ||
| 89 | +// NewBeegoRequest returns *BeegoHttpRequest with specific method | ||
| 90 | +func NewBeegoRequest(rawurl, method string) *BeegoHTTPRequest { | ||
| 91 | + var resp http.Response | ||
| 92 | + u, err := url.Parse(rawurl) | ||
| 93 | + if err != nil { | ||
| 94 | + log.Println("Httplib:", err) | ||
| 95 | + } | ||
| 96 | + req := http.Request{ | ||
| 97 | + URL: u, | ||
| 98 | + Method: method, | ||
| 99 | + Header: make(http.Header), | ||
| 100 | + Proto: "HTTP/1.1", | ||
| 101 | + ProtoMajor: 1, | ||
| 102 | + ProtoMinor: 1, | ||
| 103 | + } | ||
| 104 | + return &BeegoHTTPRequest{ | ||
| 105 | + url: rawurl, | ||
| 106 | + req: &req, | ||
| 107 | + params: map[string][]string{}, | ||
| 108 | + files: map[string]string{}, | ||
| 109 | + setting: defaultSetting, | ||
| 110 | + resp: &resp, | ||
| 111 | + } | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +// Get returns *BeegoHttpRequest with GET method. | ||
| 115 | +func Get(url string) *BeegoHTTPRequest { | ||
| 116 | + return NewBeegoRequest(url, "GET") | ||
| 117 | +} | ||
| 118 | + | ||
| 119 | +// Post returns *BeegoHttpRequest with POST method. | ||
| 120 | +func Post(url string) *BeegoHTTPRequest { | ||
| 121 | + return NewBeegoRequest(url, "POST") | ||
| 122 | +} | ||
| 123 | + | ||
| 124 | +// Put returns *BeegoHttpRequest with PUT method. | ||
| 125 | +func Put(url string) *BeegoHTTPRequest { | ||
| 126 | + return NewBeegoRequest(url, "PUT") | ||
| 127 | +} | ||
| 128 | + | ||
| 129 | +// Delete returns *BeegoHttpRequest DELETE method. | ||
| 130 | +func Delete(url string) *BeegoHTTPRequest { | ||
| 131 | + return NewBeegoRequest(url, "DELETE") | ||
| 132 | +} | ||
| 133 | + | ||
| 134 | +// Head returns *BeegoHttpRequest with HEAD method. | ||
| 135 | +func Head(url string) *BeegoHTTPRequest { | ||
| 136 | + return NewBeegoRequest(url, "HEAD") | ||
| 137 | +} | ||
| 138 | + | ||
| 139 | +// BeegoHTTPSettings is the http.Client setting | ||
| 140 | +type BeegoHTTPSettings struct { | ||
| 141 | + ShowDebug bool | ||
| 142 | + UserAgent string | ||
| 143 | + ConnectTimeout time.Duration | ||
| 144 | + ReadWriteTimeout time.Duration | ||
| 145 | + TLSClientConfig *tls.Config | ||
| 146 | + Proxy func(*http.Request) (*url.URL, error) | ||
| 147 | + Transport http.RoundTripper | ||
| 148 | + CheckRedirect func(req *http.Request, via []*http.Request) error | ||
| 149 | + EnableCookie bool | ||
| 150 | + Gzip bool | ||
| 151 | + DumpBody bool | ||
| 152 | + Retries int // if set to -1 means will retry forever | ||
| 153 | + RetryDelay time.Duration | ||
| 154 | + FilterChains []FilterChain | ||
| 155 | +} | ||
| 156 | + | ||
| 157 | +// BeegoHTTPRequest provides more useful methods than http.Request for requesting a url. | ||
| 158 | +type BeegoHTTPRequest struct { | ||
| 159 | + url string | ||
| 160 | + req *http.Request | ||
| 161 | + params map[string][]string | ||
| 162 | + files map[string]string | ||
| 163 | + setting BeegoHTTPSettings | ||
| 164 | + resp *http.Response | ||
| 165 | + body []byte | ||
| 166 | + dump []byte | ||
| 167 | +} | ||
| 168 | + | ||
| 169 | +// GetRequest returns the request object | ||
| 170 | +func (b *BeegoHTTPRequest) GetRequest() *http.Request { | ||
| 171 | + return b.req | ||
| 172 | +} | ||
| 173 | + | ||
| 174 | +// Setting changes request settings | ||
| 175 | +func (b *BeegoHTTPRequest) Setting(setting BeegoHTTPSettings) *BeegoHTTPRequest { | ||
| 176 | + b.setting = setting | ||
| 177 | + return b | ||
| 178 | +} | ||
| 179 | + | ||
| 180 | +// SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password. | ||
| 181 | +func (b *BeegoHTTPRequest) SetBasicAuth(username, password string) *BeegoHTTPRequest { | ||
| 182 | + b.req.SetBasicAuth(username, password) | ||
| 183 | + return b | ||
| 184 | +} | ||
| 185 | + | ||
| 186 | +// SetEnableCookie sets enable/disable cookiejar | ||
| 187 | +func (b *BeegoHTTPRequest) SetEnableCookie(enable bool) *BeegoHTTPRequest { | ||
| 188 | + b.setting.EnableCookie = enable | ||
| 189 | + return b | ||
| 190 | +} | ||
| 191 | + | ||
| 192 | +// SetUserAgent sets User-Agent header field | ||
| 193 | +func (b *BeegoHTTPRequest) SetUserAgent(useragent string) *BeegoHTTPRequest { | ||
| 194 | + b.setting.UserAgent = useragent | ||
| 195 | + return b | ||
| 196 | +} | ||
| 197 | + | ||
| 198 | +// Debug sets show debug or not when executing request. | ||
| 199 | +func (b *BeegoHTTPRequest) Debug(isdebug bool) *BeegoHTTPRequest { | ||
| 200 | + b.setting.ShowDebug = isdebug | ||
| 201 | + return b | ||
| 202 | +} | ||
| 203 | + | ||
| 204 | +// Retries sets Retries times. | ||
| 205 | +// default is 0 (never retry) | ||
| 206 | +// -1 retry indefinitely (forever) | ||
| 207 | +// Other numbers specify the exact retry amount | ||
| 208 | +func (b *BeegoHTTPRequest) Retries(times int) *BeegoHTTPRequest { | ||
| 209 | + b.setting.Retries = times | ||
| 210 | + return b | ||
| 211 | +} | ||
| 212 | + | ||
| 213 | +// RetryDelay sets the time to sleep between reconnection attempts | ||
| 214 | +func (b *BeegoHTTPRequest) RetryDelay(delay time.Duration) *BeegoHTTPRequest { | ||
| 215 | + b.setting.RetryDelay = delay | ||
| 216 | + return b | ||
| 217 | +} | ||
| 218 | + | ||
| 219 | +// DumpBody sets the DumbBody field | ||
| 220 | +func (b *BeegoHTTPRequest) DumpBody(isdump bool) *BeegoHTTPRequest { | ||
| 221 | + b.setting.DumpBody = isdump | ||
| 222 | + return b | ||
| 223 | +} | ||
| 224 | + | ||
| 225 | +// DumpRequest returns the DumpRequest | ||
| 226 | +func (b *BeegoHTTPRequest) DumpRequest() []byte { | ||
| 227 | + return b.dump | ||
| 228 | +} | ||
| 229 | + | ||
| 230 | +// SetTimeout sets connect time out and read-write time out for BeegoRequest. | ||
| 231 | +func (b *BeegoHTTPRequest) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *BeegoHTTPRequest { | ||
| 232 | + b.setting.ConnectTimeout = connectTimeout | ||
| 233 | + b.setting.ReadWriteTimeout = readWriteTimeout | ||
| 234 | + return b | ||
| 235 | +} | ||
| 236 | + | ||
| 237 | +// SetTLSClientConfig sets TLS connection configuration if visiting HTTPS url. | ||
| 238 | +func (b *BeegoHTTPRequest) SetTLSClientConfig(config *tls.Config) *BeegoHTTPRequest { | ||
| 239 | + b.setting.TLSClientConfig = config | ||
| 240 | + return b | ||
| 241 | +} | ||
| 242 | + | ||
| 243 | +// Header adds header item string in request. | ||
| 244 | +func (b *BeegoHTTPRequest) Header(key, value string) *BeegoHTTPRequest { | ||
| 245 | + b.req.Header.Set(key, value) | ||
| 246 | + return b | ||
| 247 | +} | ||
| 248 | + | ||
| 249 | +// SetHost set the request host | ||
| 250 | +func (b *BeegoHTTPRequest) SetHost(host string) *BeegoHTTPRequest { | ||
| 251 | + b.req.Host = host | ||
| 252 | + return b | ||
| 253 | +} | ||
| 254 | + | ||
| 255 | +// SetProtocolVersion sets the protocol version for incoming requests. | ||
| 256 | +// Client requests always use HTTP/1.1. | ||
| 257 | +func (b *BeegoHTTPRequest) SetProtocolVersion(vers string) *BeegoHTTPRequest { | ||
| 258 | + if len(vers) == 0 { | ||
| 259 | + vers = "HTTP/1.1" | ||
| 260 | + } | ||
| 261 | + | ||
| 262 | + major, minor, ok := http.ParseHTTPVersion(vers) | ||
| 263 | + if ok { | ||
| 264 | + b.req.Proto = vers | ||
| 265 | + b.req.ProtoMajor = major | ||
| 266 | + b.req.ProtoMinor = minor | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + return b | ||
| 270 | +} | ||
| 271 | + | ||
| 272 | +// SetCookie adds a cookie to the request. | ||
| 273 | +func (b *BeegoHTTPRequest) SetCookie(cookie *http.Cookie) *BeegoHTTPRequest { | ||
| 274 | + b.req.Header.Add("Cookie", cookie.String()) | ||
| 275 | + return b | ||
| 276 | +} | ||
| 277 | + | ||
| 278 | +// SetTransport sets the transport field | ||
| 279 | +func (b *BeegoHTTPRequest) SetTransport(transport http.RoundTripper) *BeegoHTTPRequest { | ||
| 280 | + b.setting.Transport = transport | ||
| 281 | + return b | ||
| 282 | +} | ||
| 283 | + | ||
| 284 | +// SetProxy sets the HTTP proxy | ||
| 285 | +// example: | ||
| 286 | +// | ||
| 287 | +// func(req *http.Request) (*url.URL, error) { | ||
| 288 | +// u, _ := url.ParseRequestURI("http://127.0.0.1:8118") | ||
| 289 | +// return u, nil | ||
| 290 | +// } | ||
| 291 | +func (b *BeegoHTTPRequest) SetProxy(proxy func(*http.Request) (*url.URL, error)) *BeegoHTTPRequest { | ||
| 292 | + b.setting.Proxy = proxy | ||
| 293 | + return b | ||
| 294 | +} | ||
| 295 | + | ||
| 296 | +// SetCheckRedirect specifies the policy for handling redirects. | ||
| 297 | +// | ||
| 298 | +// If CheckRedirect is nil, the Client uses its default policy, | ||
| 299 | +// which is to stop after 10 consecutive requests. | ||
| 300 | +func (b *BeegoHTTPRequest) SetCheckRedirect(redirect func(req *http.Request, via []*http.Request) error) *BeegoHTTPRequest { | ||
| 301 | + b.setting.CheckRedirect = redirect | ||
| 302 | + return b | ||
| 303 | +} | ||
| 304 | + | ||
| 305 | +// SetFilters will use the filter as the invocation filters | ||
| 306 | +func (b *BeegoHTTPRequest) SetFilters(fcs ...FilterChain) *BeegoHTTPRequest { | ||
| 307 | + b.setting.FilterChains = fcs | ||
| 308 | + return b | ||
| 309 | +} | ||
| 310 | + | ||
| 311 | +// AddFilters adds filter | ||
| 312 | +func (b *BeegoHTTPRequest) AddFilters(fcs ...FilterChain) *BeegoHTTPRequest { | ||
| 313 | + b.setting.FilterChains = append(b.setting.FilterChains, fcs...) | ||
| 314 | + return b | ||
| 315 | +} | ||
| 316 | + | ||
| 317 | +// Param adds query param in to request. | ||
| 318 | +// params build query string as ?key1=value1&key2=value2... | ||
| 319 | +func (b *BeegoHTTPRequest) Param(key, value string) *BeegoHTTPRequest { | ||
| 320 | + if param, ok := b.params[key]; ok { | ||
| 321 | + b.params[key] = append(param, value) | ||
| 322 | + } else { | ||
| 323 | + b.params[key] = []string{value} | ||
| 324 | + } | ||
| 325 | + return b | ||
| 326 | +} | ||
| 327 | + | ||
| 328 | +// PostFile adds a post file to the request | ||
| 329 | +func (b *BeegoHTTPRequest) PostFile(formname, filename string) *BeegoHTTPRequest { | ||
| 330 | + b.files[formname] = filename | ||
| 331 | + return b | ||
| 332 | +} | ||
| 333 | + | ||
| 334 | +// Body adds request raw body. | ||
| 335 | +// Supports string and []byte. | ||
| 336 | +func (b *BeegoHTTPRequest) Body(data interface{}) *BeegoHTTPRequest { | ||
| 337 | + switch t := data.(type) { | ||
| 338 | + case string: | ||
| 339 | + bf := bytes.NewBufferString(t) | ||
| 340 | + b.req.Body = ioutil.NopCloser(bf) | ||
| 341 | + b.req.ContentLength = int64(len(t)) | ||
| 342 | + case []byte: | ||
| 343 | + bf := bytes.NewBuffer(t) | ||
| 344 | + b.req.Body = ioutil.NopCloser(bf) | ||
| 345 | + b.req.ContentLength = int64(len(t)) | ||
| 346 | + } | ||
| 347 | + return b | ||
| 348 | +} | ||
| 349 | + | ||
| 350 | +// XMLBody adds the request raw body encoded in XML. | ||
| 351 | +func (b *BeegoHTTPRequest) XMLBody(obj interface{}) (*BeegoHTTPRequest, error) { | ||
| 352 | + if b.req.Body == nil && obj != nil { | ||
| 353 | + byts, err := xml.Marshal(obj) | ||
| 354 | + if err != nil { | ||
| 355 | + return b, err | ||
| 356 | + } | ||
| 357 | + b.req.Body = ioutil.NopCloser(bytes.NewReader(byts)) | ||
| 358 | + b.req.ContentLength = int64(len(byts)) | ||
| 359 | + b.req.Header.Set("Content-Type", "application/xml") | ||
| 360 | + } | ||
| 361 | + return b, nil | ||
| 362 | +} | ||
| 363 | + | ||
| 364 | +// YAMLBody adds the request raw body encoded in YAML. | ||
| 365 | +func (b *BeegoHTTPRequest) YAMLBody(obj interface{}) (*BeegoHTTPRequest, error) { | ||
| 366 | + if b.req.Body == nil && obj != nil { | ||
| 367 | + byts, err := yaml.Marshal(obj) | ||
| 368 | + if err != nil { | ||
| 369 | + return b, err | ||
| 370 | + } | ||
| 371 | + b.req.Body = ioutil.NopCloser(bytes.NewReader(byts)) | ||
| 372 | + b.req.ContentLength = int64(len(byts)) | ||
| 373 | + b.req.Header.Set("Content-Type", "application/x+yaml") | ||
| 374 | + } | ||
| 375 | + return b, nil | ||
| 376 | +} | ||
| 377 | + | ||
| 378 | +// JSONBody adds the request raw body encoded in JSON. | ||
| 379 | +func (b *BeegoHTTPRequest) JSONBody(obj interface{}) (*BeegoHTTPRequest, error) { | ||
| 380 | + if b.req.Body == nil && obj != nil { | ||
| 381 | + byts, err := json.Marshal(obj) | ||
| 382 | + if err != nil { | ||
| 383 | + return b, err | ||
| 384 | + } | ||
| 385 | + b.req.Body = ioutil.NopCloser(bytes.NewReader(byts)) | ||
| 386 | + b.req.ContentLength = int64(len(byts)) | ||
| 387 | + b.req.Header.Set("Content-Type", "application/json") | ||
| 388 | + } | ||
| 389 | + return b, nil | ||
| 390 | +} | ||
| 391 | + | ||
| 392 | +func (b *BeegoHTTPRequest) buildURL(paramBody string) { | ||
| 393 | + // build GET url with query string | ||
| 394 | + if b.req.Method == "GET" && len(paramBody) > 0 { | ||
| 395 | + if strings.Contains(b.url, "?") { | ||
| 396 | + b.url += "&" + paramBody | ||
| 397 | + } else { | ||
| 398 | + b.url = b.url + "?" + paramBody | ||
| 399 | + } | ||
| 400 | + return | ||
| 401 | + } | ||
| 402 | + | ||
| 403 | + // build POST/PUT/PATCH url and body | ||
| 404 | + if (b.req.Method == "POST" || b.req.Method == "PUT" || b.req.Method == "PATCH" || b.req.Method == "DELETE") && b.req.Body == nil { | ||
| 405 | + // with files | ||
| 406 | + if len(b.files) > 0 { | ||
| 407 | + pr, pw := io.Pipe() | ||
| 408 | + bodyWriter := multipart.NewWriter(pw) | ||
| 409 | + go func() { | ||
| 410 | + for formname, filename := range b.files { | ||
| 411 | + fileWriter, err := bodyWriter.CreateFormFile(formname, filename) | ||
| 412 | + if err != nil { | ||
| 413 | + log.Println("Httplib:", err) | ||
| 414 | + } | ||
| 415 | + fh, err := os.Open(filename) | ||
| 416 | + if err != nil { | ||
| 417 | + log.Println("Httplib:", err) | ||
| 418 | + } | ||
| 419 | + // iocopy | ||
| 420 | + _, err = io.Copy(fileWriter, fh) | ||
| 421 | + fh.Close() | ||
| 422 | + if err != nil { | ||
| 423 | + log.Println("Httplib:", err) | ||
| 424 | + } | ||
| 425 | + } | ||
| 426 | + for k, v := range b.params { | ||
| 427 | + for _, vv := range v { | ||
| 428 | + bodyWriter.WriteField(k, vv) | ||
| 429 | + } | ||
| 430 | + } | ||
| 431 | + bodyWriter.Close() | ||
| 432 | + pw.Close() | ||
| 433 | + }() | ||
| 434 | + b.Header("Content-Type", bodyWriter.FormDataContentType()) | ||
| 435 | + b.req.Body = ioutil.NopCloser(pr) | ||
| 436 | + b.Header("Transfer-Encoding", "chunked") | ||
| 437 | + return | ||
| 438 | + } | ||
| 439 | + | ||
| 440 | + // with params | ||
| 441 | + if len(paramBody) > 0 { | ||
| 442 | + b.Header("Content-Type", "application/x-www-form-urlencoded") | ||
| 443 | + b.Body(paramBody) | ||
| 444 | + } | ||
| 445 | + } | ||
| 446 | +} | ||
| 447 | + | ||
| 448 | +func (b *BeegoHTTPRequest) getResponse() (*http.Response, error) { | ||
| 449 | + if b.resp.StatusCode != 0 { | ||
| 450 | + return b.resp, nil | ||
| 451 | + } | ||
| 452 | + resp, err := b.DoRequest() | ||
| 453 | + if err != nil { | ||
| 454 | + return nil, err | ||
| 455 | + } | ||
| 456 | + b.resp = resp | ||
| 457 | + return resp, nil | ||
| 458 | +} | ||
| 459 | + | ||
| 460 | +// DoRequest executes client.Do | ||
| 461 | +func (b *BeegoHTTPRequest) DoRequest() (resp *http.Response, err error) { | ||
| 462 | + return b.DoRequestWithCtx(context.Background()) | ||
| 463 | +} | ||
| 464 | + | ||
| 465 | +func (b *BeegoHTTPRequest) DoRequestWithCtx(ctx context.Context) (resp *http.Response, err error) { | ||
| 466 | + | ||
| 467 | + root := doRequestFilter | ||
| 468 | + if len(b.setting.FilterChains) > 0 { | ||
| 469 | + for i := len(b.setting.FilterChains) - 1; i >= 0; i-- { | ||
| 470 | + root = b.setting.FilterChains[i](root) | ||
| 471 | + } | ||
| 472 | + } | ||
| 473 | + return root(ctx, b) | ||
| 474 | +} | ||
| 475 | + | ||
| 476 | +func (b *BeegoHTTPRequest) doRequest(ctx context.Context) (resp *http.Response, err error) { | ||
| 477 | + var paramBody string | ||
| 478 | + if len(b.params) > 0 { | ||
| 479 | + var buf bytes.Buffer | ||
| 480 | + for k, v := range b.params { | ||
| 481 | + for _, vv := range v { | ||
| 482 | + buf.WriteString(url.QueryEscape(k)) | ||
| 483 | + buf.WriteByte('=') | ||
| 484 | + buf.WriteString(url.QueryEscape(vv)) | ||
| 485 | + buf.WriteByte('&') | ||
| 486 | + } | ||
| 487 | + } | ||
| 488 | + paramBody = buf.String() | ||
| 489 | + paramBody = paramBody[0 : len(paramBody)-1] | ||
| 490 | + } | ||
| 491 | + | ||
| 492 | + b.buildURL(paramBody) | ||
| 493 | + urlParsed, err := url.Parse(b.url) | ||
| 494 | + if err != nil { | ||
| 495 | + return nil, err | ||
| 496 | + } | ||
| 497 | + | ||
| 498 | + b.req.URL = urlParsed | ||
| 499 | + | ||
| 500 | + trans := b.setting.Transport | ||
| 501 | + | ||
| 502 | + if trans == nil { | ||
| 503 | + // create default transport | ||
| 504 | + trans = &http.Transport{ | ||
| 505 | + TLSClientConfig: b.setting.TLSClientConfig, | ||
| 506 | + Proxy: b.setting.Proxy, | ||
| 507 | + Dial: TimeoutDialer(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout), | ||
| 508 | + MaxIdleConnsPerHost: 100, | ||
| 509 | + } | ||
| 510 | + } else { | ||
| 511 | + // if b.transport is *http.Transport then set the settings. | ||
| 512 | + if t, ok := trans.(*http.Transport); ok { | ||
| 513 | + if t.TLSClientConfig == nil { | ||
| 514 | + t.TLSClientConfig = b.setting.TLSClientConfig | ||
| 515 | + } | ||
| 516 | + if t.Proxy == nil { | ||
| 517 | + t.Proxy = b.setting.Proxy | ||
| 518 | + } | ||
| 519 | + if t.Dial == nil { | ||
| 520 | + t.Dial = TimeoutDialer(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout) | ||
| 521 | + } | ||
| 522 | + } | ||
| 523 | + } | ||
| 524 | + | ||
| 525 | + var jar http.CookieJar | ||
| 526 | + if b.setting.EnableCookie { | ||
| 527 | + if defaultCookieJar == nil { | ||
| 528 | + createDefaultCookie() | ||
| 529 | + } | ||
| 530 | + jar = defaultCookieJar | ||
| 531 | + } | ||
| 532 | + | ||
| 533 | + client := &http.Client{ | ||
| 534 | + Transport: trans, | ||
| 535 | + Jar: jar, | ||
| 536 | + } | ||
| 537 | + | ||
| 538 | + if b.setting.UserAgent != "" && b.req.Header.Get("User-Agent") == "" { | ||
| 539 | + b.req.Header.Set("User-Agent", b.setting.UserAgent) | ||
| 540 | + } | ||
| 541 | + | ||
| 542 | + if b.setting.CheckRedirect != nil { | ||
| 543 | + client.CheckRedirect = b.setting.CheckRedirect | ||
| 544 | + } | ||
| 545 | + | ||
| 546 | + if b.setting.ShowDebug { | ||
| 547 | + dump, err := httputil.DumpRequest(b.req, b.setting.DumpBody) | ||
| 548 | + if err != nil { | ||
| 549 | + log.Println(err.Error()) | ||
| 550 | + } | ||
| 551 | + b.dump = dump | ||
| 552 | + } | ||
| 553 | + // retries default value is 0, it will run once. | ||
| 554 | + // retries equal to -1, it will run forever until success | ||
| 555 | + // retries is setted, it will retries fixed times. | ||
| 556 | + // Sleeps for a 400ms between calls to reduce spam | ||
| 557 | + for i := 0; b.setting.Retries == -1 || i <= b.setting.Retries; i++ { | ||
| 558 | + resp, err = client.Do(b.req) | ||
| 559 | + if err == nil { | ||
| 560 | + break | ||
| 561 | + } | ||
| 562 | + time.Sleep(b.setting.RetryDelay) | ||
| 563 | + } | ||
| 564 | + return resp, err | ||
| 565 | +} | ||
| 566 | + | ||
| 567 | +// String returns the body string in response. | ||
| 568 | +// Calls Response inner. | ||
| 569 | +func (b *BeegoHTTPRequest) String() (string, error) { | ||
| 570 | + data, err := b.Bytes() | ||
| 571 | + if err != nil { | ||
| 572 | + return "", err | ||
| 573 | + } | ||
| 574 | + | ||
| 575 | + return string(data), nil | ||
| 576 | +} | ||
| 577 | + | ||
| 578 | +// Bytes returns the body []byte in response. | ||
| 579 | +// Calls Response inner. | ||
| 580 | +func (b *BeegoHTTPRequest) Bytes() ([]byte, error) { | ||
| 581 | + if b.body != nil { | ||
| 582 | + return b.body, nil | ||
| 583 | + } | ||
| 584 | + resp, err := b.getResponse() | ||
| 585 | + if err != nil { | ||
| 586 | + return nil, err | ||
| 587 | + } | ||
| 588 | + if resp.Body == nil { | ||
| 589 | + return nil, nil | ||
| 590 | + } | ||
| 591 | + defer resp.Body.Close() | ||
| 592 | + if b.setting.Gzip && resp.Header.Get("Content-Encoding") == "gzip" { | ||
| 593 | + reader, err := gzip.NewReader(resp.Body) | ||
| 594 | + if err != nil { | ||
| 595 | + return nil, err | ||
| 596 | + } | ||
| 597 | + b.body, err = ioutil.ReadAll(reader) | ||
| 598 | + return b.body, err | ||
| 599 | + } | ||
| 600 | + b.body, err = ioutil.ReadAll(resp.Body) | ||
| 601 | + return b.body, err | ||
| 602 | +} | ||
| 603 | + | ||
| 604 | +// ToFile saves the body data in response to one file. | ||
| 605 | +// Calls Response inner. | ||
| 606 | +func (b *BeegoHTTPRequest) ToFile(filename string) error { | ||
| 607 | + resp, err := b.getResponse() | ||
| 608 | + if err != nil { | ||
| 609 | + return err | ||
| 610 | + } | ||
| 611 | + if resp.Body == nil { | ||
| 612 | + return nil | ||
| 613 | + } | ||
| 614 | + defer resp.Body.Close() | ||
| 615 | + err = pathExistAndMkdir(filename) | ||
| 616 | + if err != nil { | ||
| 617 | + return err | ||
| 618 | + } | ||
| 619 | + f, err := os.Create(filename) | ||
| 620 | + if err != nil { | ||
| 621 | + return err | ||
| 622 | + } | ||
| 623 | + defer f.Close() | ||
| 624 | + _, err = io.Copy(f, resp.Body) | ||
| 625 | + return err | ||
| 626 | +} | ||
| 627 | + | ||
| 628 | +// Check if the file directory exists. If it doesn't then it's created | ||
| 629 | +func pathExistAndMkdir(filename string) (err error) { | ||
| 630 | + filename = path.Dir(filename) | ||
| 631 | + _, err = os.Stat(filename) | ||
| 632 | + if err == nil { | ||
| 633 | + return nil | ||
| 634 | + } | ||
| 635 | + if os.IsNotExist(err) { | ||
| 636 | + err = os.MkdirAll(filename, os.ModePerm) | ||
| 637 | + if err == nil { | ||
| 638 | + return nil | ||
| 639 | + } | ||
| 640 | + } | ||
| 641 | + return err | ||
| 642 | +} | ||
| 643 | + | ||
| 644 | +// ToJSON returns the map that marshals from the body bytes as json in response. | ||
| 645 | +// Calls Response inner. | ||
| 646 | +func (b *BeegoHTTPRequest) ToJSON(v interface{}) error { | ||
| 647 | + data, err := b.Bytes() | ||
| 648 | + if err != nil { | ||
| 649 | + return err | ||
| 650 | + } | ||
| 651 | + return json.Unmarshal(data, v) | ||
| 652 | +} | ||
| 653 | + | ||
| 654 | +// ToXML returns the map that marshals from the body bytes as xml in response . | ||
| 655 | +// Calls Response inner. | ||
| 656 | +func (b *BeegoHTTPRequest) ToXML(v interface{}) error { | ||
| 657 | + data, err := b.Bytes() | ||
| 658 | + if err != nil { | ||
| 659 | + return err | ||
| 660 | + } | ||
| 661 | + return xml.Unmarshal(data, v) | ||
| 662 | +} | ||
| 663 | + | ||
| 664 | +// ToYAML returns the map that marshals from the body bytes as yaml in response . | ||
| 665 | +// Calls Response inner. | ||
| 666 | +func (b *BeegoHTTPRequest) ToYAML(v interface{}) error { | ||
| 667 | + data, err := b.Bytes() | ||
| 668 | + if err != nil { | ||
| 669 | + return err | ||
| 670 | + } | ||
| 671 | + return yaml.Unmarshal(data, v) | ||
| 672 | +} | ||
| 673 | + | ||
| 674 | +// Response executes request client gets response manually. | ||
| 675 | +func (b *BeegoHTTPRequest) Response() (*http.Response, error) { | ||
| 676 | + return b.getResponse() | ||
| 677 | +} | ||
| 678 | + | ||
| 679 | +// TimeoutDialer returns functions of connection dialer with timeout settings for http.Transport Dial field. | ||
| 680 | +func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) { | ||
| 681 | + return func(netw, addr string) (net.Conn, error) { | ||
| 682 | + conn, err := net.DialTimeout(netw, addr, cTimeout) | ||
| 683 | + if err != nil { | ||
| 684 | + return nil, err | ||
| 685 | + } | ||
| 686 | + err = conn.SetDeadline(time.Now().Add(rwTimeout)) | ||
| 687 | + return conn, err | ||
| 688 | + } | ||
| 689 | +} |
| @@ -23,6 +23,9 @@ github.com/astaxie/beego/plugins/cors | @@ -23,6 +23,9 @@ github.com/astaxie/beego/plugins/cors | ||
| 23 | github.com/astaxie/beego/session | 23 | github.com/astaxie/beego/session |
| 24 | github.com/astaxie/beego/toolbox | 24 | github.com/astaxie/beego/toolbox |
| 25 | github.com/astaxie/beego/utils | 25 | github.com/astaxie/beego/utils |
| 26 | +# github.com/beego/beego/v2 v2.0.1 | ||
| 27 | +## explicit | ||
| 28 | +github.com/beego/beego/v2/client/httplib | ||
| 26 | # github.com/beorn7/perks v1.0.1 | 29 | # github.com/beorn7/perks v1.0.1 |
| 27 | github.com/beorn7/perks/quantile | 30 | github.com/beorn7/perks/quantile |
| 28 | # github.com/bsm/sarama-cluster v2.1.15+incompatible | 31 | # github.com/bsm/sarama-cluster v2.1.15+incompatible |
| @@ -283,7 +286,7 @@ golang.org/x/text/secure/bidirule | @@ -283,7 +286,7 @@ golang.org/x/text/secure/bidirule | ||
| 283 | golang.org/x/text/transform | 286 | golang.org/x/text/transform |
| 284 | golang.org/x/text/unicode/bidi | 287 | golang.org/x/text/unicode/bidi |
| 285 | golang.org/x/text/unicode/norm | 288 | golang.org/x/text/unicode/norm |
| 286 | -# golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 | 289 | +# golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 |
| 287 | golang.org/x/xerrors | 290 | golang.org/x/xerrors |
| 288 | golang.org/x/xerrors/internal | 291 | golang.org/x/xerrors/internal |
| 289 | # google.golang.org/protobuf v1.25.0 | 292 | # google.golang.org/protobuf v1.25.0 |
-
请 注册 或 登录 后发表评论