diff --git a/mallinkAdmin/src/main/java/com/iformall/config/ShiroConfig.java b/mallinkAdmin/src/main/java/com/iformall/config/ShiroConfig.java index b4d7b4d5b..0185019ee 100644 --- a/mallinkAdmin/src/main/java/com/iformall/config/ShiroConfig.java +++ b/mallinkAdmin/src/main/java/com/iformall/config/ShiroConfig.java @@ -149,6 +149,8 @@ public class ShiroConfig { //商场初始化init filterChainDefinitionMap.put("/wxProjectConfig/**", "anon"); +// filterChainDefinitionMap.put("/wxCoupon/goods/**", "anon"); + // //test // filterChainDefinitionMap.put("/merchantPoi/spuSync", "anon"); // filterChainDefinitionMap.put("/merchantPoi/spuGet", "anon"); diff --git a/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponController.java b/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponController.java index 61b790b8c..9dc47bd09 100644 --- a/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponController.java +++ b/mallinkAdmin/src/main/java/com/iformall/controller/market/WxCouponController.java @@ -14,13 +14,10 @@ import com.iformall.domain.po.WxCouponPassword; import com.iformall.domain.po.WxPayAccount; import com.iformall.domain.po.base.TenantEntity; import com.iformall.domain.vo.WxCouponStatisVo; +import com.iformall.douyin.web.bean.GoodsTemplateGet; import com.iformall.enums.*; import com.iformall.mapper.WxCouponChannelMapper; -import com.iformall.service.WxCouponPasswordService; -import com.iformall.service.WxCouponService; -import com.iformall.service.WxFlowService; -import com.iformall.service.WxMallService; -import com.iformall.service.WxPayAccountService; +import com.iformall.service.*; import com.iformall.service.util.CouponCacheUtils; import com.iformall.utils.DateUtils; import com.iformall.utils.RedisLock; @@ -29,6 +26,7 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; +import me.chanjar.weixin.common.error.WxErrorException; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.map.HashedMap; import org.apache.commons.lang3.StringUtils; @@ -60,6 +58,8 @@ public class WxCouponController extends BaseController { @Autowired private WxMallService wxMallService; @Autowired + private TtMerchantPoiService ttMerchantPoiService; + @Autowired RedisLock redisLock; @Autowired @@ -543,4 +543,23 @@ public class WxCouponController extends BaseController { return result; } + @ApiOperation("根据类目获取商品模板") + @GetMapping("/goods/getTemplate") + @ApiImplicitParam(name = "id", value = "id", dataType = "Long", paramType = "query", required = true) + @SystemControllerLog(description = "根据类目获取商品模板") + public ResultData getGoodsTemplate(Integer categoryId,Integer productType) { + logger.debug("[" + getIpAddr() + "] WxCouponController::getGoodsTemplate"); + if(productType == null){ + productType = 1; + } + try { + GoodsTemplateGet goodsTemplateGet = ttMerchantPoiService.getTtWebService(getTenantInfo()).getGoodsService().templateGet(categoryId, productType); + return new ResultData(goodsTemplateGet); + } catch (WxErrorException e) { + e.printStackTrace(); + return new ResultData(ErrorCode.SYS_SERVER_ERROR.getCode(),e.getMessage()); + } + + } + } diff --git a/mallinkCApi/src/main/java/com/iformall/controller/WxOrderController.java b/mallinkCApi/src/main/java/com/iformall/controller/WxOrderController.java index 833fb49f0..42bde72af 100644 --- a/mallinkCApi/src/main/java/com/iformall/controller/WxOrderController.java +++ b/mallinkCApi/src/main/java/com/iformall/controller/WxOrderController.java @@ -1,5 +1,7 @@ package com.iformall.controller; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader; import com.github.pagehelper.PageInfo; @@ -13,16 +15,22 @@ import com.iformall.domain.dto.OrderSaveDto; import com.iformall.domain.dto.PlatPushOrderSaveDto; import com.iformall.domain.po.*; import com.iformall.domain.po.base.BaseEntity; +import com.iformall.domain.po.tt.TtCUser; import com.iformall.domain.vo.WxCouponCVo; import com.iformall.domain.vo.WxOrderCouponPressVo; import com.iformall.domain.vo.WxOrderCouponVo; +import com.iformall.douyin.pay.TtPayService; +import com.iformall.douyin.pay.exception.TtPayException; +import com.iformall.douyin.payv2.result.CreateOrderCallback; import com.iformall.enums.*; import com.iformall.exception.MallinkException; import com.iformall.interceptor.BodyReaderHttpServletRequestWrapper; import com.iformall.service.*; +import com.iformall.service.cuser.CUserServiceFactory; import com.iformall.service.order.OrderFactory; import com.iformall.service.order.entity.WxComposeOrder; import com.iformall.utils.Constant; +import com.iformall.utils.MaUtil; import com.iformall.utils.RedisLock; import io.swagger.annotations.Api; @@ -55,6 +63,9 @@ public class WxOrderController extends BaseController { @Autowired private WxCouponService wxCouponService; + @Autowired + private CUserServiceFactory cuserFactory; + @Autowired private WxCUserBasicInfoService wxCUserBasicInfoService; @@ -76,6 +87,9 @@ public class WxOrderController extends BaseController { @Autowired private OrderFactory orderFactory; + @Autowired + private MaUtil maUtil; + @Autowired @Qualifier("couponDetailRedisTemplate") RedisTemplate cdRedisTemplate; @@ -144,6 +158,8 @@ public class WxOrderController extends BaseController { @ApiOperation(value = "抖音支付2.0与下单回调推送订单", notes = "{\"couponChannelId\":\"String\",\"couponId\":\"String\",\"press\":\"String\",\"orderGroupId\":\"String\",\"formId\":\"String\"}") @PostMapping("douyinPushOrder") public Map douyinPushOrder(HttpServletRequest request) { + Map map = new HashMap(); + SignatureHeader header = new SignatureHeader(); header.setTimeStamp(request.getHeader("Byte-Timestamp")); header.setNonce(request.getHeader("Byte-Nonce-Str")); @@ -154,27 +170,105 @@ public class WxOrderController extends BaseController { String body = ((BodyReaderHttpServletRequestWrapper) request).getBody(); logger.info("支付2.0预下单回调---body{}"+body); - Map map = new HashMap(); - map.put("err_no",1000); - map.put("err_tips","库存不足"); - return map; + JSONObject jsonObject = JSONObject.parseObject(body); + String app_id = jsonObject.getString("app_id"); + String open_id = jsonObject.getString("open_id"); + //验证app + WxAppinfo appinfo = wxAppinfoService.getByAppId(app_id); + if(appinfo == null || !EnumAppPlat.TOUTIAO.getCode().equals(appinfo.getPlat()) + || !EnumAppType.C.getCode().equals(appinfo.getType())){ + map.put("err_no",ErrorCode.APP_ID_NOT_FOUND.getCode()); + map.put("err_tips",ErrorCode.APP_ID_NOT_FOUND.getMessage()); + return map; + } + WxPayAccount payAccount = wxPayAccountService.getById(appinfo.getPayId()); + if(payAccount == null){ + map.put("err_no",ErrorCode.API_KEY_NOT_FOUND.getCode()); + map.put("err_tips","未找到支付配置"); + return map; + } + //验证用户 + Long memberId = null; + TtCUser cuser = (TtCUser) cuserFactory.getCUserService(EnumAppPlat.TOUTIAO).getByOpenId(open_id, appinfo.getTenantId()); + if(cuser != null && cuser.getUserId() != null){ + memberId = cuser.getUserId(); + } + if(memberId == null){ + map.put("err_no",ErrorCode.USER_NOT_MEMBER.getCode()); + map.put("err_tips",ErrorCode.USER_NOT_MEMBER.getMessage()); + return map; + } -// Long memberId; -// try { -// memberId = getMemberId(); -// } catch (Exception e) { -// return new ResultData(Result.ERROR,e.getMessage()); -// } -// -// List list = new ArrayList<>(); -// PlatPushOrderSaveDto dto = new PlatPushOrderSaveDto(); -// /** -// * TODO 从抖音推送的订单中取信息,每个订单里面有extParam,用来放第三方平台匹配的参数信息 -// * 注意,wx_batch_order中要存allExtParam, wx_order,wx_coupon_order中存储每个订单的参数信息,需要自己根据总参数信息进行拆分 -// */ -// list.add(dto); -// String allExtParam = "[]"; -// return wxOrderService.platPushSaveOrder(false,EnumComposeOrder.ONE_NUMBER_ORDER_BATCH,allExtParam,list,memberId,getPayWay(),getTenantInfo()); + try { + TtPayService ttPayService = maUtil.getTtPayService(appinfo, payAccount); + CreateOrderCallback createOrderCallback = ttPayService.parseOrderNotifyV2Result(body, header); + JSONObject allExtParam = new JSONObject(); + allExtParam.put("order_id",createOrderCallback.getOrderId()); + allExtParam.put("total_amount",createOrderCallback.getTotalAmount()); + allExtParam.put("discount",createOrderCallback.getDiscount()); + allExtParam.put("open_id",createOrderCallback.getOpenId()); + + List list = new ArrayList<>(); + for (CreateOrderCallback.Good good:createOrderCallback.getGoods()) { + PlatPushOrderSaveDto dto = new PlatPushOrderSaveDto(); + dto.setCouponChannelId(Long.parseLong(good.getGoodsId())); + dto.setCount(good.getQuantity()); + dto.setExtParam(good.getItemOrderInfoList().toString()); + list.add(dto); + } + + ResultData resultData = wxOrderService.platPushSaveOrder(false, EnumComposeOrder.ONE_NUMBER_ORDER_BATCH, allExtParam.toString(), list, memberId, EnumPayWay.PAY_WAY_TT, getTenantInfo()); + if(resultData.code == 200){ + WxComposeOrder order = (WxComposeOrder) resultData.data; + Map data = new HashMap<>(); + data.put("out_order_no",order.getMainOrderId()); + data.put("order_entry_schema",getOrderEntrySchema(order.getMainOrderId())); + List> goodsValid = new ArrayList<>(); + for (Long goodId:order.getCouponChannelMap().keySet()) { + Map goodsValidMap = new HashMap<>(); + goodsValidMap.put("goods_id",goodId.toString()); + WxCouponChannel couponChannel = order.getCouponChannelMap().get(goodId); + WxCoupon wxCoupon = order.getCouponMap().get(couponChannel.getCouponId()); + if(EnumCouponValidType.BETWEEN_TWO_TIME.getCode().equals(wxCoupon.getValidType())){ + goodsValidMap.put("valid_start_time",wxCoupon.getValidStartDate().getTime()); + goodsValidMap.put("valid_end_time",wxCoupon.getValidEndDate().getTime()); + }else{ + goodsValidMap.put("valid_duration",(long)wxCoupon.getValidDays()*24*3600*1000); + } + goodsValid.add(goodsValidMap); + } + data.put("order_valid_time",goodsValid); + map.put("data",data); + map.put("err_no",0); + map.put("err_tips",resultData.message); + return map; + }else{ + map.put("err_no",resultData.code); + map.put("err_tips",resultData.message); + return map; + } + + } catch (TtPayException e) { + logger.error(e.getMessage()); + map.put("err_no",ErrorCode.SYS_BEAN_EMPTY_PROPERTY_ERROR.getCode()); + map.put("err_tips",e.getMessage()); + return map; + } catch (Exception e){ + logger.error(e.getMessage()); + map.put("err_no",ErrorCode.SYS_SERVER_ERROR.getCode()); + map.put("err_tips",e.getMessage()); + return map; + } + } + + private Map getOrderEntrySchema(Long batchOrderId){ + Map map = new HashMap<>(); + map.put("path", Constant.mainPageUrl); + Map paramMap = new HashMap<>(); + paramMap.put("type","dt"); + paramMap.put("orderId",batchOrderId); + map.put("params", JSON.toJSONString(paramMap)); + return map; } diff --git a/mallinkCallback/src/main/java/com/iformall/config/ShiroConfig.java b/mallinkCallback/src/main/java/com/iformall/config/ShiroConfig.java index 32334bcee..69f7b4c13 100644 --- a/mallinkCallback/src/main/java/com/iformall/config/ShiroConfig.java +++ b/mallinkCallback/src/main/java/com/iformall/config/ShiroConfig.java @@ -112,6 +112,7 @@ public class ShiroConfig { filterChainDefinitionMap.put("/alipay/notify/**", "anon"); filterChainDefinitionMap.put("/ttPay/notify/**", "anon"); + filterChainDefinitionMap.put("/ttweb/notify/**", "anon"); filterChainDefinitionMap.put("/jinmao/notify/**", "anon"); diff --git a/mallinkCallback/src/main/java/com/iformall/controller/callback/TtWebController.java b/mallinkCallback/src/main/java/com/iformall/controller/callback/TtWebController.java new file mode 100644 index 000000000..ed5987298 --- /dev/null +++ b/mallinkCallback/src/main/java/com/iformall/controller/callback/TtWebController.java @@ -0,0 +1,59 @@ +package com.iformall.controller.callback; + +import com.alibaba.fastjson.JSONObject; +import com.iformall.controller.base.BaseController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/ttweb/notify") +public class TtWebController extends BaseController { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + + /** + * { + * "event": "verify_webhook", + * "client_key": "", + * "content": { + * "challenge": 12345 + * } + * } + */ + @PostMapping(value = "/notice") + @ResponseBody + public Map notice( @RequestBody Map parameterMap,HttpServletRequest request){ + logger.debug("[" + getIpAddr() + "] TtOrderCallbackController::notice"); + Map resultMap = new HashMap<>(); + +// String body = ((BodyReaderHttpServletRequestWrapper) request).getBody(); + logger.info("抖音开放平台通知-----parameterMap{}"+parameterMap); + try { + String header = request.getHeader("X-Douyin-Signature"); + logger.info("抖音开放平台通知-----header.X-Douyin-Signature{}"+parameterMap); +// Map parameterMap = JSONObject.parseObject(body, Map.class); + + String event = (String) parameterMap.get("event"); + logger.info("抖音开放平台通知-----event{}"+event); + String client_key = (String) parameterMap.get("client_key"); + logger.info("抖音开放平台通知-----client_key{}"+client_key); + JSONObject content = (JSONObject) parameterMap.get("content"); + logger.info("抖音开放平台通知-----content{}"+content.toString()); + String challenge = content.getString("challenge"); + logger.info("抖音开放平台通知-----content.challenge{}"+challenge); + + resultMap.put("challenge",challenge); + return resultMap; + } catch (Exception e){ + logger.error(e.getMessage()); + resultMap.put("err_tips","error"); + return resultMap; + } + } +} diff --git a/mallinkService/src/main/java/com/iformall/domain/dto/PlatPushOrderSaveDto.java b/mallinkService/src/main/java/com/iformall/domain/dto/PlatPushOrderSaveDto.java index f3c7cd65a..04d4a6edb 100644 --- a/mallinkService/src/main/java/com/iformall/domain/dto/PlatPushOrderSaveDto.java +++ b/mallinkService/src/main/java/com/iformall/domain/dto/PlatPushOrderSaveDto.java @@ -24,7 +24,7 @@ public class PlatPushOrderSaveDto implements Serializable { Integer shippingType = 0;//EnumOrderShopingType【传入参数】配送类型 UserBasicInfoAddress address;//【传入参数】配送地址 - String extParam;//【传入参数】json,额外的信息,可能每个平台不一样 + String extParam;//数组格式长度与数量一致(一个券一个订单时)【传入参数】json,额外的信息,可能每个平台不一样 WxCoupon wxCoupon;//【非传入参数】。 WxCouponChannel wxCouponChannel;//【非传入参数】。 diff --git a/mallinkService/src/main/java/com/iformall/douyin/payv2/result/CreateOrderCallback.java b/mallinkService/src/main/java/com/iformall/douyin/payv2/result/CreateOrderCallback.java index fff1db2dc..5e75ea8cc 100644 --- a/mallinkService/src/main/java/com/iformall/douyin/payv2/result/CreateOrderCallback.java +++ b/mallinkService/src/main/java/com/iformall/douyin/payv2/result/CreateOrderCallback.java @@ -195,6 +195,32 @@ public class CreateOrderCallback implements Serializable { @SerializedName(value = "goods_id_type") private Integer goodsIdType; + /** + * 是 + * 商品item_order信息,详情见 item_order_info_list部分 + */ + @SerializedName(value = "item_order_info_list") + protected List itemOrderInfoList; + + } + + @Data + @NoArgsConstructor + public static class ItemOrderInfo implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * item单id + */ + @SerializedName(value = "item_order_id") + private String itemOrderId; + + /** + * 商品优惠后价格 + */ + @SerializedName(value = "price") + private Integer price; + } } diff --git a/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsGetRequestExecutor.java b/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsGetRequestExecutor.java new file mode 100644 index 000000000..2c610be23 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsGetRequestExecutor.java @@ -0,0 +1,108 @@ +package com.iformall.douyin.web.api; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import me.chanjar.weixin.common.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * . + * + * @author ecoolper + * @date 2017/5/4 + */ +public class TtWebGoodsGetRequestExecutor implements RequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + protected RequestHttp requestHttp; + + public TtWebGoodsGetRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } + + @Override + public void execute(String uri, String data, ResponseHandler handler, WxType wxType) throws WxErrorException, IOException { + handler.handle(this.execute(uri, data, wxType)); + } + + @Override + public String execute(String uri, String queryParam, WxType wxType) throws WxErrorException, IOException { + + String access_token = handleUrl(uri); + if(StringUtils.isBlank(access_token)){ + WxError wxError = WxError.fromJson("{\n" + + " \"description\": \"未找到access_token\",\n" + + " \"error_code\": -1\n" + + " }"); + throw new WxErrorException(wxError); + } + + if (queryParam != null) { + if (uri.indexOf('?') == -1) { + uri += '?'; + } + uri += uri.endsWith("?") ? queryParam : '&' + queryParam; + } + + HttpGet httpGet = new HttpGet(uri); + httpGet.addHeader("Content-Type","application/json"); + httpGet.addHeader("access-token",access_token); + logger.info("get请求地址uri{}"+uri); + logger.info("header-----access_token{}"+access_token); + + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpGet.setConfig(config); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpGet)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + logger.info("response{}"+responseContent); + return responseContent; +// JSONObject jsonObject = JSON.parseObject(responseContent); +// JSONObject data = jsonObject.getJSONObject("data"); +// WxError error = WxError.fromJson(data.toJSONString()); +// if (error.getErrorCode() != 0) { +// throw new WxErrorException(error); +// } +// return data.toString(); + } finally { + httpGet.releaseConnection(); + } + } + + //去除链接中access_token 并返回 + private String handleUrl(String url){ + String access_token = null; + Pattern pXM = Pattern.compile("access_token=([^&]*)"); + Matcher mXM = pXM.matcher(url); + int i = 0; + while (mXM.find()) { + i++; + access_token = mXM.group(1); + } + if(i > 1){ + return null; + } +// url = url.replaceAll("&?access_token=[^&]*",""); + return access_token; + } + +} diff --git a/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsPostRequestExecutor.java b/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsPostRequestExecutor.java new file mode 100644 index 000000000..f42e7b460 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsPostRequestExecutor.java @@ -0,0 +1,117 @@ +package com.iformall.douyin.web.api; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import me.chanjar.weixin.common.WxType; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.http.RequestExecutor; +import me.chanjar.weixin.common.util.http.RequestHttp; +import me.chanjar.weixin.common.util.http.ResponseHandler; +import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.Consts; +import org.apache.http.HttpHost; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * . + * + * @author ecoolper + * @date 2017/5/4 + */ +public class TtWebGoodsPostRequestExecutor implements RequestExecutor { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + protected RequestHttp requestHttp; + + public TtWebGoodsPostRequestExecutor(RequestHttp requestHttp) { + this.requestHttp = requestHttp; + } + + @Override + public void execute(String uri, String data, ResponseHandler handler, WxType wxType) + throws WxErrorException, IOException { + handler.handle(this.execute(uri, data, wxType)); + } + + @Override + public String execute(String uri, String postEntity, WxType wxType) throws WxErrorException, IOException { + + String access_token = handleUrl(uri); + if(StringUtils.isBlank(access_token)){ + WxError wxError = WxError.fromJson("{\n" + + " \"description\": \"未找到access_token\",\n" + + " \"error_code\": -1\n" + + " }"); + throw new WxErrorException(wxError); + } + + HttpPost httpPost = new HttpPost(uri); + httpPost.addHeader("Content-Type","application/json"); + httpPost.addHeader("access-token",access_token); + logger.info("post请求地址uri{}"+uri); + logger.info("header-----access_token{}"+access_token); + logger.info("请求参数{}"+postEntity); + + if (requestHttp.getRequestHttpProxy() != null) { + RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build(); + httpPost.setConfig(config); + } + + if (postEntity != null) { + StringEntity entity = new StringEntity(postEntity, Consts.UTF_8); + entity.setContentType("application/json; charset=utf-8"); + httpPost.setEntity(entity); + } + + try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) { + String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response); + logger.info("response{}"+responseContent); + if (responseContent.isEmpty()) { + throw new WxErrorException(WxError.builder().errorCode(9999).errorMsg("无响应内容").build()); + } + return responseContent; + +// if (responseContent.startsWith("")) { +// //xml格式输出直接返回 +// return responseContent; +// } +// JSONObject jsonObject = JSON.parseObject(responseContent); +// JSONObject data = jsonObject.getJSONObject("data"); +// WxError error = WxError.fromJson(data.toJSONString()); +// if (error.getErrorCode() != 0) { +// throw new WxErrorException(error); +// } +// return data.toString(); + } finally { + httpPost.releaseConnection(); + } + } + + //去除链接中access_token 并返回 + private String handleUrl(String url){ + String access_token = null; + Pattern pXM = Pattern.compile("access_token=([^&]*)"); + Matcher mXM = pXM.matcher(url); + int i = 0; + while (mXM.find()) { + i++; + access_token = mXM.group(1); + } + if(i > 1){ + return null; + } +// url = url.replaceAll("&?access_token=[^&]*",""); + return access_token; + } +} diff --git a/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsService.java b/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsService.java new file mode 100644 index 000000000..03f9c60d4 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebGoodsService.java @@ -0,0 +1,144 @@ +package com.iformall.douyin.web.api; + + +import com.iformall.douyin.web.bean.*; +import me.chanjar.weixin.common.error.WxErrorException; + +import java.util.List; + +/** + * 接入商品库 + * + * @author + */ +public interface TtWebGoodsService { + + /** + *1 查询商品模板 + */ + String TEMPLATE_GET = "/life/goods/template/get/"; + /** + *2 查询商品草稿数据 + */ + String PRODUCT_DRAFT_GET = "/life/goods/product/draft/get/"; + /** + *3 查询商品草稿数据列表 + */ + String PRODUCT_DRAFT_LIST = "/life/goods/product/draft/list/"; + /** + *4 查询商品线上数据 + */ + String PRODUCT_ONLINE_GET = "/life/goods/product/online/get/"; + /** + *5 查询商品线上数据列表 + */ + String PRODUCT_ONLINE_LIST = "/life/goods/product/online/list/"; + /** + *6 创建/更新商品 + */ + String PRODUCT_SAVE = "/life/goods/product/save/"; + /** + *7 免审修改团购活动 + */ + String PRODUCT_FREE_AUDIT = "/life/goods/product/free_audit"; + /** + *8 创建/更新多SKU商品的SKU列表(团购/代金券不用对接这个接口) + */ + String SKU_BATCH_SAVE = "/life/goods/sku/batch_save/"; + /** + *9 上下架商品 + */ + String PRODUCT_OPERATE = "/life/goods/product/operate/"; + /** + *10 同步库存 + */ + String STOCK_SYNC = "/life/goods/stock/sync/"; + + /** + * - 查询商品模板,创建商品时的属性列表需与该接口保持一致,否则无法识别 + * category_id int TRUE 行业类目;详细见;商品类目表 https://bytedance.feishu.cn/docx/doxcnn02OUCTiKjpmzFR6ItdTye + * product_type int TRUE 商品类型 商品类型 1-团购 11-代金券 + */ + GoodsTemplateGet templateGet(Integer category_id,Integer product_type) throws WxErrorException; + + /** + * - 使用商品ID或外部商品ID查询商品草稿 + * - 处于新建审核中、修改审核中、或审核成功、失败的数据可以通过该接口查询到 + * - 一次最多查询10个草稿数据 + * product_ids string TRUE 商品ID列表(逗号分隔) + * out_ids string TRUE 外部商品ID列表(逗号分隔) + */ + List productDraftGet(String product_ids, String out_ids) throws WxErrorException ; + + /** + * - 查询本client_key(或绑定的账号)对应的商品草稿列表 + * - 处于审核中、或审核成功、失败的数据可以通过该接口查询到 + * cursor string FALSE 第一页不传,之后用前一次返回的next_cursor传入进行翻页 + * count int FALSE 分页数量,不传默认为5 + * status int FALSE 过滤草稿状态,10-审核中 12-审核失败 1-审核通过 + * + */ + ProductPage productDraftListGet(String cursor,Integer count,Integer status) throws WxErrorException ; + + /** + * - - 使用商品ID或外部商品ID查询商品线上数据 + * - 线上数据是指:通过审核后可以被用户看到的数据,包括在线、下线状态的数据 + * product_ids string TRUE 商品ID列表(逗号分隔) + * out_ids string TRUE 外部商品ID列表(逗号分隔) + */ + List productOnlineGet(String product_ids, String out_ids) throws WxErrorException ; + + /** + * - 查询本client_key(或绑定的账号)对应的商品线上列表 + * - 处于在线、下线、封禁状态的数据可以通过该接口查询到 + * cursor string FALSE 第一页不传,之后用前一次返回的next_cursor传入进行翻页 + * count int FALSE 分页数量,不传默认为5 + * status int FALSE 过滤在线状态 1-在线 2-下线 3-封禁 + * + */ + ProductPage productOnlineListGet(String cursor,Integer count,Integer status) throws WxErrorException ; + + /** + * - 创建或更新商品 + * - 对于同一服务商,相同的out_id会被认为是同一商品,重复创建会被覆盖 + * - 商品和SKU属性,需要通过模板获取 + * return - product_id 创建/更新商品成功后产生,与老接口spu_id一致 + */ + String productSave(Product product) throws WxErrorException ; + + /** + * - 免审修改团购活动 + * product_id string TRUE 商品id (商品id或商品外部id 选其一) + * out_id string TRUE 商品外部id (商品id或商品外部id 选其一) + * sold_end_time int64 FALSE 售卖结束时间 + * stock_qty int64 FALSE 总库存 + */ + boolean productFreeAudit(String productId,String outId,Long soldEndTime,Integer stockQty) throws WxErrorException ; + + /** + * 创建/更新多SKU商品的SKU列表(团购/代金券不用对接这个接口) + * + * @return + */ + boolean skuBatchSave(ProductSku sku) throws WxErrorException ; + + /** + * 上下架商品 + * product_id string TRUE 商品id(若有第三方id可不传) + * out_id string TRUE 商品第三方id + * op_type int64 TRUE 1-上线 2-下线 + * @return + */ + boolean productOperate(String product_id,String out_id,Integer op_type) throws WxErrorException ; + + /** + * 同步库存 + * product_id string TRUE 商品id(若有第三方id可不传) + * out_id string TRUE 商品第三方id + * stock StockStruct TRUE 库存信息 + * - limit_type int TRUE 库存上限类型,为2时stock_qty和avail_qty字段无意义 1-有限库存 2-无限库存 + * - stock_qty int TRUE 总库存,limit_type=2时无意义 + */ + boolean stockSync(String product_id,String out_id,Integer stock) throws WxErrorException ; + +} diff --git a/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebService.java b/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebService.java index 7f33598fe..e7f6538db 100644 --- a/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebService.java +++ b/mallinkService/src/main/java/com/iformall/douyin/web/api/TtWebService.java @@ -110,4 +110,6 @@ public interface TtWebService { */ TtWebProductService getProductService(); + TtWebGoodsService getGoodsService(); + } diff --git a/mallinkService/src/main/java/com/iformall/douyin/web/api/impl/TtWebGoodsServiceImpl.java b/mallinkService/src/main/java/com/iformall/douyin/web/api/impl/TtWebGoodsServiceImpl.java new file mode 100644 index 000000000..755722769 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/douyin/web/api/impl/TtWebGoodsServiceImpl.java @@ -0,0 +1,254 @@ +package com.iformall.douyin.web.api.impl; + +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.TypeReference; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.iformall.common.ErrorCode; +import com.iformall.douyin.pay.exception.TtPayException; +import com.iformall.douyin.payv2.request.CallBackSettingsRequest; +import com.iformall.douyin.payv2.result.BaseTtPayResult; +import com.iformall.douyin.web.api.*; +import com.iformall.douyin.web.bean.*; +import com.iformall.exception.MallinkException; +import lombok.AllArgsConstructor; +import me.chanjar.weixin.common.error.WxError; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonHelper; +import org.apache.commons.lang3.StringUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + */ +@AllArgsConstructor +public class TtWebGoodsServiceImpl implements TtWebGoodsService { + + private static final Gson GSON = new GsonBuilder().create(); + + private TtWebService service; + + + @Override + public GoodsTemplateGet templateGet(Integer category_id, Integer product_type) throws WxErrorException { + TtWebGoodsGetRequestExecutor getExecutor = new TtWebGoodsGetRequestExecutor(this.service.getRequestHttp()); + String apiUrl = this.service.getTtWebConfig().getApiBegin().getPrefix() + this.TEMPLATE_GET; + String param = "category_id=" + category_id + + "&product_type=" + product_type; + String result = this.service.execute(getExecutor, apiUrl, param); + BaseGoodsResult baseResult = GSON.fromJson(result, + new TypeReference>(){}.getType()); + if(baseResult.isSuccess()){ + return baseResult.getData(); + }else{ + throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); + } + } + + @Override + public List productDraftGet(String product_ids, String out_ids) throws WxErrorException { + TtWebGoodsGetRequestExecutor getExecutor = new TtWebGoodsGetRequestExecutor(this.service.getRequestHttp()); + String apiUrl = this.service.getTtWebConfig().getApiBegin().getPrefix() + this.PRODUCT_DRAFT_GET; + String param = "" ; + if(StringUtils.isNotBlank(product_ids)){ + param = "product_ids=" + product_ids; + }else if(StringUtils.isNotBlank(out_ids)){ + param = "out_ids=" + out_ids; + } + String result = this.service.execute(getExecutor, apiUrl, param); + BaseGoodsResult baseResult = GSON.fromJson(result, BaseGoodsResult.class); + if(baseResult.isSuccess()){ + JsonObject object = (JsonObject) baseResult.getData(); + if(object != null){ + JsonObject product_draft_list = object.getAsJsonObject("product_draft_list"); + List list = GSON.fromJson(product_draft_list.toString(), + new TypeReference>() {}.getType()); + return list; + } + return null; + }else{ + throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); + } + } + + @Override + public ProductPage productDraftListGet(String cursor, Integer count, Integer status) throws WxErrorException { + TtWebGoodsGetRequestExecutor getExecutor = new TtWebGoodsGetRequestExecutor(this.service.getRequestHttp()); + String apiUrl = this.service.getTtWebConfig().getApiBegin().getPrefix() + this.PRODUCT_DRAFT_LIST; + String param = "" ; + if(count == null){ + param = "count=" + 5; + }else{ + param = "count=" + count; + } + if(StringUtils.isNotBlank(cursor)){ + param += "&cursor=" + cursor; + } + if(status != null){ + param += "&status=" + status; + } + String result = this.service.execute(getExecutor, apiUrl, param); + BaseGoodsResult baseResult = GSON.fromJson(result, + new TypeReference>() {}.getType()); + if(baseResult.isSuccess()){ + return baseResult.getData(); + }else{ + throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); + } + } + + @Override + public List productOnlineGet(String product_ids, String out_ids) throws WxErrorException { + TtWebGoodsGetRequestExecutor getExecutor = new TtWebGoodsGetRequestExecutor(this.service.getRequestHttp()); + String apiUrl = this.service.getTtWebConfig().getApiBegin().getPrefix() + this.PRODUCT_ONLINE_GET; + String param = "" ; + if(StringUtils.isNotBlank(product_ids)){ + param = "product_ids=" + product_ids; + }else if(StringUtils.isNotBlank(out_ids)){ + param = "out_ids=" + out_ids; + } + String result = this.service.execute(getExecutor, apiUrl, param); + BaseGoodsResult baseResult = GSON.fromJson(result, BaseGoodsResult.class); + if(baseResult.isSuccess()){ + JsonObject object = (JsonObject) baseResult.getData(); + if(object != null){ + JsonObject product_online_list = object.getAsJsonObject("product_online_list"); + List list = GSON.fromJson(product_online_list.toString(), + new TypeReference>() {}.getType()); + return list; + } + return null; + }else{ + throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); + } + } + + @Override + public ProductPage productOnlineListGet(String cursor, Integer count, Integer status) throws WxErrorException { + TtWebGoodsGetRequestExecutor getExecutor = new TtWebGoodsGetRequestExecutor(this.service.getRequestHttp()); + String apiUrl = this.service.getTtWebConfig().getApiBegin().getPrefix() + this.PRODUCT_ONLINE_LIST; + String param = "" ; + if(count == null){ + param = "count=" + 5; + }else{ + param = "count=" + count; + } + if(StringUtils.isNotBlank(cursor)){ + param += "&cursor=" + cursor; + } + if(status != null){ + param += "&status=" + status; + } + String result = this.service.execute(getExecutor, apiUrl, param); + BaseGoodsResult baseResult = GSON.fromJson(result, + new TypeReference>() {}.getType()); + if(baseResult.isSuccess()){ + return baseResult.getData(); + }else{ + throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); + } + } + + @Override + public String productSave(Product product) throws WxErrorException { + TtWebGoodsPostRequestExecutor postExecutor = new TtWebGoodsPostRequestExecutor(this.service.getRequestHttp()); + String apiUrl = this.service.getTtWebConfig().getApiBegin().getPrefix() + this.PRODUCT_SAVE; + String result = this.service.execute(postExecutor, apiUrl, GSON.toJson(product)); + BaseGoodsResult baseResult = GSON.fromJson(result, BaseGoodsResult.class); + if(baseResult.isSuccess()){ + JsonObject data = (JsonObject) baseResult.getData(); + return GsonHelper.getString(data,"product_id"); + }else{ + throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); + } + } + + @Override + public boolean productFreeAudit(String productId, String outId, Long soldEndTime, Integer stockQty) throws WxErrorException { + TtWebGoodsPostRequestExecutor postExecutor = new TtWebGoodsPostRequestExecutor(this.service.getRequestHttp()); + String apiUrl = this.service.getTtWebConfig().getApiBegin().getPrefix() + this.PRODUCT_FREE_AUDIT; + Map map = new HashMap<>(); + if(StringUtils.isNotBlank(productId)){ + map.put("product_id",productId); + }else if(StringUtils.isNotBlank(outId)){ + map.put("out_id",outId); + } + if(soldEndTime != null){ + map.put("sold_end_time",soldEndTime); + } + if(stockQty != null){ + map.put("stock_qty",stockQty); + } + String result = this.service.execute(postExecutor, apiUrl, GSON.toJson(map)); + BaseGoodsResult baseResult = GSON.fromJson(result, BaseGoodsResult.class); + if(baseResult.isSuccess()){ + return true; + }else{ + throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); + } + } + + @Override + public boolean skuBatchSave(ProductSku sku) throws WxErrorException { + TtWebGoodsPostRequestExecutor postExecutor = new TtWebGoodsPostRequestExecutor(this.service.getRequestHttp()); + String apiUrl = this.service.getTtWebConfig().getApiBegin().getPrefix() + this.SKU_BATCH_SAVE; + String result = this.service.execute(postExecutor, apiUrl, GSON.toJson(sku)); + BaseGoodsResult baseResult = GSON.fromJson(result, BaseGoodsResult.class); + if(baseResult.isSuccess()){ + return true; + }else{ + throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); + } + } + + @Override + public boolean productOperate(String product_id, String out_id, Integer op_type) throws WxErrorException { + TtWebGoodsPostRequestExecutor postExecutor = new TtWebGoodsPostRequestExecutor(this.service.getRequestHttp()); + String apiUrl = this.service.getTtWebConfig().getApiBegin().getPrefix() + this.PRODUCT_OPERATE; + Map map = new HashMap<>(); + if(StringUtils.isNotBlank(product_id)){ + map.put("product_id",product_id); + }else if(StringUtils.isNotBlank(out_id)){ + map.put("out_id",out_id); + } + map.put("op_type",op_type); + String result = this.service.execute(postExecutor, apiUrl, GSON.toJson(map)); + BaseGoodsResult baseResult = GSON.fromJson(result, BaseGoodsResult.class); + if(baseResult.isSuccess()){ + return true; + }else{ + throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); + } + } + + @Override + public boolean stockSync(String product_id, String out_id, Integer stock) throws WxErrorException { + TtWebGoodsPostRequestExecutor postExecutor = new TtWebGoodsPostRequestExecutor(this.service.getRequestHttp()); + String apiUrl = this.service.getTtWebConfig().getApiBegin().getPrefix() + this.STOCK_SYNC; + Map map = new HashMap<>(); + if(StringUtils.isNotBlank(product_id)){ + map.put("product_id",product_id); + }else if(StringUtils.isNotBlank(out_id)){ + map.put("out_id",out_id); + } + Map stockStruct = new HashMap<>(); + if(stock == null || stock < 0){ + stockStruct.put("limit_type",2); + }else{ + stockStruct.put("limit_type",1); + stockStruct.put("stock_qty",stock); + } + map.put("stock",stockStruct); + String result = this.service.execute(postExecutor, apiUrl, GSON.toJson(map)); + BaseGoodsResult baseResult = GSON.fromJson(result, BaseGoodsResult.class); + if(baseResult.isSuccess()){ + return true; + }else{ + throw new WxErrorException(WxError.builder().errorCode(baseResult.getErrCode()).errorMsg(baseResult.getErrMsg()).build()); + } + } +} diff --git a/mallinkService/src/main/java/com/iformall/douyin/web/api/impl/TtWebServiceImpl.java b/mallinkService/src/main/java/com/iformall/douyin/web/api/impl/TtWebServiceImpl.java index 0b7b5b14a..1d9e81ad2 100644 --- a/mallinkService/src/main/java/com/iformall/douyin/web/api/impl/TtWebServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/douyin/web/api/impl/TtWebServiceImpl.java @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.google.gson.Gson; import com.google.gson.JsonParser; +import com.iformall.douyin.web.api.TtWebGoodsService; import com.iformall.douyin.web.api.TtWebProductService; import com.iformall.douyin.web.api.TtWebService; import com.iformall.douyin.web.api.TtWebShopMatchService; @@ -51,6 +52,7 @@ public class TtWebServiceImpl implements TtWebService, RequestHttp implements Serializable { + + private static final long serialVersionUID = -1L; + + /** + * + */ + @SerializedName(value = "base") + private BaseResult base; + + public Integer getErrCode() { + if(base.getGatewayCode().intValue() != 0){ + return base.getGatewayCode(); + }else if(base.getBizCode().intValue() != 0){ + return base.getBizCode(); + } + return 0; + } + + public boolean isSuccess() { + if(base.getGatewayCode().intValue() == 0 + && base.getBizCode().intValue() == 0){ + return true; + } + return false; + } + + public String getErrMsg() { + if(base.getGatewayCode().intValue() != 0){ + return base.getGatewayMsg(); + }else if(base.getBizCode().intValue() != 0){ + return base.getBizMsg(); + } + return ""; + } + + @SerializedName(value = "data") + private T data; + + + @Data + @NoArgsConstructor + public class BaseResult implements Serializable { + + private static final long serialVersionUID = -1L; + + /** + * 请求日志ID + */ + @SerializedName(value = "log_id") + private String logId; + /** + * 网关状态码 + */ + @SerializedName(value = "gateway_code") + private Integer gatewayCode; + /** + * 网关状态信息 + */ + @SerializedName(value = "gateway_msg") + private String gatewayMsg; + /** + * 业务状态码 + */ + @SerializedName(value = "biz_code") + private Integer bizCode; + /** + * 业务状态信息 + */ + @SerializedName(value = "biz_msg") + private String bizMsg; + + } + +} diff --git a/mallinkService/src/main/java/com/iformall/douyin/web/bean/GoodsTemplateGet.java b/mallinkService/src/main/java/com/iformall/douyin/web/bean/GoodsTemplateGet.java new file mode 100644 index 000000000..af6c3bf72 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/douyin/web/bean/GoodsTemplateGet.java @@ -0,0 +1,82 @@ +package com.iformall.douyin.web.bean; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * 结果通知. + * + * @author thinsstar + */ +@Data +@NoArgsConstructor +public class GoodsTemplateGet implements Serializable { + + private static final long serialVersionUID = -1L; + + /** + * 商品属性列表 + */ + @SerializedName(value = "product_attrs") + private List productAttrs; + + /** + * SKU属性列表 + */ + @SerializedName(value = "sku_attrs") + private List skuAttrs; + + @Data + @NoArgsConstructor + public static class ProductAttrs implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 属性描述 + */ + @SerializedName(value = "desc") + private String desc; + + /** + * 是否列表 + */ + @SerializedName(value = "is_multi") + private Boolean isMulti; + + /** + * 商品优惠后价格 + */ + @SerializedName(value = "is_required") + private Boolean isRequired; + + /** + * 属性key + */ + @SerializedName(value = "key") + private String key; + + /** + * 属性名称 + */ + @SerializedName(value = "name") + private String name; + + /** + * 属性类型 + */ + @SerializedName(value = "value_demo") + private String valueDemo; + + /** + * 属性样例 + */ + @SerializedName(value = "value_type") + private String valueType; + + } + +} diff --git a/mallinkService/src/main/java/com/iformall/douyin/web/bean/Product.java b/mallinkService/src/main/java/com/iformall/douyin/web/bean/Product.java new file mode 100644 index 000000000..177c9ab8a --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/douyin/web/bean/Product.java @@ -0,0 +1,252 @@ +package com.iformall.douyin.web.bean; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * 商品. + * + * @author thinsstar + */ +@Data +@NoArgsConstructor +public class Product implements Serializable { + + private static final long serialVersionUID = -1L; + + /** + * 草稿状态 10-审核中 12-审核失败 1-审核通过 + */ + @SerializedName(value = "draft_status") + private Integer draftStatus; + + /** + * 审核失败原因 + */ + @SerializedName(value = "audit_msg") + private String auditMsg; + + /** + * 在线状态 1-在线 2-下线 3-封禁 + */ + @SerializedName(value = "online_status") + private Integer onlineStatus; + + /** + * 商品 + */ + @SerializedName(value = "product") + private ProductStruct product; + + /** + * 商品 + */ + @SerializedName(value = "sku") + private SkuStruct sku; + + @Data + @NoArgsConstructor + public static class ProductStruct implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 商品Id + * 创建时不必填写,更新时如有out_id可不填写 + */ + @SerializedName(value = "product_id") + private String productId; + /** + * 外部商品id + */ + @SerializedName(value = "out_id") + private String outId; + /** + * 商品名 + */ + @SerializedName(value = "product_name") + private String productName; + /** + * 品类全名,保存时不必填写 + */ + @SerializedName(value = "category_full_name") + private String categoryFullName; + /** + * 品类id + */ + @SerializedName(value = "category_id") + private Integer categoryId; + /** + * 商品类型 1-团购 11-代金券 + */ + @SerializedName(value = "product_type") + private Integer productType; + /** + * 业务线 1-闭环自研开发者 3-直连服务商 5-小程序 + */ + @SerializedName(value = "biz_line") + private Integer bizLine; + /** + * 商家名 + */ + @SerializedName(value = "account_name") + private String accountName; + /** + * 售卖开始时间 + */ + @SerializedName(value = "sold_start_time") + private Long soldStartTime; + /** + * 售卖结束时间 + */ + @SerializedName(value = "sold_end_time") + private Long soldEndTime; + /** + * 创建时间,保存时不必填写 + */ + @SerializedName(value = "create_time") + private Long createTime; + /** + * 更新时间,保存时不必填写 + */ + @SerializedName(value = "update_time") + private Long updateTime; + /** + * 第三方跳转链接,小程序商品必填 + */ + @SerializedName(value = "out_url") + private String outUrl; + /** + * 店铺列表 + */ + @SerializedName(value = "poi_list") + private List poiList; + + /** + * 商品属性KV + */ + @SerializedName(value = "attr_key_value_map") + private Map attrKeyValueMap; + + } + + @Data + @NoArgsConstructor + public static class PoiStruct implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 接入方店铺id,保存时必传 + */ + @SerializedName(value = "supplier_ext_id") + private String supplierExtId; + + /** + * poi id,保存时不必填写 + */ + @SerializedName(value = "poi_id") + private Long poiId; + + /** + * 店铺id,保存时不必填写 + */ + @SerializedName(value = "supplier_id") + private Long supplierId; + + } + + @Data + @NoArgsConstructor + public static class SkuStruct implements Serializable { + private static final long serialVersionUID = 1L; + /** + * sku id,创建时不必填写 + */ + @SerializedName(value = "sku_id") + private String skuId; + /** + * 接入方店铺id,保存时必传 + */ + @SerializedName(value = "sku_name") + private String skuName; + /** + * 原价,团购创建时可不填,会根据商品搭配计算原价 + */ + @SerializedName(value = "origin_amount") + private Integer originAmount; + /** + * 实际支付价格 + */ + @SerializedName(value = "actual_amount") + private Integer actualAmount; + /** + * 库存信息 + */ + @SerializedName(value = "stock") + private StockStruct stock; + /** + * 第三方id + */ + @SerializedName(value = "out_sku_id") + private String outSkuId; + /** + * 状态 1-在线 -1-删除 + */ + @SerializedName(value = "status") + private Integer status; + + /** + * sku属性KV + */ + @SerializedName(value = "attr_key_value_map") + private Map attrKeyValueMap; + + } + + @Data + @NoArgsConstructor + public static class StockStruct implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 库存上限类型, + * 为2时stock_qty和avail_qty字段无意义 + * 1-有限库存 2-无限库存 + */ + @SerializedName(value = "limit_type") + private Integer limitType; + /** + * 总库存, + * limit_type=2时无意义 + */ + @SerializedName(value = "stock_qty") + private Integer stockQty; + /** + * 可用库存, + * limit_type=2时无意义, + * 始终保证stock_qty=avail_qty+frozen_qty+sold_qty + */ + @SerializedName(value = "avail_qty") + private Integer availQty; + /** + * 冻结库存,保存SKU时不填 + */ + @SerializedName(value = "frozen_qty") + private Integer frozenQty; + /** + * 售卖库存, 退款回滚,保存SKU时不填 + */ + @SerializedName(value = "sold_qty") + private Integer soldQty; + /** + * 销量,退款不回滚,保存SKU时不填 + */ + @SerializedName(value = "sold_count") + private Integer soldCount; + + } + +} diff --git a/mallinkService/src/main/java/com/iformall/douyin/web/bean/ProductPage.java b/mallinkService/src/main/java/com/iformall/douyin/web/bean/ProductPage.java new file mode 100644 index 000000000..014048edb --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/douyin/web/bean/ProductPage.java @@ -0,0 +1,40 @@ +package com.iformall.douyin.web.bean; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * 商品. + * + * @author thinsstar + */ +@Data +@NoArgsConstructor +public class ProductPage implements Serializable { + + private static final long serialVersionUID = -1L; + + /** + * 用于查询下一页 + */ + @SerializedName(value = "next_cursor") + private String nextCursor; + + /** + * 是否还有下一页 + */ + @SerializedName(value = "has_more") + private boolean hasMore; + + /** + * 商品 + */ + @SerializedName(value = "product_list") + private List productList; + +} diff --git a/mallinkService/src/main/java/com/iformall/douyin/web/bean/ProductSku.java b/mallinkService/src/main/java/com/iformall/douyin/web/bean/ProductSku.java new file mode 100644 index 000000000..184b26794 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/douyin/web/bean/ProductSku.java @@ -0,0 +1,40 @@ +package com.iformall.douyin.web.bean; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +/** + * 商品. + * + * @author thinsstar + */ +@Data +@NoArgsConstructor +public class ProductSku implements Serializable { + + private static final long serialVersionUID = -1L; + + /** + * 商品Id + * 创建时不必填写,更新时如有out_id可不填写 + */ + @SerializedName(value = "product_id") + private String productId; + /** + * 外部商品id + */ + @SerializedName(value = "out_id") + private String outId; + + /** + * 商品 + */ + @SerializedName(value = "sku_list") + private List skuList; + +} diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java index f5dc98666..3f8515053 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxOrderServiceImpl.java @@ -16,6 +16,7 @@ import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import com.alibaba.fastjson.JSONArray; import com.google.common.collect.Lists; import com.iformall.common.Result; import com.iformall.domain.po.*; @@ -2796,10 +2797,22 @@ public class WxOrderServiceImpl implements WxOrderService { //券一个数量创建一个订单 boolean isOneNumberOneOrder = orderAdapterService.isOneNumberOneOrder(); if (isOneNumberOneOrder) { + JSONArray jsonArray = new JSONArray(); + if(StringUtils.isNotBlank(orderdto.getExtParam())){ + try{ + jsonArray = JSONArray.parseArray(orderdto.getExtParam()); + }catch(Exception e){ + logger.error(e.getMessage()); + } + } for (int j = 0; j < orderdto.getCount(); j++) { - lastOrder = proxy.handleSaveOrderForCouponSingle(orderDate,allowUnPayOrder,composeOrder, user, orderdto.getWxCoupon(), 1, - orderdto.isPress(),orderdto.getOrderGroupId(),orderdto.getFormId(),orderdto.getShippingType(),orderdto.getAddress(),orderdto.getExtParam(), - orderdto.getWxCouponChannel(), payWay); + String extParam = ""; + if(jsonArray != null && !jsonArray.isEmpty()){ + extParam = jsonArray.get(j).toString(); + } + lastOrder = proxy.handleSaveOrderForCouponSingle(orderDate,allowUnPayOrder,composeOrder, user, orderdto.getWxCoupon(), 1, + orderdto.isPress(),orderdto.getOrderGroupId(),orderdto.getFormId(),orderdto.getShippingType(),orderdto.getAddress(),extParam, + orderdto.getWxCouponChannel(), payWay); } }else { lastOrder = proxy.handleSaveOrderForCouponSingle(orderDate,allowUnPayOrder,composeOrder, user, orderdto.getWxCoupon(), orderdto.getCount(), diff --git a/mallinkService/src/main/java/com/iformall/service/order/entity/WxComposeOrder.java b/mallinkService/src/main/java/com/iformall/service/order/entity/WxComposeOrder.java index 9ed64d1ba..c50584453 100644 --- a/mallinkService/src/main/java/com/iformall/service/order/entity/WxComposeOrder.java +++ b/mallinkService/src/main/java/com/iformall/service/order/entity/WxComposeOrder.java @@ -1,8 +1,10 @@ package com.iformall.service.order.entity; +import java.util.List; import java.util.Map; import com.iformall.domain.po.WxBatchOrder; +import com.iformall.domain.po.WxCoupon; import com.iformall.domain.po.WxCouponChannel; import com.iformall.domain.po.WxOrder; import com.iformall.domain.po.base.TenantEntity; @@ -34,5 +36,7 @@ public class WxComposeOrder extends TenantEntity{ private WxBatchOrder mainOrder;//真正的主订单对象,批量下单时才有 private Map couponChannelMap; + + private Map couponMap; } diff --git a/mallinkService/src/main/java/com/iformall/service/order/impl/SingleOrderAdapterService.java b/mallinkService/src/main/java/com/iformall/service/order/impl/SingleOrderAdapterService.java index 16206705b..c6477f0d0 100644 --- a/mallinkService/src/main/java/com/iformall/service/order/impl/SingleOrderAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/order/impl/SingleOrderAdapterService.java @@ -49,7 +49,7 @@ public class SingleOrderAdapterService extends BaseBatchOrderAdapterService { @Override public WxComposeOrder createDBMainOrder(TenantEntity tenantEntity, WxCUserBasicInfo user, int payment, EnumPayWay payWay) { - return super.createDBMainOrder(tenantEntity,user, payment,null, payWay, EnumComposeOrder.SINGLE,null); + return super.createDBMainOrder(tenantEntity,user, payment,null, payWay, EnumComposeOrder.SINGLE,null,null); } @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) diff --git a/mallinkService/src/main/java/com/iformall/service/order/impl/batch/BaseBatchOrderAdapterService.java b/mallinkService/src/main/java/com/iformall/service/order/impl/batch/BaseBatchOrderAdapterService.java index d90be2dce..9ce1d8b0d 100644 --- a/mallinkService/src/main/java/com/iformall/service/order/impl/batch/BaseBatchOrderAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/order/impl/batch/BaseBatchOrderAdapterService.java @@ -79,6 +79,7 @@ public abstract class BaseBatchOrderAdapterService implements OrderAdapterServic @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) protected WxComposeOrder createDBMainOrder(TenantEntity tenantEntity,WxCUserBasicInfo user,List orderSave,EnumPayWay payWay,EnumComposeOrder composeOrderType) { int payment = 0; + Map couponMap = new HashMap(); Map couponChannelMap = new HashMap(); for (OrderComposeSaveDto ocsd : orderSave) { WxCouponChannel wxCouponChannel = wxCouponChannelService.getById(ocsd.getSignleOrder().getCouponChannelId(),tenantEntity.getTenantId()); @@ -88,15 +89,17 @@ public abstract class BaseBatchOrderAdapterService implements OrderAdapterServic boolean isPress = ocsd.getSignleOrder().isPressOrder(); WxComposeChildOrderPrice price = getChildCouponOrderPrice(ocsd,ocsd.getWxCoupon(),wxCouponChannel, isPress, ocsd.getSignleOrder().getOrderGroupId(), ocsd.getCount()); payment = payment+price.getRealPayMent(); + couponMap.put(ocsd.getWxCoupon().getId(),ocsd.getWxCoupon()); couponChannelMap.put(wxCouponChannel.getId(), wxCouponChannel); } - return createDBMainOrder(tenantEntity, user, payment, null,payWay, composeOrderType,couponChannelMap); + return createDBMainOrder(tenantEntity, user, payment, null,payWay, composeOrderType,couponChannelMap,couponMap); } @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) protected WxComposeOrder createDBMainOrderForPushOrders(TenantEntity tenantEntity,WxCUserBasicInfo user,String allExtParam,List platPushOrderList,EnumPayWay payWay,EnumComposeOrder composeOrderType) { int payment = 0; + Map couponMap = new HashMap(); Map couponChannelMap = new HashMap(); for (PlatPushOrderSaveDto ocsd : platPushOrderList) { WxCouponChannel wxCouponChannel = wxCouponChannelService.getById(ocsd.getCouponChannelId(),tenantEntity.getTenantId()); @@ -106,14 +109,16 @@ public abstract class BaseBatchOrderAdapterService implements OrderAdapterServic boolean isPress = ocsd.isPress(); WxComposeChildOrderPrice price = getChildCouponOrderPrice(ocsd.getShippingType(),ocsd.getWxCoupon(),wxCouponChannel, isPress, ocsd.getOrderGroupId(), ocsd.getCount()); payment = payment+price.getRealPayMent(); + couponMap.put(ocsd.getWxCoupon().getId(),ocsd.getWxCoupon()); couponChannelMap.put(wxCouponChannel.getId(), wxCouponChannel); } - return createDBMainOrder(tenantEntity, user, payment, allExtParam,payWay, composeOrderType,couponChannelMap); + return createDBMainOrder(tenantEntity, user, payment, allExtParam,payWay, composeOrderType,couponChannelMap,couponMap); } @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) - protected WxComposeOrder createDBMainOrder(TenantEntity tenantEntity,WxCUserBasicInfo user,int payment,String allExtParam,EnumPayWay payWay,EnumComposeOrder composeOrderType,Map couponChannelMap) { + protected WxComposeOrder createDBMainOrder(TenantEntity tenantEntity,WxCUserBasicInfo user,int payment,String allExtParam,EnumPayWay payWay,EnumComposeOrder composeOrderType, + Map couponChannelMap,Map couponMap) { //判断是否poi订单 Integer isTtPoiOrder = null; try{ @@ -140,6 +145,9 @@ public abstract class BaseBatchOrderAdapterService implements OrderAdapterServic if (null != couponChannelMap) { composeOrder.setCouponChannelMap(couponChannelMap); } + if (null != couponMap){ + composeOrder.setCouponMap(couponMap); + } return composeOrder; } diff --git a/mallinkService/src/main/java/com/iformall/service/order/impl/batch/CouponPackageOrderAdapterService.java b/mallinkService/src/main/java/com/iformall/service/order/impl/batch/CouponPackageOrderAdapterService.java index 0f3b94f36..ca65e2447 100644 --- a/mallinkService/src/main/java/com/iformall/service/order/impl/batch/CouponPackageOrderAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/order/impl/batch/CouponPackageOrderAdapterService.java @@ -39,7 +39,7 @@ public class CouponPackageOrderAdapterService extends BaseBatchOrderAdapterServi @Override public WxComposeOrder createDBMainOrder(TenantEntity tenantEntity, WxCUserBasicInfo user, int payment, EnumPayWay payWay) { - return super.createDBMainOrder(tenantEntity, user, payment,null, payWay, EnumComposeOrder.PACKAGECOUPON,null); + return super.createDBMainOrder(tenantEntity, user, payment,null, payWay, EnumComposeOrder.PACKAGECOUPON,null,null); } @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) diff --git a/mallinkService/src/main/java/com/iformall/service/order/impl/batch/MulityNumberOneOrderBatchOrderAdapterService.java b/mallinkService/src/main/java/com/iformall/service/order/impl/batch/MulityNumberOneOrderBatchOrderAdapterService.java index a17e9c958..3955a3a61 100644 --- a/mallinkService/src/main/java/com/iformall/service/order/impl/batch/MulityNumberOneOrderBatchOrderAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/order/impl/batch/MulityNumberOneOrderBatchOrderAdapterService.java @@ -40,7 +40,7 @@ public class MulityNumberOneOrderBatchOrderAdapterService extends BaseBatchOrder @Override public WxComposeOrder createDBMainOrder(TenantEntity tenantEntity, WxCUserBasicInfo user, int payment, EnumPayWay payWay) { - return super.createDBMainOrder(tenantEntity,user, payment, null, payWay, EnumComposeOrder.MULITY_NUMBER_ORDER_BATCH,null); + return super.createDBMainOrder(tenantEntity,user, payment, null, payWay, EnumComposeOrder.MULITY_NUMBER_ORDER_BATCH,null,null); } @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class}) diff --git a/mallinkService/src/main/java/com/iformall/service/order/impl/batch/OneNumberOneOrderBatchOrderAdapterService.java b/mallinkService/src/main/java/com/iformall/service/order/impl/batch/OneNumberOneOrderBatchOrderAdapterService.java index 76f22e20d..c145eda7c 100644 --- a/mallinkService/src/main/java/com/iformall/service/order/impl/batch/OneNumberOneOrderBatchOrderAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/order/impl/batch/OneNumberOneOrderBatchOrderAdapterService.java @@ -39,7 +39,7 @@ public class OneNumberOneOrderBatchOrderAdapterService extends BaseBatchOrderAda @Override public WxComposeOrder createDBMainOrder(TenantEntity tenantEntity, WxCUserBasicInfo user, int payment, EnumPayWay payWay) { - return super.createDBMainOrder(tenantEntity,user, payment, null,payWay, EnumComposeOrder.ONE_NUMBER_ORDER_BATCH,null); + return super.createDBMainOrder(tenantEntity,user, payment, null,payWay, EnumComposeOrder.ONE_NUMBER_ORDER_BATCH,null,null); } @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})